2013-10-30 18:24:46 -04:00
// Protocol17x.cpp
/*
Implements the 1.7 . x protocol classes :
- cProtocol172
- release 1.7 .2 protocol ( # 4 )
( others may be added later in the future for the 1.7 release series )
*/
# 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-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"
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 ; \
2013-12-13 11:53:00 -05:00
ByteBuf . Proc ( Var ) ;
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-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-02-15 17:16:44 -05:00
// Compose the complete Json string to send:
Json : : Value msg ;
2014-05-28 16:41:23 -04:00
cWorld * World = m_Client - > GetPlayer ( ) - > GetWorld ( ) ;
msg [ " text " ] = cClientHandle : : FormatMessageType ( ( World = = NULL ) ? false : World - > ShouldUseChatPrefixes ( ) , a_Message . GetMessageType ( ) , a_Message . GetAdditionalMessageTypeData ( ) ) ; // The client crashes without this field being present
2014-02-15 17:16:44 -05:00
const cCompositeChat : : cParts & Parts = a_Message . GetParts ( ) ;
for ( cCompositeChat : : cParts : : const_iterator itr = Parts . begin ( ) , end = Parts . end ( ) ; itr ! = end ; + + itr )
{
Json : : Value Part ;
switch ( ( * itr ) - > m_PartType )
{
case cCompositeChat : : ptText :
{
Part [ " text " ] = ( * itr ) - > m_Text ;
AddChatPartStyle ( Part , ( * itr ) - > m_Style ) ;
break ;
}
case cCompositeChat : : ptClientTranslated :
{
const cCompositeChat : : cClientTranslatedPart & p = ( const cCompositeChat : : cClientTranslatedPart & ) * * itr ;
Part [ " translate " ] = p . m_Text ;
Json : : Value With ;
for ( AStringVector : : const_iterator itrW = p . m_Parameters . begin ( ) , endW = p . m_Parameters . end ( ) ; itrW ! = endW ; + + itr )
{
With . append ( * itrW ) ;
}
if ( ! p . m_Parameters . empty ( ) )
{
Part [ " with " ] = With ;
}
AddChatPartStyle ( Part , p . m_Style ) ;
break ;
}
case cCompositeChat : : ptUrl :
{
const cCompositeChat : : cUrlPart & p = ( const cCompositeChat : : cUrlPart & ) * * itr ;
Part [ " text " ] = p . m_Text ;
Json : : Value Url ;
Url [ " action " ] = " open_url " ;
Url [ " value " ] = p . m_Url ;
Part [ " clickEvent " ] = Url ;
AddChatPartStyle ( Part , p . m_Style ) ;
break ;
}
case cCompositeChat : : ptSuggestCommand :
case cCompositeChat : : ptRunCommand :
{
const cCompositeChat : : cCommandPart & p = ( const cCompositeChat : : cCommandPart & ) * * itr ;
Part [ " text " ] = p . m_Text ;
Json : : Value Cmd ;
Cmd [ " action " ] = ( p . m_PartType = = cCompositeChat : : ptRunCommand ) ? " run_command " : " suggest_command " ;
Cmd [ " value " ] = p . m_Command ;
Part [ " clickEvent " ] = Cmd ;
AddChatPartStyle ( Part , p . m_Style ) ;
2014-05-19 15:40:56 -04:00
break ;
}
case cCompositeChat : : ptShowAchievement :
{
const cCompositeChat : : cShowAchievementPart & p = ( const cCompositeChat : : cShowAchievementPart & ) * * itr ;
Part [ " translate " ] = " chat.type.achievement " ;
Json : : Value Ach ;
Ach [ " action " ] = " show_achievement " ;
Ach [ " value " ] = p . m_Text ;
Json : : Value AchColourAndName ;
AchColourAndName [ " color " ] = " green " ;
AchColourAndName [ " translate " ] = p . m_Text ;
AchColourAndName [ " hoverEvent " ] = Ach ;
Json : : Value Extra ;
Extra . append ( AchColourAndName ) ;
Json : : Value Name ;
Name [ " text " ] = p . m_PlayerName ;
Json : : Value With ;
With . append ( Name ) ;
With . append ( Extra ) ;
Part [ " with " ] = With ;
AddChatPartStyle ( Part , p . m_Style ) ;
2014-02-15 17:16:44 -05:00
break ;
}
}
msg [ " extra " ] . append ( Part ) ;
} // for itr - Parts[]
// Send the message to the client:
cPacketizer Pkt ( * this , 0x02 ) ;
Pkt . WriteString ( msg . toStyledString ( ) ) ;
}
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
const AString & ChunkData = a_Serializer . Serialize ( cChunkDataSerializer : : RELEASE_1_3_2 ) ;
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
Pkt . WriteString ( m_Client - > GetUUID ( ) ) ;
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-02-13 10:13:09 -05:00
void cProtocol172 : : SendMapColumn ( int a_ID , int a_X , int a_Y , const Byte * a_Colors , unsigned int a_Length )
{
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-02-18 13:50:08 -05:00
void cProtocol172 : : SendMapDecorators ( int a_ID , const cMapDecoratorList & a_Decorators )
{
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 ( ) ) ) ;
Pkt . WriteFloat ( ( float ) ( 0.1 * Player - > GetMaxSpeed ( ) ) ) ;
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
}
2013-12-22 08:45:25 -05: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_ParticleAmmount )
{
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 ) ;
Pkt . WriteInt ( a_ParticleAmmount ) ;
}
2013-11-01 11:20:15 -04:00
void cProtocol172 : : SendPlayerListItem ( const cPlayer & a_Player , bool a_IsOnline )
{
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 , 0x38 ) ; // Playerlist Item packet
Pkt . WriteString ( a_Player . GetName ( ) ) ;
Pkt . WriteBool ( a_IsOnline ) ;
2013-11-10 16:55:42 -05:00
Pkt . WriteShort ( a_IsOnline ? a_Player . GetClientHandle ( ) - > GetPing ( ) : 0 ) ;
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
2013-11-10 16:55:42 -05:00
Pkt . WriteVarInt ( a_Player . GetUniqueID ( ) ) ;
2014-04-14 14:21:00 -04:00
Pkt . WriteString ( a_Player . GetClientHandle ( ) - > GetUUID ( ) ) ;
2013-11-03 05:58:49 -05:00
Pkt . WriteString ( a_Player . GetName ( ) ) ;
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-06-29 17:44:01 -04:00
void cProtocol172 : : SendRespawn ( const cWorld & a_World , bool a_ShouldIgnoreDimensionChecks )
2013-11-01 11:20:15 -04:00
{
2014-06-29 17:44:01 -04:00
if ( ( m_LastSentDimension = = a_World . GetDimension ( ) ) & & ! 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-08 15:58:08 -04:00
Pkt . WriteInt ( a_World . GetDimension ( ) ) ;
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-08 15:58:08 -04:00
m_LastSentDimension = a_World . GetDimension ( ) ;
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 ( ) ) ;
Pkt . WriteInt ( ( int ) a_ExpOrb . GetPosX ( ) ) ;
Pkt . WriteInt ( ( int ) a_ExpOrb . GetPosY ( ) ) ;
Pkt . WriteInt ( ( int ) a_ExpOrb . GetPosZ ( ) ) ;
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
}
void cProtocol172 : : SendTimeUpdate ( Int64 a_WorldAge , Int64 a_TimeOfDay )
{
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 , 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
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?
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
}
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 ;
}
// 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 ( ) ;
// Write one NUL extra, so that we can detect over-reads
bb . Write ( " \0 " , 1 ) ;
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-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 ) ;
ASSERT ( PacketData . size ( ) > 0 ) ;
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-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 ;
}
2013-10-31 18:48:43 -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-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
{
Int64 Timestamp ;
2013-12-13 11:53:00 -05:00
a_ByteBuffer . ReadBEInt64 ( Timestamp ) ;
2013-10-31 18:48:43 -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
{
// Send the response:
2014-07-19 09:07:28 -04:00
AString Response = " { \" version \" :{ \" name \" : \" 1.7.2 \" , \" protocol \" :4}, \" players \" :{ " ;
2014-04-18 15:09:44 -04:00
cServer * Server = cRoot : : Get ( ) - > GetServer ( ) ;
2014-07-19 09:07:28 -04:00
AppendPrintf ( Response , " \" max \" :%u, \" online \" :%u, \" sample \" :[]}, " ,
2014-04-18 15:09:44 -04:00
Server - > GetMaxPlayers ( ) ,
Server - > GetNumPlayers ( )
2013-10-30 18:24:46 -04:00
) ;
2014-01-07 11:53:40 -05:00
AppendPrintf ( Response , " \" description \" :{ \" text \" : \" %s \" }, " ,
2014-04-18 15:09:44 -04:00
Server - > GetDescription ( ) . c_str ( )
2013-10-30 18:24:46 -04:00
) ;
2014-07-19 09:07:28 -04:00
AppendPrintf ( Response , " \" favicon \" : \" data:image/png;base64,%s \" " ,
2014-04-18 15:09:44 -04:00
Server - > GetFaviconData ( ) . c_str ( )
2014-01-07 10:31:06 -05:00
) ;
2013-10-30 18:24:46 -04:00
Response . append ( " } " ) ;
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 ;
2013-12-13 11:53:00 -05:00
a_ByteBuffer . ReadVarUTF8String ( Username ) ;
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 ) ;
2013-11-03 05:58:49 -05:00
// TODO: handle in m_Client
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 ;
2013-12-13 11:53:00 -05:00
a_ByteBuffer . ReadString ( Data , Length ) ;
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-11-01 11:20:15 -04:00
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-02-15 17:16:44 -05:00
void cProtocol172 : : AddChatPartStyle ( Json : : Value & a_Value , const AString & a_PartStyle )
{
size_t len = a_PartStyle . length ( ) ;
for ( size_t i = 0 ; i < len ; i + + )
{
switch ( a_PartStyle [ i ] )
{
case ' b ' :
{
// bold
a_Value [ " bold " ] = Json : : Value ( true ) ;
break ;
}
case ' i ' :
{
// italic
a_Value [ " italic " ] = Json : : Value ( true ) ;
break ;
}
case ' u ' :
{
// Underlined
a_Value [ " underlined " ] = Json : : Value ( true ) ;
break ;
}
case ' s ' :
{
// strikethrough
a_Value [ " strikethrough " ] = Json : : Value ( true ) ;
break ;
}
case ' o ' :
{
// obfuscated
a_Value [ " obfuscated " ] = Json : : Value ( true ) ;
break ;
}
case ' @ ' :
{
// Color, specified by the next char:
i + + ;
if ( i > = len )
{
// String too short, didn't contain a color
break ;
}
switch ( a_PartStyle [ i ] )
{
case ' 0 ' : a_Value [ " color " ] = Json : : Value ( " black " ) ; break ;
case ' 1 ' : a_Value [ " color " ] = Json : : Value ( " dark_blue " ) ; break ;
case ' 2 ' : a_Value [ " color " ] = Json : : Value ( " dark_green " ) ; break ;
case ' 3 ' : a_Value [ " color " ] = Json : : Value ( " dark_aqua " ) ; break ;
case ' 4 ' : a_Value [ " color " ] = Json : : Value ( " dark_red " ) ; break ;
case ' 5 ' : a_Value [ " color " ] = Json : : Value ( " dark_purple " ) ; break ;
case ' 6 ' : a_Value [ " color " ] = Json : : Value ( " gold " ) ; break ;
case ' 7 ' : a_Value [ " color " ] = Json : : Value ( " gray " ) ; break ;
case ' 8 ' : a_Value [ " color " ] = Json : : Value ( " dark_gray " ) ; break ;
case ' 9 ' : a_Value [ " color " ] = Json : : Value ( " blue " ) ; break ;
case ' a ' : a_Value [ " color " ] = Json : : Value ( " green " ) ; break ;
case ' b ' : a_Value [ " color " ] = Json : : Value ( " aqua " ) ; break ;
case ' c ' : a_Value [ " color " ] = Json : : Value ( " red " ) ; break ;
case ' d ' : a_Value [ " color " ] = Json : : Value ( " light_purple " ) ; break ;
case ' e ' : a_Value [ " color " ] = Json : : Value ( " yellow " ) ; break ;
case ' f ' : a_Value [ " color " ] = Json : : Value ( " white " ) ; break ;
} // switch (color)
} // case '@'
} // switch (Style[i])
} // for i - a_PartStyle[]
}
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 ( ) ;
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 ( ) ;
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-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 ( ) )
{
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 ) ;
WriteByte ( Frame . GetRotation ( ) ) ;
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 ( ) )
{
case cMonster : : mtCreeper :
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cCreeper & ) a_Mob ) . IsBlowing ( ) ? 1 : - 1 ) ;
WriteByte ( 0x11 ) ;
WriteByte ( ( ( const cCreeper & ) a_Mob ) . IsCharged ( ) ? 1 : 0 ) ;
break ;
}
case cMonster : : mtBat :
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cBat & ) a_Mob ) . IsHanging ( ) ? 1 : 0 ) ;
break ;
}
case cMonster : : mtPig :
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cPig & ) a_Mob ) . IsSaddled ( ) ? 1 : 0 ) ;
break ;
}
case cMonster : : mtVillager :
{
WriteByte ( 0x50 ) ;
WriteInt ( ( ( const cVillager & ) a_Mob ) . GetVilType ( ) ) ;
break ;
}
case cMonster : : mtZombie :
{
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 ;
}
case cMonster : : mtGhast :
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cGhast & ) a_Mob ) . IsCharging ( ) ) ;
break ;
}
case cMonster : : mtWolf :
{
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 ;
}
case cMonster : : mtSheep :
{
WriteByte ( 0x10 ) ;
Byte SheepMetadata = 0 ;
SheepMetadata = ( ( const cSheep & ) a_Mob ) . GetFurColor ( ) ;
if ( ( ( const cSheep & ) a_Mob ) . IsSheared ( ) )
{
SheepMetadata | = 0x10 ;
}
WriteByte ( SheepMetadata ) ;
break ;
}
case cMonster : : mtEnderman :
{
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 ;
}
case cMonster : : mtSkeleton :
{
WriteByte ( 0x0d ) ;
WriteByte ( ( ( const cSkeleton & ) a_Mob ) . IsWither ( ) ? 1 : 0 ) ;
break ;
}
case cMonster : : mtWitch :
{
WriteByte ( 0x15 ) ;
WriteByte ( ( ( const cWitch & ) a_Mob ) . IsAngry ( ) ? 1 : 0 ) ;
break ;
}
2014-03-25 04:32:58 -04:00
case cMonster : : mtWither :
{
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
case cMonster : : mtSlime :
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cSlime & ) a_Mob ) . GetSize ( ) ) ;
break ;
}
case cMonster : : mtMagmaCube :
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cMagmaCube & ) a_Mob ) . GetSize ( ) ) ;
break ;
}
case cMonster : : mtHorse :
{
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())
}
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-04-14 14:21:00 -04:00
Pkt . WriteString ( a_Player . GetClientHandle ( ) - > GetUUID ( ) ) ;
2014-04-14 12:52:21 -04:00
Pkt . WriteString ( a_Player . GetName ( ) ) ;
2014-07-14 14:49:31 -04:00
2014-07-16 07:05:09 -04:00
const Json : : Value & Properties = m_Client - > GetProperties ( ) ;
const Json : : Value : : const_iterator End = Properties . end ( ) ;
Pkt . WriteVarInt ( Properties . size ( ) ) ;
for ( Json : : Value : : iterator itr = Properties . begin ( ) ; itr ! = End ; + + itr )
2014-07-14 14:49:31 -04:00
{
Pkt . WriteString ( ( ( Json : : Value ) * itr ) . get ( " name " , " " ) . toStyledString ( ) ) ;
Pkt . WriteString ( ( ( Json : : Value ) * itr ) . get ( " value " , " " ) . toStyledString ( ) ) ;
Pkt . WriteString ( ( ( Json : : Value ) * itr ) . get ( " signature " , " " ) . toStyledString ( ) ) ;
}
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 )
{
// Send the response:
2014-07-19 09:07:28 -04:00
AString Response = " { \" version \" : { \" name \" : \" 1.7.6 \" , \" protocol \" :5}, \" players \" : { " ;
AppendPrintf ( Response , " \" max \" : %u, \" online \" : %u, \" sample \" : []}, " ,
2014-04-14 16:52:59 -04:00
cRoot : : Get ( ) - > GetServer ( ) - > GetMaxPlayers ( ) ,
cRoot : : Get ( ) - > GetServer ( ) - > GetNumPlayers ( )
) ;
2014-07-19 09:07:28 -04:00
AppendPrintf ( Response , " \" description \" : { \" text \" : \" %s \" }, " ,
2014-04-14 16:52:59 -04:00
cRoot : : Get ( ) - > GetServer ( ) - > GetDescription ( ) . c_str ( )
) ;
2014-07-19 09:07:28 -04:00
AppendPrintf ( Response , " \" favicon \" : \" data:image/png;base64,%s \" " ,
2014-04-14 16:52:59 -04:00
cRoot : : Get ( ) - > GetServer ( ) - > GetFaviconData ( ) . c_str ( )
) ;
Response . append ( " } " ) ;
cPacketizer Pkt ( * this , 0x00 ) ; // Response packet
Pkt . WriteString ( Response ) ;
}