More info: http://forum.mc-server.org/showthread.php?tid=555 git-svn-id: http://mc-server.googlecode.com/svn/trunk@836 0a769ca7-a7f5-676a-18bf-c427514a06d6
		
			
				
	
	
		
			1367 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1367 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
 | 
						|
// Protocol125.cpp
 | 
						|
 | 
						|
// Implements the cProtocol125 class representing the release 1.2.5 protocol (#29)
 | 
						|
 | 
						|
#include "Globals.h"
 | 
						|
 | 
						|
#include "Protocol125.h"
 | 
						|
 | 
						|
#include "cClientHandle.h"
 | 
						|
#include "ChunkDataSerializer.h"
 | 
						|
#include "cEntity.h"
 | 
						|
#include "cMonster.h"
 | 
						|
#include "cPickup.h"
 | 
						|
#include "cPlayer.h"
 | 
						|
#include "cChatColor.h"
 | 
						|
#include "cWindow.h"
 | 
						|
#include "cRoot.h"
 | 
						|
#include "cServer.h"
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
enum
 | 
						|
{
 | 
						|
	PACKET_KEEP_ALIVE                = 0x00,
 | 
						|
	PACKET_LOGIN                     = 0x01,
 | 
						|
	PACKET_HANDSHAKE                 = 0x02,
 | 
						|
	PACKET_CHAT                      = 0x03,
 | 
						|
	PACKET_UPDATE_TIME               = 0x04,
 | 
						|
	PACKET_ENTITY_EQUIPMENT          = 0x05,
 | 
						|
	PACKET_USE_ENTITY                = 0x07,
 | 
						|
	PACKET_UPDATE_HEALTH             = 0x08,
 | 
						|
	PACKET_RESPAWN                   = 0x09,
 | 
						|
	PACKET_PLAYER_ON_GROUND          = 0x0a,
 | 
						|
	PACKET_PLAYER_POS                = 0x0b,
 | 
						|
	PACKET_PLAYER_LOOK               = 0x0c,
 | 
						|
	PACKET_PLAYER_MOVE_LOOK          = 0x0d,
 | 
						|
	PACKET_BLOCK_DIG                 = 0x0e,
 | 
						|
	PACKET_BLOCK_PLACE               = 0x0f,
 | 
						|
	PACKET_SLOT_SELECTED             = 0x10,
 | 
						|
	PACKET_ADD_TO_INV                = 0x11,  // TODO: Sure this is not Use Bed??
 | 
						|
	PACKET_ANIMATION                 = 0x12,
 | 
						|
	PACKET_PACKET_ENTITY_ACTION      = 0x13,
 | 
						|
	PACKET_PLAYER_SPAWN              = 0x14,
 | 
						|
	PACKET_PICKUP_SPAWN              = 0x15,
 | 
						|
	PACKET_COLLECT_PICKUP            = 0x16,
 | 
						|
	PACKET_ADD_VEHICLE               = 0x17,
 | 
						|
	PACKET_SPAWN_MOB                 = 0x18,
 | 
						|
	PACKET_DESTROY_ENTITY            = 0x1d,
 | 
						|
	PACKET_ENTITY                    = 0x1e,
 | 
						|
	PACKET_ENT_REL_MOVE              = 0x1f,
 | 
						|
	PACKET_ENT_LOOK                  = 0x20,
 | 
						|
	PACKET_ENT_REL_MOVE_LOOK         = 0x21,
 | 
						|
	PACKET_ENT_TELEPORT              = 0x22,
 | 
						|
	PACKET_ENT_HEAD_LOOK             = 0x23,
 | 
						|
	PACKET_ENT_STATUS                = 0x26,
 | 
						|
	PACKET_METADATA                  = 0x28,
 | 
						|
	PACKET_PRE_CHUNK                 = 0x32,
 | 
						|
	PACKET_MAP_CHUNK                 = 0x33,
 | 
						|
	PACKET_MULTI_BLOCK               = 0x34,
 | 
						|
	PACKET_BLOCK_CHANGE              = 0x35,
 | 
						|
	PACKET_BLOCK_ACTION              = 0x36,
 | 
						|
	PACKET_EXPLOSION                 = 0x3C,
 | 
						|
	PACKET_SOUND_EFFECT              = 0x3D,
 | 
						|
	PACKET_CHANGE_GAME_STATE         = 0x46,
 | 
						|
	PACKET_THUNDERBOLT               = 0x47,
 | 
						|
	PACKET_WINDOW_OPEN               = 0x64,
 | 
						|
	PACKET_WINDOW_CLOSE              = 0x65,
 | 
						|
	PACKET_WINDOW_CLICK              = 0x66,
 | 
						|
	PACKET_INVENTORY_SLOT            = 0x67,
 | 
						|
	PACKET_INVENTORY_WHOLE           = 0x68,
 | 
						|
	PACKET_INVENTORY_PROGRESS        = 0x69,
 | 
						|
	PACKET_CREATIVE_INVENTORY_ACTION = 0x6B,
 | 
						|
	PACKET_UPDATE_SIGN               = 0x82,
 | 
						|
	PACKET_PLAYER_LIST_ITEM          = 0xC9,
 | 
						|
	PACKET_PLAYER_ABILITIES          = 0xca,
 | 
						|
	PACKET_PING                      = 0xfe,
 | 
						|
	PACKET_DISCONNECT                = 0xff
 | 
						|
} ;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#define HANDLE_PACKET_READ(Proc, Type, Var) \
 | 
						|
	Type Var; \
 | 
						|
	{ \
 | 
						|
		if (!m_ReceivedData.Proc(Var)) \
 | 
						|
		{ \
 | 
						|
			return PARSE_INCOMPLETE; \
 | 
						|
		} \
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
typedef unsigned char Byte;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
cProtocol125::cProtocol125(cClientHandle * a_Client) :
 | 
						|
	super(a_Client),
 | 
						|
	m_ReceivedData(64 KiB)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
 | 
						|
{
 | 
						|
	UNUSED(a_BlockType);
 | 
						|
	
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte (PACKET_BLOCK_ACTION);
 | 
						|
	WriteInt  (a_BlockX);
 | 
						|
	WriteShort((short)a_BlockY);
 | 
						|
	WriteInt  (a_BlockZ);
 | 
						|
	WriteByte (a_Byte1);
 | 
						|
	WriteByte (a_Byte2);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_BLOCK_CHANGE);
 | 
						|
	WriteInt (a_BlockX);
 | 
						|
	WriteByte((unsigned char)a_BlockY);
 | 
						|
	WriteInt (a_BlockZ);
 | 
						|
	WriteByte(a_BlockType);
 | 
						|
	WriteByte(a_BlockMeta);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	if (a_Changes.size() == 1)
 | 
						|
	{
 | 
						|
		// Special packet for single-block changes
 | 
						|
		const sSetBlock & blk = a_Changes.front();
 | 
						|
		SendBlockChange(a_ChunkX * cChunkDef::Width + blk.x, blk.y, a_ChunkZ * cChunkDef::Width + blk.z, blk.BlockType, blk.BlockMeta);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	
 | 
						|
	WriteByte (PACKET_MULTI_BLOCK);
 | 
						|
	WriteInt  (a_ChunkX);
 | 
						|
	WriteInt  (a_ChunkZ);
 | 
						|
	WriteShort((unsigned short)a_Changes.size());
 | 
						|
	WriteInt  (sizeof(int) * a_Changes.size());
 | 
						|
	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);
 | 
						|
		WriteInt(Coords << 16 | Blocks);
 | 
						|
	}
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendChat(const AString & a_Message)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte  (PACKET_CHAT);
 | 
						|
	WriteString(a_Message);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
 | 
						|
	// Send the pre-chunk:
 | 
						|
	SendPreChunk(a_ChunkX, a_ChunkZ, true);
 | 
						|
	
 | 
						|
	// Send the chunk data:
 | 
						|
	AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_2_5);
 | 
						|
	WriteByte(PACKET_MAP_CHUNK);
 | 
						|
	WriteInt (a_ChunkX);
 | 
						|
	WriteInt (a_ChunkZ);
 | 
						|
	SendData(Serialized.data(), Serialized.size());
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_COLLECT_PICKUP);
 | 
						|
	WriteInt (a_Pickup.GetUniqueID());
 | 
						|
	WriteInt (a_Player.GetUniqueID());
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendDestroyEntity(const cEntity & a_Entity)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_DESTROY_ENTITY);
 | 
						|
	WriteInt (a_Entity.GetUniqueID());
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendDisconnect(const AString & a_Reason)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte  ((unsigned char)PACKET_DISCONNECT);
 | 
						|
	WriteString(a_Reason);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendEntHeadLook(const cEntity & a_Entity)
 | 
						|
{
 | 
						|
	ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID());  // Must not send for self
 | 
						|
	
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_ENT_HEAD_LOOK);
 | 
						|
	WriteInt (a_Entity.GetUniqueID());
 | 
						|
	WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendEntLook(const cEntity & a_Entity)
 | 
						|
{
 | 
						|
	ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID());  // Must not send for self
 | 
						|
	
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_ENT_LOOK);
 | 
						|
	WriteInt (a_Entity.GetUniqueID());
 | 
						|
	WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
 | 
						|
	WriteByte((char)((a_Entity.GetPitch()    / 360.f) * 256));
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte (PACKET_ENTITY_EQUIPMENT);
 | 
						|
	WriteInt  (a_Entity.GetUniqueID());
 | 
						|
	WriteShort(a_SlotNum);
 | 
						|
	WriteShort(a_Item.m_ItemType);
 | 
						|
	WriteShort(a_Item.m_ItemDamage);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendEntityStatus(const cEntity & a_Entity, char a_Status)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_ENT_STATUS);
 | 
						|
	WriteInt (a_Entity.GetUniqueID());
 | 
						|
	WriteByte(a_Status);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendEntRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
 | 
						|
{
 | 
						|
	ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID());  // Must not send for self
 | 
						|
	
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_ENT_REL_MOVE);
 | 
						|
	WriteInt (a_Entity.GetUniqueID());
 | 
						|
	WriteByte(a_RelX);
 | 
						|
	WriteByte(a_RelY);
 | 
						|
	WriteByte(a_RelZ);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendEntRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
 | 
						|
{
 | 
						|
	ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID());  // Must not send for self
 | 
						|
	
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_ENT_REL_MOVE_LOOK);
 | 
						|
	WriteInt (a_Entity.GetUniqueID());
 | 
						|
	WriteByte(a_RelX);
 | 
						|
	WriteByte(a_RelY);
 | 
						|
	WriteByte(a_RelZ);
 | 
						|
	WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
 | 
						|
	WriteByte((char)((a_Entity.GetPitch()    / 360.f) * 256));
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendGameMode(eGameMode a_GameMode)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_CHANGE_GAME_STATE);
 | 
						|
	WriteByte(3);
 | 
						|
	WriteByte((char)a_GameMode);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendHandshake(const AString & a_ConnectionHash)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte  (PACKET_HANDSHAKE);
 | 
						|
	WriteString(a_ConnectionHash);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendHealth(void)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte (PACKET_UPDATE_HEALTH);
 | 
						|
	WriteShort((short)m_Client->GetPlayer()->GetHealth());
 | 
						|
	WriteShort(m_Client->GetPlayer()->GetFoodLevel());
 | 
						|
	WriteFloat(m_Client->GetPlayer()->GetFoodSaturationLevel());
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendInventoryProgress(char a_WindowID, short a_ProgressBar, short a_Value)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte (PACKET_INVENTORY_PROGRESS);
 | 
						|
	WriteByte (a_WindowID);
 | 
						|
	WriteShort(a_ProgressBar);
 | 
						|
	WriteShort(a_Value);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte (PACKET_INVENTORY_SLOT);
 | 
						|
	WriteByte (a_WindowID);
 | 
						|
	WriteShort(a_SlotNum);
 | 
						|
	WriteItem (a_Item);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendKeepAlive(int a_PingID)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_KEEP_ALIVE);
 | 
						|
	WriteInt (a_PingID);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
 | 
						|
{
 | 
						|
	UNUSED(a_World);
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
 | 
						|
	WriteByte  (PACKET_LOGIN);
 | 
						|
	WriteInt   (a_Player.GetUniqueID());  // EntityID of the player
 | 
						|
	WriteString("");  // Username, not used
 | 
						|
	WriteString("default");  // Level type
 | 
						|
	WriteInt   ((int)a_Player.GetGameMode());
 | 
						|
	WriteInt   (0);  // TODO: Dimension (Nether / Overworld / End)
 | 
						|
	WriteByte  (2);  // TODO: Difficulty
 | 
						|
	WriteByte  (0);  // Unused
 | 
						|
	WriteByte  (60);  // Client list width or something
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendMetadata(const cEntity & a_Entity)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_METADATA);
 | 
						|
	WriteInt (a_Entity.GetUniqueID());
 | 
						|
	AString MetaData = GetEntityMetaData(a_Entity);
 | 
						|
	SendData(MetaData.data(), MetaData.size());
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte   (PACKET_PICKUP_SPAWN);
 | 
						|
	WriteInt    (a_Pickup.GetUniqueID());
 | 
						|
	WriteShort  (a_Pickup.GetItem()->m_ItemType);
 | 
						|
	WriteByte   (a_Pickup.GetItem()->m_ItemCount);
 | 
						|
	WriteShort  (a_Pickup.GetItem()->m_ItemDamage);
 | 
						|
	WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32));
 | 
						|
	WriteByte   ((char)(a_Pickup.GetSpeed().x * 8));
 | 
						|
	WriteByte   ((char)(a_Pickup.GetSpeed().y * 8));
 | 
						|
	WriteByte   ((char)(a_Pickup.GetSpeed().z * 8));
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_ANIMATION);
 | 
						|
	WriteInt (a_Player.GetUniqueID());
 | 
						|
	WriteByte(a_Animation);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	AString PlayerName(a_Player.GetColor());
 | 
						|
	PlayerName.append(a_Player.GetName());
 | 
						|
	if (PlayerName.length() > 14)
 | 
						|
	{
 | 
						|
		PlayerName.erase(14);
 | 
						|
	}
 | 
						|
	PlayerName += cChatColor::White;
 | 
						|
 | 
						|
	WriteByte  ((unsigned char)PACKET_PLAYER_LIST_ITEM);
 | 
						|
	WriteString(PlayerName);
 | 
						|
	WriteBool  (a_IsOnline);
 | 
						|
	WriteShort (a_Player.GetClientHandle()->GetPing());
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendPlayerMoveLook(void)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
 | 
						|
	/*
 | 
						|
	LOGD("Sending PlayerMoveLook: {%0.2f, %0.2f, %0.2f}, stance %0.2f, OnGround: %d",
 | 
						|
		m_Player->GetPosX(), m_Player->GetPosY(), m_Player->GetPosZ(), m_Player->GetStance(), m_Player->IsOnGround() ? 1 : 0
 | 
						|
	);
 | 
						|
	*/
 | 
						|
 | 
						|
	WriteByte	(PACKET_PLAYER_MOVE_LOOK);
 | 
						|
	cPlayer * Player = m_Client->GetPlayer();
 | 
						|
	WriteDouble(Player->GetPosX());
 | 
						|
	WriteDouble(Player->GetStance() + 0.03);  // Add a small amount so that the player doesn't start inside a block
 | 
						|
	WriteDouble(Player->GetPosY()   + 0.03);  // Add a small amount so that the player doesn't start inside a block
 | 
						|
	WriteDouble(Player->GetPosZ());
 | 
						|
	WriteFloat (Player->GetRotation());
 | 
						|
	WriteFloat (Player->GetPitch());
 | 
						|
	WriteBool  (Player->IsOnGround());
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendPlayerPosition(void)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	LOGD("Ignore send PlayerPos");  // PlayerPos is a C->S packet only now
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
 | 
						|
{
 | 
						|
	const cItem & HeldItem = a_Player.GetEquippedItem();
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte	 (PACKET_PLAYER_SPAWN);
 | 
						|
	WriteInt   (a_Player.GetUniqueID());
 | 
						|
	WriteString(a_Player.GetName());
 | 
						|
	WriteInt   ((int)(a_Player.GetPosX() * 32));
 | 
						|
	WriteInt   ((int)(a_Player.GetPosY() * 32));
 | 
						|
	WriteInt   ((int)(a_Player.GetPosZ() * 32));
 | 
						|
	WriteByte  ((char)((a_Player.GetRot().x / 360.f) * 256));
 | 
						|
	WriteByte  ((char)((a_Player.GetRot().y / 360.f) * 256));
 | 
						|
	WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendRespawn(void)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte  (PACKET_RESPAWN);
 | 
						|
	WriteInt   (0);  // TODO: Dimension;  0 = Overworld
 | 
						|
	WriteByte  (2);  // TODO: Difficulty; 2 = Normal
 | 
						|
	WriteByte  ((char)m_Client->GetPlayer()->GetGameMode());
 | 
						|
	WriteShort (256);  // Current world height
 | 
						|
	WriteString("default");
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendSpawnMob(const cMonster & a_Mob)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte   (PACKET_SPAWN_MOB);
 | 
						|
	WriteInt    (a_Mob.GetUniqueID());
 | 
						|
	WriteByte   (a_Mob.GetMobType());
 | 
						|
	WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
 | 
						|
	WriteByte   (0);
 | 
						|
	WriteByte   (0);
 | 
						|
	WriteByte   (0);
 | 
						|
	AString MetaData = GetEntityMetaData(a_Mob);
 | 
						|
	SendData (MetaData.data(), MetaData.size());
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendTeleportEntity(const cEntity & a_Entity)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte   (PACKET_ENT_TELEPORT);
 | 
						|
	WriteInt    (a_Entity.GetUniqueID());
 | 
						|
	WriteVectorI((Vector3i)(a_Entity.GetPosition() * 32));
 | 
						|
	WriteByte   ((char)((a_Entity.GetRotation() / 360.f) * 256));
 | 
						|
	WriteByte   ((char)((a_Entity.GetPitch() / 360.f) * 256));
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_THUNDERBOLT);
 | 
						|
	WriteInt (0x7fffffff);  // Entity ID of the thunderbolt; we use a constant one
 | 
						|
	WriteBool(true);  // Unknown bool
 | 
						|
	WriteInt (a_BlockX * 32);
 | 
						|
	WriteInt (a_BlockY * 32);
 | 
						|
	WriteInt (a_BlockZ * 32);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendTimeUpdate(Int64 a_WorldTime)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte (PACKET_UPDATE_TIME);
 | 
						|
	WriteInt64(a_WorldTime);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	SendPreChunk(a_ChunkX, a_ChunkZ, false);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::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
 | 
						|
)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte  ((unsigned char)PACKET_UPDATE_SIGN);
 | 
						|
	WriteInt   (a_BlockX);
 | 
						|
	WriteShort ((short)a_BlockY);
 | 
						|
	WriteInt   (a_BlockZ);
 | 
						|
	WriteString(a_Line1);
 | 
						|
	WriteString(a_Line2);
 | 
						|
	WriteString(a_Line3);
 | 
						|
	WriteString(a_Line4);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendWeather(eWeather a_Weather)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	switch( a_Weather )
 | 
						|
	{
 | 
						|
		case eWeather_Sunny:
 | 
						|
		{
 | 
						|
			WriteByte(PACKET_CHANGE_GAME_STATE);
 | 
						|
			WriteByte(2);  // Stop rain
 | 
						|
			WriteByte(0);  // Unused
 | 
						|
			Flush();
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		
 | 
						|
		case eWeather_Rain:
 | 
						|
		case eWeather_ThunderStorm:
 | 
						|
		{
 | 
						|
			WriteByte(PACKET_CHANGE_GAME_STATE);
 | 
						|
			WriteByte(1);  // Begin rain
 | 
						|
			WriteByte(0);  // Unused
 | 
						|
			Flush();
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendWholeInventory(const cInventory & a_Inventory)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	SendWholeInventory(0, a_Inventory.c_NumSlots, a_Inventory.GetSlots());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendWholeInventory(const cWindow & a_Window)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	SendWholeInventory(
 | 
						|
		(char)a_Window.GetWindowID(), 
 | 
						|
		a_Window.GetNumSlots(),
 | 
						|
		a_Window.GetSlots()
 | 
						|
	);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendWindowClose(char a_WindowID)
 | 
						|
{
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte(PACKET_WINDOW_CLOSE);
 | 
						|
	WriteByte(a_WindowID);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots)
 | 
						|
{
 | 
						|
	if (a_WindowType < 0)
 | 
						|
	{
 | 
						|
		// Do not send for inventory windows
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	cCSLock Lock(m_CSPacket);
 | 
						|
	WriteByte  (PACKET_WINDOW_OPEN);
 | 
						|
	WriteByte  (a_WindowID);
 | 
						|
	WriteByte  (a_WindowType);
 | 
						|
	WriteString(a_WindowTitle);
 | 
						|
	WriteByte  (a_NumSlots);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendData(const char * a_Data, int a_Size)
 | 
						|
{
 | 
						|
	m_Client->SendData(a_Data, a_Size);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::DataReceived(const char * a_Data, int a_Size)
 | 
						|
{
 | 
						|
	if (!m_ReceivedData.Write(a_Data, a_Size))
 | 
						|
	{
 | 
						|
		// Too much data in the incoming queue, report to caller:
 | 
						|
		m_Client->PacketBufferFull();
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	// Parse and handle all complete packets in m_ReceivedData:
 | 
						|
	while (m_ReceivedData.CanReadBytes(1))
 | 
						|
	{
 | 
						|
		unsigned char PacketType;
 | 
						|
		m_ReceivedData.ReadByte(PacketType);
 | 
						|
		switch (ParsePacket(PacketType))
 | 
						|
		{
 | 
						|
			case PARSE_UNKNOWN:
 | 
						|
			{
 | 
						|
				// An unknown packet has been received, notify the client and abort:
 | 
						|
				m_Client->PacketUnknown(PacketType);
 | 
						|
				return;
 | 
						|
			}
 | 
						|
			case PARSE_ERROR:
 | 
						|
			{
 | 
						|
				// An error occurred while parsing a known packet, notify the client and abort:
 | 
						|
				m_Client->PacketError(PacketType);
 | 
						|
				return;
 | 
						|
			}
 | 
						|
			case PARSE_INCOMPLETE:
 | 
						|
			{
 | 
						|
				// Incomplete packet, bail out and process with the next batch of data
 | 
						|
				m_ReceivedData.ResetRead();
 | 
						|
				return;
 | 
						|
			}
 | 
						|
			default:
 | 
						|
			{
 | 
						|
				// Packet successfully parsed, commit the read data and try again one more packet
 | 
						|
				m_ReceivedData.CommitRead();
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParsePacket(unsigned char a_PacketType)
 | 
						|
{
 | 
						|
	switch (a_PacketType)
 | 
						|
	{
 | 
						|
		default: return PARSE_UNKNOWN;
 | 
						|
		case PACKET_ANIMATION:                 return ParseArmAnim();
 | 
						|
		case PACKET_BLOCK_DIG:                 return ParseBlockDig();
 | 
						|
		case PACKET_BLOCK_PLACE:               return ParseBlockPlace();
 | 
						|
		case PACKET_CHAT:                      return ParseChat();
 | 
						|
		case PACKET_CREATIVE_INVENTORY_ACTION: return ParseCreativeInventoryAction();
 | 
						|
		case PACKET_DISCONNECT:                return ParseDisconnect();
 | 
						|
		case PACKET_HANDSHAKE:                 return ParseHandshake();
 | 
						|
		case PACKET_KEEP_ALIVE:                return ParseKeepAlive();
 | 
						|
		case PACKET_LOGIN:                     return ParseLogin();
 | 
						|
		case PACKET_PACKET_ENTITY_ACTION:      return ParseEntityAction();
 | 
						|
		case PACKET_PING:                      return ParsePing();
 | 
						|
		case PACKET_PLAYER_ABILITIES:          return ParsePlayerAbilities();
 | 
						|
		case PACKET_PLAYER_LOOK:               return ParsePlayerLook();
 | 
						|
		case PACKET_PLAYER_MOVE_LOOK:          return ParsePlayerMoveLook();
 | 
						|
		case PACKET_PLAYER_ON_GROUND:          return ParsePlayerOnGround();
 | 
						|
		case PACKET_PLAYER_POS:                return ParsePlayerPosition();
 | 
						|
		case PACKET_RESPAWN:                   return ParseRespawn();
 | 
						|
		case PACKET_SLOT_SELECTED:             return ParseSlotSelected();
 | 
						|
		case PACKET_UPDATE_SIGN:               return ParseUpdateSign();
 | 
						|
		case PACKET_USE_ENTITY:                return ParseUseEntity();
 | 
						|
		case PACKET_WINDOW_CLICK:              return ParseWindowClick();
 | 
						|
		case PACKET_WINDOW_CLOSE:              return ParseWindowClose();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#define HANDLE_PACKET_PARSE(Packet) \
 | 
						|
	{ \
 | 
						|
		int res = Packet.Parse(m_ReceivedData); \
 | 
						|
		if (res < 0) \
 | 
						|
		{ \
 | 
						|
			return res; \
 | 
						|
		} \
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseArmAnim(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt, int,  EntityID);
 | 
						|
	HANDLE_PACKET_READ(ReadChar,  char, Animation);
 | 
						|
	m_Client->HandleAnimation(Animation);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseBlockDig(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadChar,	char, Status);
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt, int,  PosX);
 | 
						|
	HANDLE_PACKET_READ(ReadByte,	Byte, PosY);
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt, int,  PosZ);
 | 
						|
	HANDLE_PACKET_READ(ReadChar,	char, Direction);
 | 
						|
	m_Client->HandleBlockDig(PosX, PosY, PosZ, Direction, Status);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseBlockPlace(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt, int,  PosX);
 | 
						|
	HANDLE_PACKET_READ(ReadByte,  Byte, PosY);
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt, int,  PosZ);
 | 
						|
	HANDLE_PACKET_READ(ReadChar,  char, Direction);
 | 
						|
 | 
						|
	cItem HeldItem;
 | 
						|
	int res = ParseItem(HeldItem);
 | 
						|
	if (res < 0)
 | 
						|
	{
 | 
						|
		return res;
 | 
						|
	}
 | 
						|
 | 
						|
	m_Client->HandleBlockPlace(PosX, PosY, PosZ, Direction, HeldItem);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseChat(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Message);
 | 
						|
	m_Client->HandleChat(Message);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseCreativeInventoryAction(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEShort, short, SlotNum);
 | 
						|
	cItem HeldItem;
 | 
						|
	int res = ParseItem(HeldItem);
 | 
						|
	if (res < 0)
 | 
						|
	{
 | 
						|
		return res;
 | 
						|
	}
 | 
						|
	m_Client->HandleCreativeInventory(SlotNum, HeldItem);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseDisconnect(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Reason);
 | 
						|
	m_Client->HandleDisconnect(Reason);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseEntityAction(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt, int,  EntityID);
 | 
						|
	HANDLE_PACKET_READ(ReadChar,  char, ActionID);
 | 
						|
	// TODO: m_Client->HandleEntityAction(...);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseHandshake(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username);
 | 
						|
 | 
						|
	AStringVector UserData = StringSplit(Username, ";"); // "FakeTruth;localhost:25565"
 | 
						|
	if (UserData.empty())
 | 
						|
	{
 | 
						|
		m_Client->Kick("Did not receive username");
 | 
						|
		return PARSE_OK;
 | 
						|
	}
 | 
						|
	m_Username = UserData[0];
 | 
						|
 | 
						|
	LOGD("HANDSHAKE %s", Username.c_str());
 | 
						|
 | 
						|
	if (!m_Client->HandleHandshake( m_Username ))
 | 
						|
	{
 | 
						|
		return PARSE_OK; // Player is not allowed into the server
 | 
						|
	}
 | 
						|
 | 
						|
	SendHandshake(cRoot::Get()->GetServer()->GetServerID());
 | 
						|
	LOGD("User \"%s\" was sent a handshake response", m_Username.c_str());
 | 
						|
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseKeepAlive(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt, int, KeepAliveID);
 | 
						|
	m_Client->HandleKeepAlive(KeepAliveID);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseLogin(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt,           int,     ProtocolVersion);
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username);
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, LevelType);
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt,           int,     ServerMode);
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt,           int,     Dimension);
 | 
						|
	HANDLE_PACKET_READ(ReadChar,            char,    Difficulty);
 | 
						|
	HANDLE_PACKET_READ(ReadByte,            Byte,    WorldHeight);
 | 
						|
	HANDLE_PACKET_READ(ReadByte,            Byte,    MaxPlayers);
 | 
						|
 | 
						|
	if (ProtocolVersion < 29)
 | 
						|
	{
 | 
						|
		m_Client->Kick("Your client is outdated!");
 | 
						|
		return PARSE_OK;
 | 
						|
	}
 | 
						|
	else if (ProtocolVersion > 29)
 | 
						|
	{
 | 
						|
		m_Client->Kick("Your client version is higher than the server!");
 | 
						|
		return PARSE_OK;
 | 
						|
	}
 | 
						|
 | 
						|
	if (m_Username.compare(Username) != 0)
 | 
						|
	{
 | 
						|
		LOGWARNING("Login Username (\"%s\") does not match Handshake username (\"%s\") for client @ \"%s\", kicking",
 | 
						|
			Username.c_str(),
 | 
						|
			m_Username.c_str(),
 | 
						|
			m_Client->GetIPString().c_str()
 | 
						|
		);
 | 
						|
		m_Client->Kick("Hacked client");  // Don't tell them why we don't want them
 | 
						|
		return PARSE_OK;
 | 
						|
	}
 | 
						|
 | 
						|
	m_Client->HandleLogin(ProtocolVersion, Username);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParsePing(void)
 | 
						|
{
 | 
						|
	// Packet has no more data
 | 
						|
	m_Client->HandlePing();
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParsePlayerAbilities(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBool, bool, Invulnerable);
 | 
						|
	HANDLE_PACKET_READ(ReadBool, bool, IsFlying);
 | 
						|
	HANDLE_PACKET_READ(ReadBool, bool, CanFly);
 | 
						|
	HANDLE_PACKET_READ(ReadBool, bool, InstaMine);
 | 
						|
	// TODO: m_Client->HandlePlayerAbilities(...);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParsePlayerLook(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEFloat, float, Rotation);
 | 
						|
	HANDLE_PACKET_READ(ReadBEFloat, float, Pitch);
 | 
						|
	HANDLE_PACKET_READ(ReadBool,    bool,  IsOnGround);
 | 
						|
	m_Client->HandlePlayerLook(Rotation, Pitch, IsOnGround);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParsePlayerMoveLook(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEDouble, double, PosX);
 | 
						|
	HANDLE_PACKET_READ(ReadBEDouble, double, PosY);
 | 
						|
	HANDLE_PACKET_READ(ReadBEDouble, double, Stance);
 | 
						|
	HANDLE_PACKET_READ(ReadBEDouble, double, PosZ);
 | 
						|
	HANDLE_PACKET_READ(ReadBEFloat,  float,  Rotation);
 | 
						|
	HANDLE_PACKET_READ(ReadBEFloat,  float,  Pitch);
 | 
						|
	HANDLE_PACKET_READ(ReadBool,     bool,   IsOnGround);
 | 
						|
	// LOGD("Recv PML: {%0.2f, %0.2f, %0.2f}, Stance %0.2f, Gnd: %d", PosX, PosY, PosZ, Stance, IsOnGround ? 1 : 0);
 | 
						|
	m_Client->HandlePlayerMoveLook(PosX, PosY, PosZ, Stance, Rotation, Pitch, IsOnGround);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParsePlayerOnGround(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBool, bool, IsOnGround);
 | 
						|
	// TODO: m_Client->HandleFlying(IsOnGround);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParsePlayerPosition(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEDouble, double, PosX);
 | 
						|
	HANDLE_PACKET_READ(ReadBEDouble, double, PosY);
 | 
						|
	HANDLE_PACKET_READ(ReadBEDouble, double, Stance);
 | 
						|
	HANDLE_PACKET_READ(ReadBEDouble, double, PosZ);
 | 
						|
	HANDLE_PACKET_READ(ReadBool,     bool,   IsOnGround);
 | 
						|
	m_Client->HandlePlayerPos(PosX, PosY, PosZ, Stance, IsOnGround);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseRespawn(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt,           int,     Dimension);
 | 
						|
	HANDLE_PACKET_READ(ReadChar,            char,    Difficulty);
 | 
						|
	HANDLE_PACKET_READ(ReadChar,            char,    CreativeMode);
 | 
						|
	HANDLE_PACKET_READ(ReadBEShort,         short,   WorldHeight);
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, LevelType);
 | 
						|
	m_Client->HandleRespawn();
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseSlotSelected(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEShort, short, SlotNum);
 | 
						|
	m_Client->HandleSlotSelected(SlotNum);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseUpdateSign(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt,           int,     BlockX);
 | 
						|
	HANDLE_PACKET_READ(ReadBEShort,         short,   BlockY);
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt,           int,     BlockZ);
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line1);
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line2);
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line3);
 | 
						|
	HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line4);
 | 
						|
	m_Client->HandleUpdateSign(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseUseEntity(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt, int,  SourceEntityID);
 | 
						|
	HANDLE_PACKET_READ(ReadBEInt, int,  TargetEntityID);
 | 
						|
	HANDLE_PACKET_READ(ReadBool,  bool, IsLeftClick);
 | 
						|
	m_Client->HandleUseEntity(TargetEntityID, IsLeftClick);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseWindowClick(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadChar,    char,  WindowID);
 | 
						|
	HANDLE_PACKET_READ(ReadBEShort, short, SlotNum);
 | 
						|
	HANDLE_PACKET_READ(ReadBool,    bool,  IsRightClick);
 | 
						|
	HANDLE_PACKET_READ(ReadBEShort, short, TransactionID);
 | 
						|
	HANDLE_PACKET_READ(ReadBool,    bool,  IsShiftPressed);
 | 
						|
	cItem HeldItem;
 | 
						|
	int res = ParseItem(HeldItem);
 | 
						|
	if (res < 0)
 | 
						|
	{
 | 
						|
		return res;
 | 
						|
	}
 | 
						|
	m_Client->HandleWindowClick(WindowID, SlotNum, IsRightClick, IsShiftPressed, HeldItem);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseWindowClose(void)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadChar, char, WindowID);
 | 
						|
	m_Client->HandleWindowClose(WindowID);
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad)
 | 
						|
{
 | 
						|
	WriteByte(PACKET_PRE_CHUNK);
 | 
						|
	WriteInt (a_ChunkX);
 | 
						|
	WriteInt (a_ChunkZ);
 | 
						|
	WriteBool(a_ShouldLoad);
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::SendWholeInventory(char a_WindowID, int a_NumItems, const cItem * a_Items)
 | 
						|
{
 | 
						|
	WriteByte (PACKET_INVENTORY_WHOLE);
 | 
						|
	WriteByte (a_WindowID);
 | 
						|
	WriteShort((short)a_NumItems);
 | 
						|
 | 
						|
	for (int j = 0; j < a_NumItems; j++)
 | 
						|
	{
 | 
						|
		WriteItem(a_Items[j]);
 | 
						|
	}
 | 
						|
	Flush();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cProtocol125::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;
 | 
						|
	}
 | 
						|
	
 | 
						|
	WriteShort(ItemType);
 | 
						|
	if (a_Item.IsEmpty())
 | 
						|
	{
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	
 | 
						|
	WriteByte (a_Item.m_ItemCount);
 | 
						|
	WriteShort(a_Item.m_ItemDamage);
 | 
						|
	
 | 
						|
	if (cItem::IsEnchantable(a_Item.m_ItemType))
 | 
						|
	{
 | 
						|
		// TODO: Implement enchantments
 | 
						|
		WriteShort(-1);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int cProtocol125::ParseItem(cItem & a_Item)
 | 
						|
{
 | 
						|
	HANDLE_PACKET_READ(ReadBEShort, short, ItemType);
 | 
						|
 | 
						|
	if (ItemType <= -1)
 | 
						|
	{
 | 
						|
		a_Item.Empty();
 | 
						|
		return PARSE_OK;
 | 
						|
	}
 | 
						|
	a_Item.m_ItemType = ItemType;
 | 
						|
 | 
						|
	HANDLE_PACKET_READ(ReadChar,    char,  ItemCount);
 | 
						|
	HANDLE_PACKET_READ(ReadBEShort, short, ItemDamage);
 | 
						|
	a_Item.m_ItemCount  = ItemCount;
 | 
						|
	a_Item.m_ItemDamage = ItemDamage;
 | 
						|
	if (ItemCount <= 0)
 | 
						|
	{
 | 
						|
		a_Item.Empty();
 | 
						|
	}
 | 
						|
 | 
						|
	if (!cItem::IsEnchantable(ItemType))
 | 
						|
	{
 | 
						|
		return PARSE_OK;
 | 
						|
	}
 | 
						|
	
 | 
						|
	HANDLE_PACKET_READ(ReadBEShort, short, EnchantNumBytes);
 | 
						|
	
 | 
						|
	if (EnchantNumBytes == 0)
 | 
						|
	{
 | 
						|
		return PARSE_OK;
 | 
						|
	}
 | 
						|
		
 | 
						|
	// TODO: Enchantment not implemented yet!
 | 
						|
	if (!m_ReceivedData.SkipRead(EnchantNumBytes))
 | 
						|
	{
 | 
						|
		return PARSE_INCOMPLETE;
 | 
						|
	}
 | 
						|
	
 | 
						|
	return PARSE_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
AString cProtocol125::GetEntityMetaData(const cEntity & a_Entity)
 | 
						|
{
 | 
						|
	// We should send all the metadata here
 | 
						|
	AString MetaData;
 | 
						|
	// Common metadata (index 0, byte):
 | 
						|
	MetaData.push_back(0);
 | 
						|
	MetaData.push_back(GetEntityMetadataFlags(a_Entity));
 | 
						|
	
 | 
						|
	// TODO: Add more entity-specific metadata
 | 
						|
	
 | 
						|
	MetaData.push_back(0x7f);  // End metadata
 | 
						|
	return MetaData;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
char cProtocol125::GetEntityMetadataFlags(const cEntity & a_Entity)
 | 
						|
{
 | 
						|
	char Flags = 0;
 | 
						|
	if (a_Entity.IsOnFire())
 | 
						|
	{
 | 
						|
		Flags |= 1;
 | 
						|
	}
 | 
						|
	if (a_Entity.IsCrouched())
 | 
						|
	{
 | 
						|
		Flags |= 2;
 | 
						|
	}
 | 
						|
	if (a_Entity.IsRiding())
 | 
						|
	{
 | 
						|
		Flags |= 4;
 | 
						|
	}
 | 
						|
	if (a_Entity.IsSprinting())
 | 
						|
	{
 | 
						|
		Flags |= 8;
 | 
						|
	}
 | 
						|
	if (a_Entity.IsRclking())
 | 
						|
	{
 | 
						|
		Flags |= 16;
 | 
						|
	}
 | 
						|
	return Flags;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 |