From 66f4c9e0c08762fb4668792999c6200e9fd78c89 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Mon, 27 Aug 2012 17:31:16 +0000 Subject: Cut out all packet handling to a separate cProtocol descendant git-svn-id: http://mc-server.googlecode.com/svn/trunk@796 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Bindings.cpp | 4 +- source/Bindings.h | 2 +- source/ByteBuffer.cpp | 9 + source/ByteBuffer.h | 3 + source/PacketID.h | 2 +- source/Protocol.h | 95 ++++ source/Protocol125.cpp | 1104 +++++++++++++++++++++++++++++++++++++ source/Protocol125.h | 126 +++++ source/ProtocolRecognizer.h | 78 +++ source/cChunk.cpp | 109 ---- source/cChunkMap.cpp | 38 -- source/cChunkMap.h | 8 - source/cClientHandle.cpp | 1067 ++++++----------------------------- source/cClientHandle.h | 104 ++-- source/cServer.cpp | 18 - source/cServer.h | 1 - source/cSocketThreads.cpp | 3 +- source/cSocketThreads.h | 4 +- source/cWindow.h | 4 +- source/cWorld.cpp | 55 +- source/cWorld.h | 11 +- source/packets/cPacket.h | 9 +- source/packets/cPacket_13.h | 2 +- source/packets/cPacket_Player.cpp | 12 +- source/packets/cPacket_Player.h | 2 +- 25 files changed, 1685 insertions(+), 1185 deletions(-) create mode 100644 source/Protocol.h create mode 100644 source/Protocol125.cpp create mode 100644 source/Protocol125.h create mode 100644 source/ProtocolRecognizer.h (limited to 'source') diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 56e17be1a..9b356ab5f 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/25/12 23:57:06. +** Generated automatically by tolua++-1.0.92 on 08/27/12 16:12:30. */ #ifndef __cplusplus @@ -21119,7 +21119,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"E_ITEM_SWITCH",E_ITEM_SWITCH); tolua_constant(tolua_S,"E_ADD_TO_INV",E_ADD_TO_INV); tolua_constant(tolua_S,"E_ANIMATION",E_ANIMATION); - tolua_constant(tolua_S,"E_PACKET_13",E_PACKET_13); + tolua_constant(tolua_S,"E_PACKET_ENTITY_ACTION",E_PACKET_ENTITY_ACTION); tolua_constant(tolua_S,"E_NAMED_ENTITY_SPAWN",E_NAMED_ENTITY_SPAWN); tolua_constant(tolua_S,"E_PICKUP_SPAWN",E_PICKUP_SPAWN); tolua_constant(tolua_S,"E_COLLECT_ITEM",E_COLLECT_ITEM); diff --git a/source/Bindings.h b/source/Bindings.h index 82dfb6034..39946bd56 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/25/12 23:57:07. +** Generated automatically by tolua++-1.0.92 on 08/27/12 16:12:30. */ /* Exported function */ diff --git a/source/ByteBuffer.cpp b/source/ByteBuffer.cpp index e410bdfe0..af7151260 100644 --- a/source/ByteBuffer.cpp +++ b/source/ByteBuffer.cpp @@ -306,6 +306,15 @@ bool cByteBuffer::SkipRead(int a_Count) +void cByteBuffer::ReadAll(AString & a_Data) +{ + ReadString(a_Data, GetReadableSpace()); +} + + + + + void cByteBuffer::CommitRead(void) { m_DataStart = m_ReadPos; diff --git a/source/ByteBuffer.h b/source/ByteBuffer.h index f49461fce..68dc48cd9 100644 --- a/source/ByteBuffer.h +++ b/source/ByteBuffer.h @@ -68,6 +68,9 @@ public: /// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer bool SkipRead(int a_Count); + /// Reads all available data into a_Data + void ReadAll(AString & a_Data); + /// Removes the bytes that have been read from the ringbuffer void CommitRead(void); diff --git a/source/PacketID.h b/source/PacketID.h index aa7fec4c0..3167d04a8 100644 --- a/source/PacketID.h +++ b/source/PacketID.h @@ -27,7 +27,7 @@ enum ENUM_PACKET_ID E_ITEM_SWITCH = 0x10, // OBSOLETE, use E_SLOT_SELECTED instead E_ADD_TO_INV = 0x11, // TODO: Sure this is not Use Bed?? E_ANIMATION = 0x12, - E_PACKET_13 = 0x13, + E_PACKET_ENTITY_ACTION = 0x13, E_NAMED_ENTITY_SPAWN = 0x14, E_PICKUP_SPAWN = 0x15, E_COLLECT_ITEM = 0x16, diff --git a/source/Protocol.h b/source/Protocol.h new file mode 100644 index 000000000..4422b45ba --- /dev/null +++ b/source/Protocol.h @@ -0,0 +1,95 @@ + +// Protocol.h + +// Interfaces to the cProtocol class representing the generic interface that a protocol +// parser and serializer must implement + + + + + +#pragma once + +#include "Defines.h" + + + + +class cPlayer; +class cEntity; +class cWindow; +class cInventory; +class cPawn; +class cPickup; +class cMonster; +class cChunkDataSerializer; + + + + + +class cProtocol +{ +public: + cProtocol(cClientHandle * a_Client) : + m_Client(a_Client) + { + } + + /// Called when client sends some data + virtual void DataReceived(const char * a_Data, int a_Size) = 0; + + // Sending stuff to clients: + virtual void SendDisconnect (const AString & a_Reason) = 0; + virtual void SendLogin (const cPlayer & a_Player) = 0; + virtual void SendHandshake (const AString & a_ServerName) = 0; + virtual void SendInventorySlot (int a_WindowID, short a_SlotNum, const cItem & a_Item) = 0; + virtual void SendChat (const AString & a_Message) = 0; + virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) = 0; + virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) = 0; + virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) = 0; + virtual void SendWindowClose (char a_WindowID) = 0; + virtual void SendWholeInventory (const cInventory & a_Inventory) = 0; + virtual void SendWholeInventory (const cWindow & a_Window) = 0; + virtual void SendTeleportEntity (const cEntity & a_Entity) = 0; + virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) = 0; + virtual void SendPlayerPosition (void) = 0; + virtual void SendRelEntMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) = 0; + virtual void SendRelEntMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) = 0; + virtual void SendEntLook (const cEntity & a_Entity) = 0; + virtual void SendEntHeadLook (const cEntity & a_Entity) = 0; + virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) = 0; + virtual void SendHealth (void) = 0; + virtual void SendRespawn (void) = 0; + virtual void SendGameMode (eGameMode a_GameMode) = 0; + virtual void SendDestroyEntity (const cEntity & a_Entity) = 0; + virtual void SendPlayerMoveLook (void) = 0; + virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) = 0; + virtual void SendMetadata (const cPawn & a_Entity) = 0; + virtual void SendInventoryProgress(char a_WindowID, short a_Progressbar, short a_Value) = 0; + virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; + virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0; + virtual void SendSpawnMob (const cMonster & a_Mob) = 0; + virtual void 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) = 0; + virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) = 0; + virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; + virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 0; + virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0; + virtual void SendWeather (eWeather a_Weather) = 0; + virtual void SendTimeUpdate (Int64 a_WorldTime) = 0; + virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; + virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) = 0; + virtual void SendKeepAlive (int a_PingID) = 0; + +protected: + cClientHandle * m_Client; + cCriticalSection m_CSPacket; //< Each SendXYZ() function must acquire this CS in order to send the whole packet at once + + /// A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it + virtual void SendData(const char * a_Data, int a_Size) = 0; +} ; + + + + + diff --git a/source/Protocol125.cpp b/source/Protocol125.cpp new file mode 100644 index 000000000..73d9ab672 --- /dev/null +++ b/source/Protocol125.cpp @@ -0,0 +1,1104 @@ + +// Protocol125.cpp + +// Implements the cProtocol125 class representing the release 1.2.5 protocol (#29) + +#include "Globals.h" + +#include "Protocol125.h" + +#include "packets/cPacket.h" +#include "packets/cPacket_13.h" +#include "packets/cPacket_ArmAnim.h" +#include "packets/cPacket_BlockAction.h" +#include "packets/cPacket_BlockChange.h" +#include "packets/cPacket_BlockDig.h" +#include "packets/cPacket_BlockPlace.h" +#include "packets/cPacket_Chat.h" +#include "packets/cPacket_CollectItem.h" +#include "packets/cPacket_CreativeInventoryAction.h" +#include "packets/cPacket_DestroyEntity.h" +#include "packets/cPacket_Disconnect.h" +#include "packets/cPacket_EntityEquipment.h" +#include "packets/cPacket_EntityLook.h" +#include "packets/cPacket_EntityStatus.h" +#include "packets/cPacket_Flying.h" +#include "packets/cPacket_Handshake.h" +#include "packets/cPacket_InventoryProgressBar.h" +#include "packets/cPacket_InventorySlot.h" +#include "packets/cPacket_ItemSwitch.h" +#include "packets/cPacket_KeepAlive.h" +#include "packets/cPacket_Login.h" +#include "packets/cPacket_MapChunk.h" +#include "packets/cPacket_Metadata.h" +#include "packets/cPacket_MultiBlock.h" +#include "packets/cPacket_NamedEntitySpawn.h" +#include "packets/cPacket_NewInvalidState.h" +#include "packets/cPacket_PickupSpawn.h" +#include "packets/cPacket_Ping.h" +#include "packets/cPacket_Player.h" +#include "packets/cPacket_PreChunk.h" +#include "packets/cPacket_RelativeEntityMove.h" +#include "packets/cPacket_RelativeEntityMoveLook.h" +#include "packets/cPacket_Respawn.h" +#include "packets/cPacket_SpawnMob.h" +#include "packets/cPacket_TeleportEntity.h" +#include "packets/cPacket_Thunderbolt.h" +#include "packets/cPacket_TimeUpdate.h" +#include "packets/cPacket_UpdateHealth.h" +#include "packets/cPacket_UpdateSign.h" +#include "packets/cPacket_UseEntity.h" +#include "packets/cPacket_WholeInventory.h" +#include "packets/cPacket_WindowClick.h" +#include "packets/cPacket_WindowClose.h" +#include "packets/cPacket_WindowOpen.h" + +#include "cClientHandle.h" +#include "ChunkDataSerializer.h" +#include "cEntity.h" +#include "cMonster.h" +#include "cPickup.h" +#include "cPlayer.h" + + + + + +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) +{ + cCSLock Lock(m_CSPacket); + cPacket_BlockAction ba; + ba.m_BlockX = a_BlockX; + ba.m_BlockY = (short)a_BlockY; + ba.m_BlockZ = a_BlockZ; + ba.m_Byte1 = a_Byte1; + ba.m_Byte2 = a_Byte2; + Send(ba); +} + + + + + +void cProtocol125::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +{ + cCSLock Lock(m_CSPacket); + cPacket_BlockChange BlockChange; + BlockChange.m_PosX = a_BlockX; + BlockChange.m_PosY = (unsigned char)a_BlockY; + BlockChange.m_PosZ = a_BlockZ; + BlockChange.m_BlockType = a_BlockType; + BlockChange.m_BlockMeta = a_BlockMeta; + Send(BlockChange); +} + + + + + +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; + } + + cPacket_MultiBlock MultiBlock; + MultiBlock.m_ChunkX = a_ChunkX; + MultiBlock.m_ChunkZ = a_ChunkZ; + MultiBlock.m_NumBlocks = (short)a_Changes.size(); + MultiBlock.m_Data = new cPacket_MultiBlock::sBlockChange[a_Changes.size()]; + int i = 0; + for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr, i++) + { + unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12); + unsigned int Blocks = itr->BlockMeta | (itr->BlockType << 4); + MultiBlock.m_Data[i].Data = Coords << 16 | Blocks; + } + Send(MultiBlock); +} + + + + + +void cProtocol125::SendChat(const AString & a_Message) +{ + cCSLock Lock(m_CSPacket); + cPacket_Chat Chat(a_Message); + Send(Chat); +} + + + + + +void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) +{ + cCSLock Lock(m_CSPacket); + + // Send the pre-chunk: + cPacket_PreChunk pre(a_ChunkX, a_ChunkZ, true); + Send(pre); + + // Send the data: + cPacket_MapChunk mc(a_ChunkX, a_ChunkZ, a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_2_5)); + Send(mc); +} + + + + + +void cProtocol125::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +{ + cCSLock Lock(m_CSPacket); + cPacket_CollectItem ci; + ci.m_CollectedID = a_Pickup.GetUniqueID(); + ci.m_CollectorID = a_Player.GetUniqueID(); + Send(ci); +} + + + + + +void cProtocol125::SendDestroyEntity(const cEntity & a_Entity) +{ + cCSLock Lock(m_CSPacket); + cPacket_DestroyEntity de; + de.m_UniqueID = a_Entity.GetUniqueID(); + Send(de); +} + + + + + +void cProtocol125::SendDisconnect(const AString & a_Reason) +{ + cCSLock Lock(m_CSPacket); + cPacket_Disconnect DC(a_Reason); + Send(DC); // TODO: Send it immediately to the socket, bypassing any packet buffers (? is it safe? packet boundaries...) +} + + + + + +void cProtocol125::SendEntHeadLook(const cEntity & a_Entity) +{ + ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self + + cCSLock Lock(m_CSPacket); + cPacket_EntityHeadLook ehl(a_Entity); + Send(ehl); +} + + + + + +void cProtocol125::SendEntLook(const cEntity & a_Entity) +{ + ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self + + cCSLock Lock(m_CSPacket); + cPacket_EntityLook el; + el.m_UniqueID = a_Entity.GetUniqueID(); + el.m_Rotation = (char)((a_Entity.GetRotation() / 360.f) * 256); + el.m_Pitch = (char)((a_Entity.GetPitch() / 360.f) * 256); + Send(el); +} + + + + + +void cProtocol125::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) +{ + cCSLock Lock(m_CSPacket); + cPacket_EntityEquipment ee; + ee.m_UniqueID = a_Entity.GetUniqueID(); + ee.m_SlotNum = a_SlotNum; + ee.m_ItemType = a_Item.m_ItemType; + ee.m_ItemDamage = a_Item.m_ItemDamage; + Send(ee); +} + + + + + +void cProtocol125::SendEntityStatus(const cEntity & a_Entity, char a_Status) +{ + cCSLock Lock(m_CSPacket); + cPacket_EntityStatus es; + es.m_Status = a_Status; + es.m_UniqueID = a_Entity.GetUniqueID(); + Send(es); +} + + + + + +void cProtocol125::SendGameMode(eGameMode a_GameMode) +{ + cCSLock Lock(m_CSPacket); + cPacket_NewInvalidState nis; + nis.m_Reason = 3; + nis.m_GameMode = (char)a_GameMode; + Send(nis); +} + + + + + +void cProtocol125::SendHandshake(const AString & a_ServerName) +{ + cCSLock Lock(m_CSPacket); + cPacket_Handshake Handshake; + Handshake.m_Username = a_ServerName; + Send(Handshake); +} + + + + + +void cProtocol125::SendHealth(void) +{ + cCSLock Lock(m_CSPacket); + cPacket_UpdateHealth Health; + Health.m_Health = (short)m_Client->GetPlayer()->GetHealth(); + Health.m_Food = m_Client->GetPlayer()->GetFoodLevel(); + Health.m_Saturation = m_Client->GetPlayer()->GetFoodSaturationLevel(); + Send(Health); +} + + + + + +void cProtocol125::SendInventoryProgress(char a_WindowID, short a_ProgressBar, short a_Value) +{ + cCSLock Lock(m_CSPacket); + cPacket_InventoryProgressBar Progress; + Progress.m_WindowID = a_WindowID; + Progress.m_ProgressBar = a_ProgressBar; + Progress.m_Value = a_Value; + Progress.m_WindowID = a_WindowID; + Send(Progress); +} + + + + + +void cProtocol125::SendInventorySlot(int a_WindowID, short a_SlotNum, const cItem & a_Item) +{ + cCSLock Lock(m_CSPacket); + cPacket_InventorySlot Packet; + Packet.m_WindowID = (char)a_WindowID; + Packet.m_SlotNum = a_SlotNum; + Packet.m_ItemID = (short)(a_Item.m_ItemID); + Packet.m_ItemCount = a_Item.m_ItemCount; + Packet.m_ItemUses = a_Item.m_ItemHealth; + Send(Packet); +} + + + + + +void cProtocol125::SendKeepAlive(int a_PingID) +{ + cCSLock Lock(m_CSPacket); + cPacket_KeepAlive ka(a_PingID); + Send(ka); +} + + + + + +void cProtocol125::SendLogin(const cPlayer & a_Player) +{ + cCSLock Lock(m_CSPacket); + cPacket_Login LoginResponse; + LoginResponse.m_ProtocolVersion = a_Player.GetUniqueID(); + LoginResponse.m_Username = ""; // Not used + LoginResponse.m_ServerMode = a_Player.GetGameMode(); // set gamemode from player. + LoginResponse.m_Dimension = 0; // TODO: Dimension (Nether / Overworld / End) + LoginResponse.m_MaxPlayers = 60; // Client list width or something + LoginResponse.m_Difficulty = 2; // TODO: Difficulty + Send(LoginResponse); +} + + + + + +void cProtocol125::SendMetadata(const cPawn & a_Pawn) +{ + cCSLock Lock(m_CSPacket); + cPacket_Metadata md(a_Pawn.GetMetaData(), a_Pawn.GetUniqueID()); + Send(md); +} + + + + + +void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup) +{ + cCSLock Lock(m_CSPacket); + cPacket_PickupSpawn PickupSpawn; + PickupSpawn.m_UniqueID = a_Pickup.GetUniqueID(); + PickupSpawn.m_ItemType = a_Pickup.GetItem()->m_ItemType; + PickupSpawn.m_ItemCount = a_Pickup.GetItem()->m_ItemCount; + PickupSpawn.m_ItemDamage = a_Pickup.GetItem()->m_ItemHealth; + PickupSpawn.m_PosX = (int) (a_Pickup.GetPosX() * 32); + PickupSpawn.m_PosY = (int) (a_Pickup.GetPosY() * 32); + PickupSpawn.m_PosZ = (int) (a_Pickup.GetPosZ() * 32); + PickupSpawn.m_Rotation = (char)(a_Pickup.GetSpeed().x * 8); + PickupSpawn.m_Pitch = (char)(a_Pickup.GetSpeed().y * 8); + PickupSpawn.m_Roll = (char)(a_Pickup.GetSpeed().z * 8); + Send(PickupSpawn); +} + + + + + +void cProtocol125::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation) +{ + cCSLock Lock(m_CSPacket); + cPacket_ArmAnim Anim; + Anim.m_EntityID = a_Player.GetUniqueID(); + Anim.m_Animation = a_Animation; + Send(Anim); +} + + + + + +void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) +{ + cCSLock Lock(m_CSPacket); + cPacket_PlayerListItem pli(a_Player.GetColor() + a_Player.GetName(), a_IsOnline, a_Player.GetClientHandle()->GetPing()); + Send(pli); +} + + + + + +void cProtocol125::SendPlayerMoveLook(void) +{ + cCSLock Lock(m_CSPacket); + cPacket_PlayerMoveLook pml(*m_Client->GetPlayer()); + /* + 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 + ); + */ + Send(pml); +} + + + + + +void cProtocol125::SendPlayerPosition(void) +{ + cCSLock Lock(m_CSPacket); + cPacket_PlayerPosition pp(*(m_Client->GetPlayer())); + Send(pp); +} + + + + + +void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) +{ + cCSLock Lock(m_CSPacket); + cPacket_NamedEntitySpawn SpawnPacket; + SpawnPacket.m_UniqueID = a_Player.GetUniqueID(); + SpawnPacket.m_PlayerName = a_Player.GetName(); + SpawnPacket.m_PosX = (int)(a_Player.GetPosX() * 32); + SpawnPacket.m_PosY = (int)(a_Player.GetPosY() * 32); + SpawnPacket.m_PosZ = (int)(a_Player.GetPosZ() * 32); + SpawnPacket.m_Rotation = (char)((a_Player.GetRot().x / 360.f) * 256); + SpawnPacket.m_Pitch = (char)((a_Player.GetRot().y / 360.f) * 256); + const cItem & HeldItem = a_Player.GetEquippedItem(); + SpawnPacket.m_CurrentItem = HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType; // Unlike -1 in inventory, the named entity packet uses 0 for "empty" + Send(SpawnPacket); +} + + + + + +void cProtocol125::SendRelEntMove(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); + cPacket_RelativeEntityMove rem; + rem.m_UniqueID = a_Entity.GetUniqueID(); + rem.m_MoveX = a_RelX; + rem.m_MoveY = a_RelY; + rem.m_MoveZ = a_RelZ; + Send(rem); +} + + + + + +void cProtocol125::SendRelEntMoveLook(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); + cPacket_RelativeEntityMoveLook reml; + reml.m_UniqueID = a_Entity.GetUniqueID(); + reml.m_MoveX = a_RelX; + reml.m_MoveY = a_RelY; + reml.m_MoveZ = a_RelZ; + reml.m_Yaw = (char)((a_Entity.GetRotation() / 360.f) * 256); + reml.m_Pitch = (char)((a_Entity.GetPitch() / 360.f) * 256); + Send(reml); +} + + + + + +void cProtocol125::SendRespawn(void) +{ + cCSLock Lock(m_CSPacket); + cPacket_Respawn Packet; + Packet.m_CreativeMode = (char)m_Client->GetPlayer()->GetGameMode(); // Set GameMode packet based on Player's GameMode; + Send(Packet); +} + + + + + +void cProtocol125::SendSpawnMob(const cMonster & a_Mob) +{ + cCSLock Lock(m_CSPacket); + cPacket_SpawnMob Spawn; + Spawn.m_UniqueID = a_Mob.GetUniqueID(); + Spawn.m_Type = a_Mob.GetMobType(); + Spawn.m_Pos = ((Vector3i)(a_Mob.GetPosition())) * 32; + Spawn.m_Yaw = 0; + Spawn.m_Pitch = 0; + Spawn.m_MetaDataSize = 1; + Spawn.m_MetaData = new char[Spawn.m_MetaDataSize]; + Spawn.m_MetaData[0] = 0x7f; // not on fire/crouching/riding + Send(Spawn); +} + + + + + +void cProtocol125::SendTeleportEntity(const cEntity & a_Entity) +{ + cCSLock Lock(m_CSPacket); + cPacket_TeleportEntity te(a_Entity); + Send(te); +} + + + + + +void cProtocol125::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + cCSLock Lock(m_CSPacket); + cPacket_Thunderbolt ThunderboltPacket; + ThunderboltPacket.m_xLBPos = a_BlockX; + ThunderboltPacket.m_yLBPos = a_BlockY; + ThunderboltPacket.m_zLBPos = a_BlockZ; + Send(ThunderboltPacket); +} + + + + + +void cProtocol125::SendTimeUpdate(Int64 a_WorldTime) +{ + cCSLock Lock(m_CSPacket); + cPacket_TimeUpdate tu; + tu.m_Time = a_WorldTime; + Send(tu); +} + + + + + +void cProtocol125::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) +{ + cCSLock Lock(m_CSPacket); + cPacket_PreChunk UnloadPacket; + UnloadPacket.m_PosX = a_ChunkX; + UnloadPacket.m_PosZ = a_ChunkZ; + UnloadPacket.m_bLoad = false; // Unload + Send(UnloadPacket); +} + + + + + +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); + cPacket_UpdateSign us; + us.m_BlockX = a_BlockX; + us.m_BlockY = (short)a_BlockY; + us.m_BlockZ = a_BlockZ; + us.m_Line1 = a_Line1; + us.m_Line2 = a_Line2; + us.m_Line3 = a_Line3; + us.m_Line4 = a_Line4; + Send(us); +} + + + + + +void cProtocol125::SendWeather(eWeather a_Weather) +{ + cCSLock Lock(m_CSPacket); + switch( a_Weather ) + { + case eWeather_Sunny: + { + cPacket_NewInvalidState WeatherPacket; + WeatherPacket.m_Reason = 2; // stop rain + Send(WeatherPacket); + break; + } + + case eWeather_Rain: + { + cPacket_NewInvalidState WeatherPacket; + WeatherPacket.m_Reason = 1; // begin rain + Send(WeatherPacket); + break; + } + + case eWeather_ThunderStorm: + { + cPacket_NewInvalidState WeatherPacket; + WeatherPacket.m_Reason = 1; // begin rain + Send(WeatherPacket); + break; + } + } +} + + + + + +void cProtocol125::SendWholeInventory(const cInventory & a_Inventory) +{ + cCSLock Lock(m_CSPacket); + cPacket_WholeInventory wi(a_Inventory); + Send(wi); +} + + + + + +void cProtocol125::SendWholeInventory(const cWindow & a_Window) +{ + cCSLock Lock(m_CSPacket); + cPacket_WholeInventory wi(a_Window); + Send(wi); +} + + + + + +void cProtocol125::SendWindowClose(char a_WindowID) +{ + cCSLock Lock(m_CSPacket); + cPacket_WindowClose wc; + wc.m_WindowID = a_WindowID; + Send(wc); +} + + + + + +void cProtocol125::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) +{ + cCSLock Lock(m_CSPacket); + cPacket_WindowOpen WindowOpen; + WindowOpen.m_WindowID = a_WindowID; + WindowOpen.m_InventoryType = a_WindowType; + WindowOpen.m_WindowTitle = a_WindowTitle; + WindowOpen.m_NumSlots = a_NumSlots; + Send(WindowOpen); +} + + + + + +void cProtocol125::Send(const cPacket & a_Packet) +{ + AString str; + a_Packet.Serialize(str); + SendData(str.data(), str.size()); +} + + + + + +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 PACKET_UNKNOWN: + { + // An unknown packet has been received, notify the client and abort: + m_Client->PacketUnknown(PacketType); + return; + } + case PACKET_ERROR: + { + // An error occurred while parsing a known packet, notify the client and abort: + m_Client->PacketError(PacketType); + return; + } + case PACKET_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 PACKET_UNKNOWN; + case E_KEEP_ALIVE: return ParseKeepAlive(); + case E_HANDSHAKE: return ParseHandshake(); + case E_LOGIN: return ParseLogin(); + case E_PLAYERPOS: return ParsePlayerPosition(); + case E_PLAYERLOOK: return ParsePlayerLook(); + case E_PLAYERMOVELOOK: return ParsePlayerMoveLook(); + case E_PLAYER_ABILITIES: return ParsePlayerAbilities(); + case E_CHAT: return ParseChat(); + case E_ANIMATION: return ParseArmAnim(); + case E_FLYING: return ParseFlying(); + case E_BLOCK_DIG: return ParseBlockDig(); + case E_BLOCK_PLACE: return ParseBlockPlace(); + case E_DISCONNECT: return ParseDisconnect(); + case E_ITEM_SWITCH: return ParseItemSwitch(); + case E_ENTITY_EQUIPMENT: return ParseEntityEquipment(); + case E_CREATIVE_INVENTORY_ACTION: return ParseCreativeInventoryAction(); + case E_NEW_INVALID_STATE: return ParseNewInvalidState(); + case E_PICKUP_SPAWN: return ParsePickupSpawn(); + case E_USE_ENTITY: return ParseUseEntity(); + case E_WINDOW_CLOSE: return ParseWindowClose(); + case E_WINDOW_CLICK: return ParseWindowClick(); + case E_PACKET_ENTITY_ACTION: return ParseEntityAction(); + case E_UPDATE_SIGN: return ParseUpdateSign(); + case E_RESPAWN: return ParseRespawn(); + case E_PING: return ParsePing(); + } +} + + + + + +#define HANDLE_PACKET_PARSE(Packet) \ + { \ + int res = Packet.Parse(m_ReceivedData); \ + if (res < 0) \ + { \ + return res; \ + } \ + } + + + + + +int cProtocol125::ParseKeepAlive(void) +{ + cPacket_KeepAlive KeepAlive; + HANDLE_PACKET_PARSE(KeepAlive); + m_Client->HandleKeepAlive(KeepAlive.m_KeepAliveID); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseHandshake(void) +{ + cPacket_Handshake Handshake; + HANDLE_PACKET_PARSE(Handshake); + m_Client->HandleHandshake(Handshake.m_Username); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseLogin(void) +{ + cPacket_Login Login; + HANDLE_PACKET_PARSE(Login); + m_Client->HandleLogin(Login.m_ProtocolVersion, Login.m_Username); + return PACKET_OK; +} + + + + + +int cProtocol125::ParsePlayerPosition(void) +{ + cPacket_PlayerPosition pp; + HANDLE_PACKET_PARSE(pp); + m_Client->HandlePlayerPos(pp.m_PosX, pp.m_PosY, pp.m_PosZ, pp.m_Stance, pp.m_IsOnGround); + return PACKET_OK; +} + + + + + +int cProtocol125::ParsePlayerLook(void) +{ + cPacket_PlayerLook pl; + HANDLE_PACKET_PARSE(pl); + m_Client->HandlePlayerLook(pl.m_Rotation, pl.m_Pitch, pl.m_IsOnGround); + return PACKET_OK; +} + + + + + +int cProtocol125::ParsePlayerMoveLook(void) +{ + cPacket_PlayerMoveLook pml; + HANDLE_PACKET_PARSE(pml); + m_Client->HandlePlayerMoveLook(pml.m_PosX, pml.m_PosY, pml.m_PosZ, pml.m_Stance, pml.m_Rotation, pml.m_Pitch, pml.m_IsOnGround); + return PACKET_OK; +} + + + + + +int cProtocol125::ParsePlayerAbilities(void) +{ + cPacket_PlayerAbilities pa; + HANDLE_PACKET_PARSE(pa); + // TODO: m_Client->HandlePlayerAbilities(...); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseChat(void) +{ + cPacket_Chat ch; + HANDLE_PACKET_PARSE(ch); + m_Client->HandleChat(ch.m_Message); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseArmAnim(void) +{ + cPacket_ArmAnim aa; + HANDLE_PACKET_PARSE(aa); + m_Client->HandleAnimation(aa.m_Animation); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseFlying(void) +{ + cPacket_Flying fl; + HANDLE_PACKET_PARSE(fl); + // TODO: m_Client->HandleFlying(fl.m_bFlying); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseBlockDig(void) +{ + cPacket_BlockDig bd; + HANDLE_PACKET_PARSE(bd); + m_Client->HandleBlockDig(bd.m_PosX, bd.m_PosY, bd.m_PosZ, bd.m_Direction, bd.m_Status); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseBlockPlace(void) +{ + cPacket_BlockPlace bp; + HANDLE_PACKET_PARSE(bp); + m_Client->HandleBlockPlace(bp.m_PosX, bp.m_PosY, bp.m_PosZ, bp.m_Direction, bp.m_HeldItem); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseDisconnect(void) +{ + cPacket_Disconnect dc; + HANDLE_PACKET_PARSE(dc); + m_Client->HandleDisconnect(dc.m_Reason); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseItemSwitch(void) +{ + cPacket_ItemSwitch its; + HANDLE_PACKET_PARSE(its); + m_Client->HandleSlotSelected(its.m_SlotNum); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseEntityEquipment(void) +{ + cPacket_EntityEquipment ee; + HANDLE_PACKET_PARSE(ee); + // TODO: m_Client->HandleEntityEquipment(...); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseCreativeInventoryAction(void) +{ + cPacket_CreativeInventoryAction cia; + HANDLE_PACKET_PARSE(cia); + m_Client->HandleCreativeInventory(cia.m_SlotNum, cia.m_ClickedItem); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseNewInvalidState(void) +{ + cPacket_NewInvalidState nis; + HANDLE_PACKET_PARSE(nis); + // TODO: m_Client->Handle(...); + return PACKET_OK; +} + + + + + +int cProtocol125::ParsePickupSpawn(void) +{ + cPacket_PickupSpawn ps; + HANDLE_PACKET_PARSE(ps); + // TODO: m_Client->HandlePickupSpawn(...); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseUseEntity(void) +{ + cPacket_UseEntity ue; + HANDLE_PACKET_PARSE(ue); + m_Client->HandleUseEntity(ue.m_TargetEntityID, ue.m_IsLeftClick); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseWindowClose(void) +{ + cPacket_WindowClose wc; + HANDLE_PACKET_PARSE(wc); + m_Client->HandleWindowClose(wc.m_WindowID); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseWindowClick(void) +{ + cPacket_WindowClick wc; + HANDLE_PACKET_PARSE(wc); + m_Client->HandleWindowClick(wc.m_WindowID, wc.m_SlotNum, wc.m_IsRightClick, wc.m_IsShiftPressed, wc.m_HeldItem); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseEntityAction(void) +{ + cPacket_13 ea; + HANDLE_PACKET_PARSE(ea); + // TODO: m_Client->HandleEntityAction(...); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseUpdateSign(void) +{ + cPacket_UpdateSign us; + HANDLE_PACKET_PARSE(us); + m_Client->HandleUpdateSign( + us.m_BlockX, us.m_BlockY, us.m_BlockZ, + us.m_Line1, us.m_Line2, us.m_Line3, us.m_Line4 + ); + return PACKET_OK; +} + + + + + +int cProtocol125::ParseRespawn(void) +{ + cPacket_Respawn rsp; + HANDLE_PACKET_PARSE(rsp); + m_Client->HandleRespawn(); + return PACKET_OK; +} + + + + + +int cProtocol125::ParsePing(void) +{ + cPacket_Ping ping; + HANDLE_PACKET_PARSE(ping); + m_Client->HandlePing(); + return PACKET_OK; +} + + + + + diff --git a/source/Protocol125.h b/source/Protocol125.h new file mode 100644 index 000000000..cfa5c1ecd --- /dev/null +++ b/source/Protocol125.h @@ -0,0 +1,126 @@ + +// Protocol125.h + +// Interfaces to the cProtocol125 class representing the release 1.2.5 protocol (#29) + + + + + +#pragma once + +#include "Protocol.h" +#include "ByteBuffer.h" + + + + + +// fwd: +class cPacket; + + + + + +class cProtocol125 : + public cProtocol +{ + typedef cProtocol super; +public: + cProtocol125(cClientHandle * a_Client); + + /// Called when client sends some data: + virtual void DataReceived(const char * a_Data, int a_Size) override; + + /// Sending stuff to clients: + virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) override; + virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; + virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; + virtual void SendChat (const AString & a_Message) override; + virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; + virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; + virtual void SendDestroyEntity (const cEntity & a_Entity) override; + virtual void SendDisconnect (const AString & a_Reason) override; + virtual void SendEntHeadLook (const cEntity & a_Entity) override; + virtual void SendEntLook (const cEntity & a_Entity) override; + virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; + virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override; + virtual void SendGameMode (eGameMode a_GameMode) override; + virtual void SendHandshake (const AString & a_ServerName) override; + virtual void SendHealth (void) override; + virtual void SendInventoryProgress(char a_WindowID, short a_Progressbar, short a_Value) override; + virtual void SendInventorySlot (int a_WindowID, short a_SlotNum, const cItem & a_Item) override; + virtual void SendKeepAlive (int a_PingID) override; + virtual void SendLogin (const cPlayer & a_Player) override; + virtual void SendMetadata (const cPawn & a_Entity) override; + virtual void SendPickupSpawn (const cPickup & a_Pickup) override; + virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override; + virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override; + virtual void SendPlayerMoveLook (void) override; + virtual void SendPlayerPosition (void) override; + virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendRelEntMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; + virtual void SendRelEntMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; + virtual void SendRespawn (void) override; + virtual void SendSpawnMob (const cMonster & a_Mob) override; + virtual void SendTeleportEntity (const cEntity & a_Entity) override; + virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void SendTimeUpdate (Int64 a_WorldTime) override; + virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; + virtual void 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) override; + virtual void SendWeather (eWeather a_Weather) override; + virtual void SendWholeInventory (const cInventory & a_Inventory) override; + virtual void SendWholeInventory (const cWindow & a_Window) override; + virtual void SendWindowClose (char a_WindowID) override; + virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override; + +protected: + /// Results of packet-parsing: + enum { + PACKET_OK = 1, + PACKET_ERROR = -1, + PACKET_UNKNOWN = -2, + PACKET_INCOMPLETE = -3, + } ; + + cByteBuffer m_ReceivedData; //< Buffer for the received data + + void Send(const cPacket & a_Packet); + + virtual void SendData(const char * a_Data, int a_Size) override; + + /// Parse the packet of the specified type from m_ReceivedData (switch into ParseXYZ() ) + virtual int ParsePacket(unsigned char a_PacketType); + + // Specific packet parsers: + virtual int ParseKeepAlive (void); + virtual int ParseHandshake (void); + virtual int ParseLogin (void); + virtual int ParsePlayerPosition (void); + virtual int ParsePlayerLook (void); + virtual int ParsePlayerMoveLook (void); + virtual int ParsePlayerAbilities (void); + virtual int ParseChat (void); + virtual int ParseArmAnim (void); + virtual int ParseFlying (void); + virtual int ParseBlockDig (void); + virtual int ParseBlockPlace (void); + virtual int ParseDisconnect (void); + virtual int ParseItemSwitch (void); + virtual int ParseEntityEquipment (void); + virtual int ParseCreativeInventoryAction(void); + virtual int ParseNewInvalidState (void); + virtual int ParsePickupSpawn (void); + virtual int ParseUseEntity (void); + virtual int ParseWindowClose (void); + virtual int ParseWindowClick (void); + virtual int ParseEntityAction (void); + virtual int ParseUpdateSign (void); + virtual int ParseRespawn (void); + virtual int ParsePing (void); +} ; + + + + diff --git a/source/ProtocolRecognizer.h b/source/ProtocolRecognizer.h new file mode 100644 index 000000000..5afdf9506 --- /dev/null +++ b/source/ProtocolRecognizer.h @@ -0,0 +1,78 @@ + +// ProtocolRecognizer.h + +// Interfaces to the cProtocolRecognizer class representing the meta-protocol that recognizes possibly multiple +// protocol versions and redirects everything to them + + + + + +#pragma once + +#include "Protocol.h" + + + + + +class cProtocolRecognizer : + public cProtocol +{ +public: + cProtocolRecognizer(cClientHandle * a_Client); + + /// Called when client sends some data: + virtual void DataReceived(const char * a_Data, int a_Size) override; + + /// Sending stuff to clients: + virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) override; + virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; + virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; + virtual void SendChat (const AString & a_Message) override; + virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; + virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; + virtual void SendDestroyEntity (const cEntity & a_Entity) override; + virtual void SendDisconnect (const AString & a_Reason) override; + virtual void SendEntHeadLook (const cEntity & a_Entity) override; + virtual void SendEntLook (const cEntity & a_Entity) override; + virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; + virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override; + virtual void SendGameMode (eGameMode a_GameMode) override; + virtual void SendHandshake (const AString & a_ServerName) override; + virtual void SendHealth (void) override; + virtual void SendInventoryProgress(char a_WindowID, short a_Progressbar, short a_Value) override; + virtual void SendInventorySlot (int a_WindowID, short a_SlotNum, const cItem & a_Item) override; + virtual void SendKeepAlive (int a_PingID) override; + virtual void SendLogin (const cPlayer & a_Player) override; + virtual void SendMetadata (const cPawn & a_Entity) override; + virtual void SendPickupSpawn (const cPickup & a_Pickup) override; + virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override; + virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override; + virtual void SendPlayerMoveLook (void) override; + virtual void SendPlayerPosition (void) override; + virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendRelEntMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; + virtual void SendRelEntMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; + virtual void SendRespawn (void) override; + virtual void SendSpawnMob (const cMonster & a_Mob) override; + virtual void SendTeleportEntity (const cEntity & a_Entity) override; + virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void SendTimeUpdate (Int64 a_WorldTime) override; + virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; + virtual void 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) override; + virtual void SendWeather (eWeather a_Weather) override; + virtual void SendWholeInventory (const cInventory & a_Inventory) override; + virtual void SendWholeInventory (const cWindow & a_Window) override; + virtual void SendWindowClose (char a_WindowID) override; + virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override; + +protected: + cProtocol * m_Protocol; //< The recognized protocol + cByteBuffer m_Buffer; //< Buffer used until the protocol is recognized +} ; + + + + + diff --git a/source/cChunk.cpp b/source/cChunk.cpp index aec75cd41..351f456af 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -1619,115 +1619,6 @@ void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_ -/* -// _X 2012_02_23: Loading in old format not supported anymore -/// Loads the chunk from the old-format disk file, erases the file afterwards. Returns true if successful -bool cChunk::LoadFromDisk() -{ - AString SourceFile; - Printf(SourceFile, "world/X%i_Y%i_Z%i.bin", m_PosX, m_PosY, m_PosZ ); - - cFile f; - if (!f.Open(SourceFile, cFile::fmRead)) - { - return false; - } - - if (f.Read(m_BlockData, sizeof(m_BlockData)) != sizeof(m_BlockData)) - { - LOGERROR("ERROR READING FROM FILE %s", SourceFile.c_str()); - return false; - } - - // Now load Block Entities: - ENUM_BLOCK_ID BlockType; - while (f.Read(&BlockType, sizeof(ENUM_BLOCK_ID)) == sizeof(ENUM_BLOCK_ID)) - { - switch (BlockType) - { - case E_BLOCK_CHEST: - { - cChestEntity * ChestEntity = new cChestEntity( 0, 0, 0, m_World ); - if (!ChestEntity->LoadFromFile(f)) - { - LOGERROR("ERROR READING CHEST FROM FILE %s", SourceFile.c_str()); - delete ChestEntity; - return false; - } - m_BlockEntities.push_back( ChestEntity ); - break; - } - - case E_BLOCK_FURNACE: - { - cFurnaceEntity* FurnaceEntity = new cFurnaceEntity( 0, 0, 0, m_World ); - if (!FurnaceEntity->LoadFromFile(f)) - { - LOGERROR("ERROR READING FURNACE FROM FILE %s", SourceFile.c_str()); - delete FurnaceEntity; - return false; - } - m_BlockEntities.push_back( FurnaceEntity ); - break; - } - - case E_BLOCK_SIGN_POST: - case E_BLOCK_WALLSIGN: - { - cSignEntity * SignEntity = new cSignEntity(BlockType, 0, 0, 0, m_World ); - if (!SignEntity->LoadFromFile( f ) ) - { - LOGERROR("ERROR READING SIGN FROM FILE %s", SourceFile.c_str()); - delete SignEntity; - return false; - } - m_BlockEntities.push_back( SignEntity ); - break; - } - - default: - { - ASSERT(!"Unhandled block entity in file"); - break; - } - } - } - f.Close(); - - // Delete old format file - if (std::remove(SourceFile.c_str()) != 0) - { - LOGERROR("Could not delete file %s", SourceFile.c_str()); - } - else - { - LOGINFO("Successfully deleted old format file \"%s\"", SourceFile.c_str()); - } - m_IsDirty = false; - return true; -} -*/ - - - - - -void cChunk::Broadcast( const cPacket * a_Packet, cClientHandle* a_Exclude) -{ - for (cClientHandleList::const_iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr ) - { - if (*itr == a_Exclude) - { - continue; - } - (*itr)->Send(*a_Packet); - } // for itr - LoadedByClient[] -} - - - - - void cChunk::BroadcastPlayerAnimation(const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude) { for (cClientHandleList::const_iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr ) diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index d46ee36fb..f4203ca4e 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -224,44 +224,6 @@ bool cChunkMap::LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLO -void cChunkMap::BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const cPacket & a_Packet, cClientHandle * a_Exclude) -{ - // Broadcasts a_Packet to all clients in the chunk where block [x, y, z] is, except to client a_Exclude - - cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); - if (Chunk == NULL) - { - return; - } - // It's perfectly legal to broadcast packets even to invalid chunks! - Chunk->Broadcast(a_Packet, a_Exclude); -} - - - - - -void cChunkMap::BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, const cPacket * a_Packet, cClientHandle * a_Exclude) -{ - // Broadcasts a_Packet to all clients in the chunk where block [x, y, z] is, except to client a_Exclude - - cCSLock Lock(m_CSLayers); - int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_X, a_Y, a_Z, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if (Chunk == NULL) - { - return; - } - // It's perfectly legal to broadcast packets even to invalid chunks! - Chunk->Broadcast(a_Packet, a_Exclude); -} - - - - - void cChunkMap::BroadcastPlayerAnimation(const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); diff --git a/source/cChunkMap.h b/source/cChunkMap.h index 3af00b13d..a28b35fb6 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -16,7 +16,6 @@ class cItem; class MTRand; class cChunkStay; class cChunk; -class cPacket; class cPlayer; class cChestEntity; class cFurnaceEntity; @@ -43,13 +42,6 @@ public: cChunkMap(cWorld* a_World ); ~cChunkMap(); - // Direct action methods: - /// Broadcast a_Packet to all clients in the chunk specified - void BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const cPacket & a_Packet, cClientHandle * a_Exclude = NULL); - - /// Broadcasts a_Packet to all clients in the chunk where block [x, y, z] is, except to client a_Exclude - void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, const cPacket * a_Packet, cClientHandle * a_Exclude = NULL); - /// Broadcasts an a_Player's animation to all clients in the chunk where a_Player is void BroadcastPlayerAnimation(const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL); diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 21d1f1722..a939dc786 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -40,50 +40,7 @@ #include "cAuthenticator.h" #include "MersenneTwister.h" -#include "packets/cPacket_13.h" -#include "packets/cPacket_ArmAnim.h" -#include "packets/cPacket_BlockAction.h" -#include "packets/cPacket_BlockChange.h" -#include "packets/cPacket_BlockDig.h" -#include "packets/cPacket_BlockPlace.h" -#include "packets/cPacket_Chat.h" -#include "packets/cPacket_CollectItem.h" -#include "packets/cPacket_CreativeInventoryAction.h" -#include "packets/cPacket_DestroyEntity.h" -#include "packets/cPacket_Disconnect.h" -#include "packets/cPacket_EntityEquipment.h" -#include "packets/cPacket_EntityLook.h" -#include "packets/cPacket_EntityStatus.h" -#include "packets/cPacket_Flying.h" -#include "packets/cPacket_Handshake.h" -#include "packets/cPacket_InventoryProgressBar.h" -#include "packets/cPacket_InventorySlot.h" -#include "packets/cPacket_ItemSwitch.h" -#include "packets/cPacket_KeepAlive.h" -#include "packets/cPacket_Login.h" -#include "packets/cPacket_MapChunk.h" -#include "packets/cPacket_Metadata.h" -#include "packets/cPacket_MultiBlock.h" -#include "packets/cPacket_NamedEntitySpawn.h" -#include "packets/cPacket_NewInvalidState.h" -#include "packets/cPacket_PickupSpawn.h" -#include "packets/cPacket_Ping.h" -#include "packets/cPacket_Player.h" -#include "packets/cPacket_PreChunk.h" -#include "packets/cPacket_RelativeEntityMove.h" -#include "packets/cPacket_RelativeEntityMoveLook.h" -#include "packets/cPacket_Respawn.h" -#include "packets/cPacket_SpawnMob.h" -#include "packets/cPacket_TeleportEntity.h" -#include "packets/cPacket_Thunderbolt.h" -#include "packets/cPacket_TimeUpdate.h" -#include "packets/cPacket_UpdateHealth.h" -#include "packets/cPacket_UpdateSign.h" -#include "packets/cPacket_UseEntity.h" -#include "packets/cPacket_WholeInventory.h" -#include "packets/cPacket_WindowClick.h" -#include "packets/cPacket_WindowClose.h" -#include "packets/cPacket_WindowOpen.h" +#include "Protocol125.h" @@ -126,8 +83,8 @@ int cClientHandle::s_ClientCount = 0; cClientHandle::cClientHandle(const cSocket & a_Socket, int a_ViewDistance) : m_ViewDistance(a_ViewDistance) , m_ProtocolVersion(MCS_PROTOCOL_VERSION) - , m_ReceivedData(64 KiB) , m_Socket(a_Socket) + , m_OutgoingData(64 KiB) , m_bDestroyed(false) , m_Player(NULL) , m_bKicking(false) @@ -139,44 +96,15 @@ cClientHandle::cClientHandle(const cSocket & a_Socket, int a_ViewDistance) , m_LastStreamedChunkZ(0x7fffffff) , m_UniqueID(0) { + m_Protocol = new cProtocol125(this); + s_ClientCount++; // Not protected by CS because clients are always constructed from the same thread m_UniqueID = s_ClientCount; cTimer t1; m_LastPingTime = t1.GetNowTime(); - // All the packets that can be received from the client - for (int i = 0; i < ARRAYCOUNT(m_PacketMap); ++i) - { - m_PacketMap[i] = NULL; - } - m_PacketMap[E_KEEP_ALIVE] = new cPacket_KeepAlive; - m_PacketMap[E_HANDSHAKE] = new cPacket_Handshake; - m_PacketMap[E_LOGIN] = new cPacket_Login; - m_PacketMap[E_PLAYERPOS] = new cPacket_PlayerPosition; - m_PacketMap[E_PLAYERLOOK] = new cPacket_PlayerLook; - m_PacketMap[E_PLAYERMOVELOOK] = new cPacket_PlayerMoveLook; - m_PacketMap[E_PLAYER_ABILITIES] = new cPacket_PlayerAbilities; - m_PacketMap[E_CHAT] = new cPacket_Chat; - m_PacketMap[E_ANIMATION] = new cPacket_ArmAnim; - m_PacketMap[E_FLYING] = new cPacket_Flying; - m_PacketMap[E_BLOCK_DIG] = new cPacket_BlockDig; - m_PacketMap[E_BLOCK_PLACE] = new cPacket_BlockPlace; - m_PacketMap[E_DISCONNECT] = new cPacket_Disconnect; - m_PacketMap[E_ITEM_SWITCH] = new cPacket_ItemSwitch; - m_PacketMap[E_ENTITY_EQUIPMENT] = new cPacket_EntityEquipment; - m_PacketMap[E_CREATIVE_INVENTORY_ACTION] = new cPacket_CreativeInventoryAction; - m_PacketMap[E_NEW_INVALID_STATE] = new cPacket_NewInvalidState; - m_PacketMap[E_PICKUP_SPAWN] = new cPacket_PickupSpawn; - m_PacketMap[E_USE_ENTITY] = new cPacket_UseEntity; - m_PacketMap[E_WINDOW_CLOSE] = new cPacket_WindowClose; - m_PacketMap[E_WINDOW_CLICK] = new cPacket_WindowClick; - m_PacketMap[E_PACKET_13] = new cPacket_13; - m_PacketMap[E_UPDATE_SIGN] = new cPacket_UpdateSign; - m_PacketMap[E_RESPAWN] = new cPacket_Respawn; - m_PacketMap[E_PING] = new cPacket_Ping; - - LOG("New ClientHandle created at %p", this); + LOGD("New ClientHandle created at %p", this); } @@ -185,7 +113,7 @@ cClientHandle::cClientHandle(const cSocket & a_Socket, int a_ViewDistance) cClientHandle::~cClientHandle() { - LOG("Deleting client \"%s\" at %p", GetUsername().c_str(), this); + LOGD("Deleting client \"%s\" at %p", GetUsername().c_str(), this); // Remove from cSocketThreads, we're not to be called anymore: cRoot::Get()->GetServer()->ClientDestroying(this); @@ -202,13 +130,11 @@ cClientHandle::~cClientHandle() if (!m_Username.empty() && (World != NULL)) { // Send the Offline PlayerList packet: - AString NameColor = (m_Player ? m_Player->GetColor() : ""); - cPacket_PlayerListItem PlayerList(NameColor + GetUsername(), false, (short)9999); - World->Broadcast(PlayerList, this); + World->BroadcastPlayerListItem(*m_Player, false, this); // Send the Chat packet: - cPacket_Chat Left(m_Username + " left the game!"); - World->Broadcast(Left, this); + AString Left(m_Username + " left the game!"); + World->BroadcastChat(Left, this); } if (World != NULL) { @@ -229,30 +155,14 @@ cClientHandle::~cClientHandle() m_Player->Destroy(); m_Player = NULL; } - for (int i = 0; i < ARRAYCOUNT(m_PacketMap); i++) - { - delete m_PacketMap[i]; - } // Queue all remaining outgoing packets to cSocketThreads: { - cCSLock Lock(m_CSPackets); - for (PacketList::iterator itr = m_PendingNrmSendPackets.begin(); itr != m_PendingNrmSendPackets.end(); ++itr) - { - AString Data; - (*itr)->Serialize(Data); - cRoot::Get()->GetServer()->WriteToClient(&m_Socket, Data); - delete *itr; - } - m_PendingNrmSendPackets.clear(); - for (PacketList::iterator itr = m_PendingLowSendPackets.begin(); itr != m_PendingLowSendPackets.end(); ++itr) - { - AString Data; - (*itr)->Serialize(Data); - cRoot::Get()->GetServer()->WriteToClient(&m_Socket, Data); - delete *itr; - } - m_PendingLowSendPackets.clear(); + cCSLock Lock(m_CSOutgoingData); + AString Data; + m_OutgoingData.ReadAll(Data); + m_OutgoingData.CommitRead(); + cRoot::Get()->GetServer()->WriteToClient(&m_Socket, Data); } // Queue the socket to close as soon as it sends all outgoing data: @@ -262,7 +172,10 @@ cClientHandle::~cClientHandle() // TODO: The socket needs to stay alive, someone else has to own it cRoot::Get()->GetServer()->RemoveClient(&m_Socket); - LOG("ClientHandle at %p deleted", this); + delete m_Protocol; + m_Protocol = NULL; + + LOGD("ClientHandle at %p deleted", this); } @@ -320,33 +233,26 @@ void cClientHandle::Authenticate(void) World = cRoot::Get()->GetDefaultWorld(); } - if(m_Player->GetGameMode() == eGameMode_NotSet) + if (m_Player->GetGameMode() == eGameMode_NotSet) + { m_Player->LoginSetGameMode(World->GetGameMode()); + } m_Player->SetIP (m_Socket.GetIPString()); cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::HOOK_PLAYER_SPAWN, 1, m_Player); // Return a server login packet - cPacket_Login LoginResponse; - LoginResponse.m_ProtocolVersion = m_Player->GetUniqueID(); - //LoginResponse.m_Username = ""; - LoginResponse.m_ServerMode = m_Player->GetGameMode(); // set gamemode from player. - LoginResponse.m_Dimension = 0; - LoginResponse.m_MaxPlayers = (unsigned char)cRoot::Get()->GetDefaultWorld()->GetMaxPlayers(); - LoginResponse.m_Difficulty = 2; - Send(LoginResponse); + m_Protocol->SendLogin(*m_Player); // Send Weather if raining: if ((World->GetWeather() == 1) || (World->GetWeather() == 2)) { - cPacket_NewInvalidState RainPacket; - RainPacket.m_Reason = 1; //begin rain - Send(RainPacket); + m_Protocol->SendWeather(World->GetWeather()); } // Send time - Send(cPacket_TimeUpdate(World->GetWorldTime())); + m_Protocol->SendTimeUpdate(World->GetWorldTime()); // Send inventory m_Player->GetInventory().SendWholeInventory(this); @@ -422,7 +328,7 @@ void cClientHandle::StreamChunks(void) for (cChunkCoordsList::iterator itr = RemoveChunks.begin(); itr != RemoveChunks.end(); ++itr) { World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ, this); - Send(cPacket_PreChunk(itr->m_ChunkX, itr->m_ChunkZ, false)); + m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - RemoveChunks[] // Add all chunks that are in range and not yet in m_LoadedChunks: @@ -502,232 +408,6 @@ void cClientHandle::RemoveFromAllChunks() -void cClientHandle::HandlePacket(cPacket * a_Packet) -{ - // TODO: _X: This function will get out-sourced into a separate cProtocol class - // and the switch statements will be split into virtual functions of that class - // Therefore I keep this function huge and untidy for the time being - // ( http://forum.mc-server.org/showthread.php?tid=524 ) - - // LOGD("Recv packet %02x", a_Packet->m_PacketID); - - m_TimeLastPacket = cWorld::GetTime(); - - // LOG("Recv packet 0x%02x from client \"%s\" (\"%s\")", a_Packet->m_PacketID, m_Socket.GetIPString().c_str(), m_Username.c_str()); - - if (m_bKicking) - { - return; - } - - switch (m_State) - { - case csConnected: - { - switch (a_Packet->m_PacketID) - { - case E_NEW_INVALID_STATE: // New/Invalid State packet received. I'm guessing the client only sends it when there's a problem with the bed? - { - LOGINFO("Got New Invalid State packet"); - break; - } - case E_PING: HandlePing (); break; - case E_HANDSHAKE: - { - cPacket_Handshake * Handshake = reinterpret_cast(a_Packet); - HandleHandshake(Handshake->m_Username); - break; - } - case E_LOGIN: - { - cPacket_Login * Login = reinterpret_cast(a_Packet); - HandleLogin(Login->m_ProtocolVersion, Login->m_Username); - break; - } - - // Ignored packets: - case E_PLAYERLOOK: - case E_CHAT: - case E_PLAYERMOVELOOK: - case E_PLAYERPOS: - case E_KEEP_ALIVE: break; - default: HandleUnexpectedPacket(a_Packet->m_PacketID); break; - } // switch (PacketType) - break; - } // case csConnected - - case csAuthenticating: - { - // Waiting for external authentication, no packets are handled - switch (a_Packet->m_PacketID) - { - // Ignored packets: - case E_KEEP_ALIVE: - case E_CHAT: - case E_FLYING: - case E_PLAYERLOOK: - case E_PLAYERMOVELOOK: - case E_PLAYERPOS: break; - - default: HandleUnexpectedPacket(a_Packet->m_PacketID); break; - } - break; - } - - case csDownloadingWorld: - { - // Waiting for chunks to stream to client, no packets are handled - switch (a_Packet->m_PacketID) - { - // Ignored packets: - case E_KEEP_ALIVE: - case E_CHAT: - case E_FLYING: - case E_PLAYERLOOK: - case E_PLAYERMOVELOOK: - case E_PLAYERPOS: break; - - default: HandleUnexpectedPacket(a_Packet->m_PacketID); break; - } - break; - } - - case csConfirmingPos: - { - switch (a_Packet->m_PacketID) - { - // Ignored packets: - case E_KEEP_ALIVE: - case E_CHAT: - case E_FLYING: - case E_PLAYERLOOK: - case E_PLAYERPOS: break; - - case E_PLAYERMOVELOOK: - { - cPacket_PlayerMoveLook * MoveLook = reinterpret_cast(a_Packet); - HandleMoveLookConfirm(MoveLook->m_PosX, MoveLook->m_PosY, MoveLook->m_PosZ); - break; - } - - default: - { - HandleUnexpectedPacket(a_Packet->m_PacketID); - break; - } - } // switch (PacketType) - break; - } // case csConfirmingPos - - case csPlaying: - { - switch (a_Packet->m_PacketID) - { - case E_CREATIVE_INVENTORY_ACTION: - { - cPacket_CreativeInventoryAction * cia = reinterpret_cast(a_Packet); - HandleCreativeInventory(cia->m_SlotNum, cia->m_ClickedItem); - break; - } - case E_PLAYERPOS: - { - cPacket_PlayerPosition * pp = reinterpret_cast(a_Packet); - HandlePlayerPos(pp->m_PosX, pp->m_PosY, pp->m_PosZ, pp->m_Stance, pp->m_IsOnGround); - break; - } - case E_BLOCK_DIG: - { - cPacket_BlockDig * bd = reinterpret_cast(a_Packet); - HandleBlockDig(bd->m_PosX, bd->m_PosY, bd->m_PosZ, bd->m_Direction, bd->m_Status); - break; - } - case E_BLOCK_PLACE: - { - cPacket_BlockPlace * bp = reinterpret_cast(a_Packet); - HandleBlockPlace(bp->m_PosX, bp->m_PosY, bp->m_PosZ, bp->m_Direction, bp->m_HeldItem); - break; - } - case E_CHAT: - { - cPacket_Chat * ch = reinterpret_cast(a_Packet); - HandleChat(ch->m_Message); - break; - } - case E_PLAYERLOOK: - { - cPacket_PlayerLook * pl = reinterpret_cast(a_Packet); - HandlePlayerLook(pl->m_Rotation, pl->m_Pitch, pl->m_IsOnGround); - break; - } - case E_PLAYERMOVELOOK: - { - cPacket_PlayerMoveLook * pml = reinterpret_cast(a_Packet); - HandlePlayerMoveLook(pml->m_PosX, pml->m_PosY, pml->m_PosZ, pml->m_Stance, pml->m_Rotation, pml->m_Pitch, pml->m_IsOnGround); - break; - } - case E_ANIMATION: - { - cPacket_ArmAnim * aa = reinterpret_cast(a_Packet); - HandleAnimation(aa->m_Animation); - break; - } - case E_SLOT_SELECTED: - { - cPacket_ItemSwitch * isw = reinterpret_cast(a_Packet); - HandleSlotSelected(isw->m_SlotNum); - break; - } - case E_WINDOW_CLOSE: - { - cPacket_WindowClose * wc = reinterpret_cast(a_Packet); - HandleWindowClose(wc->m_WindowID); - break; - } - case E_WINDOW_CLICK: - { - cPacket_WindowClick * wc = reinterpret_cast(a_Packet); - HandleWindowClick(wc->m_WindowID, wc->m_SlotNum, wc->m_IsRightClick, wc->m_IsShiftPressed, wc->m_HeldItem); - break; - } - case E_UPDATE_SIGN: - { - cPacket_UpdateSign * us = reinterpret_cast(a_Packet); - HandleUpdateSign(us->m_BlockX, us->m_BlockY, us->m_BlockZ, us->m_Line1, us->m_Line2, us->m_Line3, us->m_Line4); - break; - } - case E_USE_ENTITY: - { - cPacket_UseEntity * ue = reinterpret_cast(a_Packet); - HandleUseEntity(ue->m_TargetEntityID, ue->m_IsLeftClick); - break; - } - case E_RESPAWN: - { - HandleRespawn(); - break; - } - case E_DISCONNECT: - { - cPacket_Disconnect * dc = reinterpret_cast(a_Packet); - HandleDisconnect(dc->m_Reason); - break; - } - case E_KEEP_ALIVE: - { - cPacket_KeepAlive * ka = reinterpret_cast(a_Packet); - HandleKeepAlive(ka->m_KeepAliveID); - break; - } - } // switch (Packet type) - break; - } // case csPlaying - } // switch (m_State) -} - - - - - void cClientHandle::HandlePing(void) { // Somebody tries to retrieve information about the server @@ -763,11 +443,10 @@ void cClientHandle::HandleHandshake(const AString & a_Username) Kick("The server is currently full :(-- Try again later"); return; } - cPacket_Chat Connecting(m_Username + " is connecting."); - cRoot::Get()->GetServer()->Broadcast(Connecting, this); + cRoot::Get()->GetServer()->BroadcastChat(m_Username + " is connecting.", this); SendHandshake(cRoot::Get()->GetServer()->GetServerID()); - LOG("User \"%s\" was sent a handshake", m_Username.c_str()); + LOGD("User \"%s\" was sent a handshake", m_Username.c_str()); } @@ -1148,6 +827,11 @@ void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_ return; } */ + if (m_State != csPlaying) + { + // Ignore this packet unles the player is fully in: + return; + } m_Player->MoveTo(Vector3d(a_PosX, a_PosY, a_PosZ)); m_Player->SetStance (a_Stance); @@ -1297,6 +981,25 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID) +void cClientHandle::SendData(const char * a_Data, int a_Size) +{ + { + cCSLock Lock(m_CSOutgoingData); + if (!m_OutgoingData.Write(a_Data, a_Size)) + { + // Client has too much outgoing data queued, drop them silently: + Destroy(); + } + } + + // Notify SocketThreads that we have something to write: + cRoot::Get()->GetServer()->NotifyClientWrite(this); +} + + + + + bool cClientHandle::CheckBlockInteractionsRate(void) { ASSERT(m_Player != NULL); @@ -1345,9 +1048,8 @@ void cClientHandle::Tick(float a_Dt) if (m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime()) { m_PingID++; - cPacket_KeepAlive Ping(m_PingID); m_PingStartTime = t1.GetNowTime(); - Send(Ping); + m_Protocol->SendKeepAlive(m_PingID); m_LastPingTime = m_PingStartTime; } } @@ -1356,155 +1058,10 @@ void cClientHandle::Tick(float a_Dt) -void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* = E_PRIORITY_NORMAL */) -{ - if (m_bKicking) return; // Don't add more packets if player is getting kicked anyway - - // If it is the packet spawning myself for myself, drop it silently: - if (a_Packet.m_PacketID == E_NAMED_ENTITY_SPAWN) - { - if (((cPacket_NamedEntitySpawn &)a_Packet).m_UniqueID == m_Player->GetUniqueID()) - { - return; - } - } - - // Filter out packets that don't belong to a csDownloadingWorld state: - if (m_State == csDownloadingWorld) - { - switch (a_Packet.m_PacketID) - { - case E_PLAYERMOVELOOK: - case E_KEEP_ALIVE: - case E_PRE_CHUNK: - case E_MAP_CHUNK: - { - // Allow - break; - } - default: return; - } - } - - // Filter out map chunks that the client doesn't want anymore: - if (a_Packet.m_PacketID == E_MAP_CHUNK) - { - // Check chunks being sent, erase them from m_ChunksToSend: - int ChunkX = ((cPacket_MapChunk &)a_Packet).m_PosX; - int ChunkZ = ((cPacket_MapChunk &)a_Packet).m_PosZ; - bool Found = false; - cCSLock Lock(m_CSChunkLists); - for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end(); ++itr) - { - if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) - { - m_ChunksToSend.erase(itr); - - // TODO: _X: Decouple this from packet sending, it creates a deadlock possibility - // -- postpone till Tick() instead, using a bool flag - CheckIfWorldDownloaded(); - - Found = true; - break; - } - } // for itr - m_ChunksToSend[] - if (!Found) - { - // This just sometimes happens. If you have a reliably replicatable situation for this, go ahead and fix it - // It's not a big issue anyway, just means that some chunks may be compressed several times - // LOGD("Refusing to send chunk [%d, %d] to client \"%s\" at [%d, %d].", ChunkX, ChunkZ, m_Username.c_str(), m_Player->GetChunkX(), m_Player->GetChunkZ()); - return; - } - } - - // Filter out pre chunks that the client doesn't want anymore: - if ((a_Packet.m_PacketID == E_PRE_CHUNK) && ((cPacket_PreChunk &)a_Packet).m_bLoad) - { - int ChunkX = ((cPacket_PreChunk &)a_Packet).m_PosX; - int ChunkZ = ((cPacket_PreChunk &)a_Packet).m_PosZ; - bool Found = false; - cCSLock Lock(m_CSChunkLists); - for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end(); ++itr) - { - if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) - { - Found = true; - break; - } - } // for itr - m_ChunksToSend[] - if (!Found) - { - // This just sometimes happens. If you have a reliably replicatable situation for this, go ahead and fix it - // It's not a big issue anyway, just means that some chunks may be compressed several times - // LOGD("Refusing to send PREchunk [%d, %d] to client \"%s\" at [%d, %d].", ChunkX, ChunkZ, m_Username.c_str(), m_Player->GetChunkX(), m_Player->GetChunkZ()); - return; - } - } - - // Optimize away multiple queued RelativeEntityMoveLook packets: - static int NumRelEntMoveLookTotal = 0; - static int NumRelEntMoveLookRemoved = 0; - cCSLock Lock(m_CSPackets); - if (a_Priority == E_PRIORITY_NORMAL) - { - if (a_Packet.m_PacketID == E_REL_ENT_MOVE_LOOK) - { - NumRelEntMoveLookTotal++; - PacketList & Packets = m_PendingNrmSendPackets; - const cPacket_RelativeEntityMoveLook & ThisPacketData = reinterpret_cast< const cPacket_RelativeEntityMoveLook &>(a_Packet); - for (PacketList::iterator itr = Packets.begin(); itr != Packets.end(); ++itr) - { - bool bBreak = false; - switch ((*itr)->m_PacketID) - { - case E_REL_ENT_MOVE_LOOK: - { - cPacket_RelativeEntityMoveLook * PacketData = reinterpret_cast< cPacket_RelativeEntityMoveLook *>(*itr); - if (ThisPacketData.m_UniqueID == PacketData->m_UniqueID) - { - Packets.erase(itr); - bBreak = true; - delete PacketData; - NumRelEntMoveLookRemoved++; - break; - } - break; - } // case E_REL_END_MOVE_LOOK - } // switch (*itr -> Packet type) - if (bBreak) - { - break; - } - } // for itr - Packets[] - if ((NumRelEntMoveLookTotal % 1000) == 10) // print out a debug statistics every 1000 packets sent - { - LOGD("RelEntMoveLook optimization: removed %d out of %d packets, saved %d bytes (%d KiB) of bandwidth", - NumRelEntMoveLookRemoved, NumRelEntMoveLookTotal, - NumRelEntMoveLookRemoved * sizeof(cPacket_RelativeEntityMoveLook), - NumRelEntMoveLookRemoved * sizeof(cPacket_RelativeEntityMoveLook) / 1024 - ); - } - } // if (E_REL_ENT_MOVE_LOOK - m_PendingNrmSendPackets.push_back(a_Packet.Clone()); - } - else if (a_Priority == E_PRIORITY_LOW) - { - m_PendingLowSendPackets.push_back(a_Packet.Clone()); - } - Lock.Unlock(); - - // Notify SocketThreads that we have something to write: - cRoot::Get()->GetServer()->NotifyClientWrite(this); -} - - - - - void cClientHandle::SendDisconnect(const AString & a_Reason) { - cPacket_Disconnect DC(a_Reason); - Send(DC); // TODO: Send it immediately to the socket, bypassing any packet buffers (? is it safe? packet boundaries...) + LOGD("Sending a DC"); + m_Protocol->SendDisconnect(a_Reason); } @@ -1513,9 +1070,7 @@ void cClientHandle::SendDisconnect(const AString & a_Reason) void cClientHandle::SendHandshake(const AString & a_ServerName) { - cPacket_Handshake Handshake; - Handshake.m_Username = a_ServerName; - Send(Handshake); + m_Protocol->SendHandshake(a_ServerName); } @@ -1524,13 +1079,7 @@ void cClientHandle::SendHandshake(const AString & a_ServerName) void cClientHandle::SendInventorySlot(int a_WindowID, short a_SlotNum, const cItem & a_Item) { - cPacket_InventorySlot Packet; - Packet.m_WindowID = (char)a_WindowID; - Packet.m_SlotNum = a_SlotNum; - Packet.m_ItemID = (short)(a_Item.m_ItemID); - Packet.m_ItemCount = a_Item.m_ItemCount; - Packet.m_ItemUses = a_Item.m_ItemHealth; - Send(Packet); + m_Protocol->SendInventorySlot(a_WindowID, a_SlotNum, a_Item); } @@ -1539,8 +1088,7 @@ void cClientHandle::SendInventorySlot(int a_WindowID, short a_SlotNum, const cIt void cClientHandle::SendChat(const AString & a_Message) { - cPacket_Chat Chat(a_Message); - Send(Chat); + m_Protocol->SendChat(a_Message); } @@ -1549,10 +1097,7 @@ void cClientHandle::SendChat(const AString & a_Message) void cClientHandle::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation) { - cPacket_ArmAnim Anim; - Anim.m_EntityID = a_Player.GetUniqueID(); - Anim.m_Animation = a_Animation; - Send(Anim); + m_Protocol->SendPlayerAnimation(a_Player, a_Animation); } @@ -1561,12 +1106,7 @@ void cClientHandle::SendPlayerAnimation(const cPlayer & a_Player, char a_Animati void cClientHandle::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) { - cPacket_EntityEquipment ee; - ee.m_UniqueID = a_Entity.GetUniqueID(); - ee.m_SlotNum = a_SlotNum; - ee.m_ItemType = a_Item.m_ItemType; - ee.m_ItemDamage = a_Item.m_ItemDamage; - Send(ee); + m_Protocol->SendEntityEquipment(a_Entity, a_SlotNum, a_Item); } @@ -1575,12 +1115,7 @@ void cClientHandle::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNu void cClientHandle::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) { - cPacket_WindowOpen WindowOpen; - WindowOpen.m_WindowID = a_WindowID; - WindowOpen.m_InventoryType = a_WindowType; - WindowOpen.m_WindowTitle = a_WindowTitle; - WindowOpen.m_NumSlots = a_NumSlots; - Send(WindowOpen); + m_Protocol->SendWindowOpen(a_WindowID, a_WindowType, a_WindowTitle, a_NumSlots); } @@ -1589,9 +1124,7 @@ void cClientHandle::SendWindowOpen(char a_WindowID, char a_WindowType, const ASt void cClientHandle::SendWindowClose(char a_WindowID) { - cPacket_WindowClose wc; - wc.m_WindowID = a_WindowID; - Send(wc); + m_Protocol->SendWindowClose(a_WindowID); } @@ -1600,8 +1133,7 @@ void cClientHandle::SendWindowClose(char a_WindowID) void cClientHandle::SendWholeInventory(const cInventory & a_Inventory) { - cPacket_WholeInventory wi(a_Inventory); - Send(wi); + m_Protocol->SendWholeInventory(a_Inventory); } @@ -1610,8 +1142,7 @@ void cClientHandle::SendWholeInventory(const cInventory & a_Inventory) void cClientHandle::SendWholeInventory(const cWindow & a_Window) { - cPacket_WholeInventory wi(a_Window); - Send(wi); + m_Protocol->SendWholeInventory(a_Window); } @@ -1620,18 +1151,16 @@ void cClientHandle::SendWholeInventory(const cWindow & a_Window) void cClientHandle::SendTeleportEntity(const cEntity & a_Entity) { - cPacket_TeleportEntity te(a_Entity); - Send(te); + m_Protocol->SendTeleportEntity(a_Entity); } -void cClientHandle::SendPlayerListItem(const cPlayer & a_Player) +void cClientHandle::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) { - cPacket_PlayerListItem pli(a_Player.GetColor() + a_Player.GetName(), true, a_Player.GetClientHandle()->GetPing()); - Send(pli); + m_Protocol->SendPlayerListItem(a_Player, a_IsOnline); } @@ -1640,8 +1169,7 @@ void cClientHandle::SendPlayerListItem(const cPlayer & a_Player) void cClientHandle::SendPlayerPosition(void) { - cPacket_PlayerPosition pp(m_Player); - Send(pp); + m_Protocol->SendPlayerPosition(); } @@ -1652,14 +1180,7 @@ void cClientHandle::SendRelEntMoveLook(const cEntity & a_Entity, char a_RelX, ch { ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self - cPacket_RelativeEntityMoveLook reml; - reml.m_UniqueID = a_Entity.GetUniqueID(); - reml.m_MoveX = a_RelX; - reml.m_MoveY = a_RelY; - reml.m_MoveZ = a_RelZ; - reml.m_Yaw = (char)((a_Entity.GetRotation() / 360.f) * 256); - reml.m_Pitch = (char)((a_Entity.GetPitch() / 360.f) * 256); - Send(reml); + m_Protocol->SendRelEntMoveLook(a_Entity, a_RelX, a_RelY, a_RelZ); } @@ -1670,12 +1191,7 @@ void cClientHandle::SendRelEntMove(const cEntity & a_Entity, char a_RelX, char a { ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self - cPacket_RelativeEntityMove rem; - rem.m_UniqueID = a_Entity.GetUniqueID(); - rem.m_MoveX = a_RelX; - rem.m_MoveY = a_RelY; - rem.m_MoveZ = a_RelZ; - Send(rem); + m_Protocol->SendRelEntMove(a_Entity, a_RelX, a_RelY, a_RelZ); } @@ -1686,11 +1202,7 @@ void cClientHandle::SendEntLook(const cEntity & a_Entity) { ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self - cPacket_EntityLook el; - el.m_UniqueID = a_Entity.GetUniqueID(); - el.m_Rotation = (char)((a_Entity.GetRotation() / 360.f) * 256); - el.m_Pitch = (char)((a_Entity.GetPitch() / 360.f) * 256); - Send(el); + m_Protocol->SendEntLook(a_Entity); } @@ -1701,8 +1213,7 @@ void cClientHandle::SendEntHeadLook(const cEntity & a_Entity) { ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self - cPacket_EntityHeadLook ehl(a_Entity); - Send(ehl); + m_Protocol->SendEntHeadLook(a_Entity); } @@ -1711,13 +1222,7 @@ void cClientHandle::SendEntHeadLook(const cEntity & a_Entity) void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) { - cPacket_BlockAction ba; - ba.m_BlockX = a_BlockX; - ba.m_BlockY = (short)a_BlockY; - ba.m_BlockZ = a_BlockZ; - ba.m_Byte1 = a_Byte1; - ba.m_Byte2 = a_Byte2; - Send(ba); + m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2); } @@ -1726,11 +1231,7 @@ void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, ch void cClientHandle::SendHealth(void) { - cPacket_UpdateHealth Health; - Health.m_Health = m_Player->GetHealth(); - Health.m_Food = m_Player->GetFoodLevel(); - Health.m_Saturation = m_Player->GetFoodSaturationLevel(); - Send(Health); + m_Protocol->SendHealth(); } @@ -1739,21 +1240,16 @@ void cClientHandle::SendHealth(void) void cClientHandle::SendRespawn(void) { - cPacket_Respawn Packet; - Packet.m_CreativeMode = (char)m_Player->GetGameMode(); // Set GameMode packet based on Player's GameMode; - Send(Packet); + m_Protocol->SendRespawn(); } -void cClientHandle::SendGameMode(char a_GameMode) +void cClientHandle::SendGameMode(eGameMode a_GameMode) { - cPacket_NewInvalidState nis; - nis.m_Reason = 3; - nis.m_GameMode = a_GameMode; - Send(nis); + m_Protocol->SendGameMode(a_GameMode); } @@ -1762,9 +1258,7 @@ void cClientHandle::SendGameMode(char a_GameMode) void cClientHandle::SendDestroyEntity(const cEntity & a_Entity) { - cPacket_DestroyEntity de; - de.m_UniqueID = a_Entity.GetUniqueID(); - Send(de); + m_Protocol->SendDestroyEntity(a_Entity); } @@ -1773,13 +1267,12 @@ void cClientHandle::SendDestroyEntity(const cEntity & a_Entity) void cClientHandle::SendPlayerMoveLook(void) { - cPacket_PlayerMoveLook pml(*m_Player); /* 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 ); */ - Send(pml); + m_Protocol->SendPlayerMoveLook(); } @@ -1788,10 +1281,7 @@ void cClientHandle::SendPlayerMoveLook(void) void cClientHandle::SendEntityStatus(const cEntity & a_Entity, char a_Status) { - cPacket_EntityStatus es; - es.m_Status = a_Status; - es.m_UniqueID = a_Entity.GetUniqueID(); - Send(es); + m_Protocol->SendEntityStatus(a_Entity, a_Status); } @@ -1800,8 +1290,7 @@ void cClientHandle::SendEntityStatus(const cEntity & a_Entity, char a_Status) void cClientHandle::SendMetadata(const cPawn & a_Pawn) { - cPacket_Metadata md(a_Pawn.GetMetaData(), a_Pawn.GetUniqueID()); - Send(md); + m_Protocol->SendMetadata(a_Pawn); } @@ -1810,12 +1299,7 @@ void cClientHandle::SendMetadata(const cPawn & a_Pawn) void cClientHandle::SendInventoryProgress(char a_WindowID, short a_ProgressBar, short a_Value) { - cPacket_InventoryProgressBar Progress; - Progress.m_WindowID = a_WindowID; - Progress.m_ProgressBar = a_ProgressBar; - Progress.m_Value = a_Value; - Progress.m_WindowID = a_WindowID; - Send(Progress); + m_Protocol->SendInventoryProgress(a_WindowID, a_ProgressBar, a_Value); } @@ -1824,17 +1308,13 @@ void cClientHandle::SendInventoryProgress(char a_WindowID, short a_ProgressBar, void cClientHandle::SendPlayerSpawn(const cPlayer & a_Player) { - cPacket_NamedEntitySpawn SpawnPacket; - SpawnPacket.m_UniqueID = a_Player.GetUniqueID(); - SpawnPacket.m_PlayerName = a_Player.GetName(); - SpawnPacket.m_PosX = (int)(a_Player.GetPosX() * 32); - SpawnPacket.m_PosY = (int)(a_Player.GetPosY() * 32); - SpawnPacket.m_PosZ = (int)(a_Player.GetPosZ() * 32); - SpawnPacket.m_Rotation = (char)((a_Player.GetRot().x / 360.f) * 256); - SpawnPacket.m_Pitch = (char)((a_Player.GetRot().y / 360.f) * 256); - const cItem & HeldItem = a_Player.GetEquippedItem(); - SpawnPacket.m_CurrentItem = HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType; // Unlike -1 in inventory, the named entity packet uses 0 for "empty" - Send(SpawnPacket); + if (a_Player.GetUniqueID() == m_Player->GetUniqueID()) + { + // Do NOT send this packet to myself + return; + } + + m_Protocol->SendPlayerSpawn(a_Player); } @@ -1843,18 +1323,7 @@ void cClientHandle::SendPlayerSpawn(const cPlayer & a_Player) void cClientHandle::SendPickupSpawn(const cPickup & a_Pickup) { - cPacket_PickupSpawn PickupSpawn; - PickupSpawn.m_UniqueID = a_Pickup.GetUniqueID(); - PickupSpawn.m_ItemType = a_Pickup.GetItem()->m_ItemType; - PickupSpawn.m_ItemCount = a_Pickup.GetItem()->m_ItemCount; - PickupSpawn.m_ItemDamage = a_Pickup.GetItem()->m_ItemHealth; - PickupSpawn.m_PosX = (int) (a_Pickup.GetPosX() * 32); - PickupSpawn.m_PosY = (int) (a_Pickup.GetPosY() * 32); - PickupSpawn.m_PosZ = (int) (a_Pickup.GetPosZ() * 32); - PickupSpawn.m_Rotation = (char)(a_Pickup.GetSpeed().x * 8); - PickupSpawn.m_Pitch = (char)(a_Pickup.GetSpeed().y * 8); - PickupSpawn.m_Roll = (char)(a_Pickup.GetSpeed().z * 8); - Send(PickupSpawn); + m_Protocol->SendPickupSpawn(a_Pickup); } @@ -1863,16 +1332,7 @@ void cClientHandle::SendPickupSpawn(const cPickup & a_Pickup) void cClientHandle::SendSpawnMob(const cMonster & a_Mob) { - cPacket_SpawnMob Spawn; - Spawn.m_UniqueID = a_Mob.GetUniqueID(); - Spawn.m_Type = a_Mob.GetMobType(); - Spawn.m_Pos = ((Vector3i)(a_Mob.GetPosition())) * 32; - Spawn.m_Yaw = 0; - Spawn.m_Pitch = 0; - Spawn.m_MetaDataSize = 1; - Spawn.m_MetaData = new char[Spawn.m_MetaDataSize]; - Spawn.m_MetaData[0] = 0x7f; // not on fire/crouching/riding - Send(Spawn); + m_Protocol->SendSpawnMob(a_Mob); } @@ -1884,15 +1344,10 @@ void cClientHandle::SendUpdateSign( const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4 ) { - cPacket_UpdateSign us; - us.m_BlockX = a_BlockX; - us.m_BlockY = a_BlockY; - us.m_BlockZ = a_BlockZ; - us.m_Line1 = a_Line1; - us.m_Line2 = a_Line2; - us.m_Line3 = a_Line3; - us.m_Line4 = a_Line4; - Send(us); + m_Protocol->SendUpdateSign( + a_BlockX, a_BlockY, a_BlockZ, + a_Line1, a_Line2, a_Line3, a_Line4 + ); } @@ -1901,10 +1356,7 @@ void cClientHandle::SendUpdateSign( void cClientHandle::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) { - cPacket_CollectItem ci; - ci.m_CollectedID = a_Pickup.GetUniqueID(); - ci.m_CollectorID = a_Player.GetUniqueID(); - Send(ci); + m_Protocol->SendCollectPickup(a_Pickup, a_Player); } @@ -1913,13 +1365,7 @@ void cClientHandle::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & void cClientHandle::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - cPacket_BlockChange BlockChange; - BlockChange.m_PosX = a_BlockX; - BlockChange.m_PosY = (unsigned char)a_BlockY; - BlockChange.m_PosZ = a_BlockZ; - BlockChange.m_BlockType = a_BlockType; - BlockChange.m_BlockMeta = a_BlockMeta; - Send(BlockChange); + m_Protocol->SendBlockChange(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); } @@ -1928,27 +1374,7 @@ void cClientHandle::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BL void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) { - 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::Height + blk.z, blk.BlockType, blk.BlockMeta); - return; - } - - cPacket_MultiBlock MultiBlock; - MultiBlock.m_ChunkX = a_ChunkX; - MultiBlock.m_ChunkZ = a_ChunkZ; - MultiBlock.m_NumBlocks = (short)a_Changes.size(); - MultiBlock.m_Data = new cPacket_MultiBlock::sBlockChange[a_Changes.size()]; - int i = 0; - for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr, i++) - { - unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12); - unsigned int Blocks = itr->BlockMeta | (itr->BlockType << 4); - MultiBlock.m_Data[i].Data = Coords << 16 | Blocks; - } - Send(MultiBlock); + m_Protocol->SendBlockChanges(a_ChunkX, a_ChunkZ, a_Changes); } @@ -1957,11 +1383,7 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) { - cPacket_PreChunk UnloadPacket; - UnloadPacket.m_PosX = a_ChunkX; - UnloadPacket.m_PosZ = a_ChunkZ; - UnloadPacket.m_bLoad = false; // Unload - Send(UnloadPacket); + m_Protocol->SendUnloadChunk(a_ChunkX, a_ChunkZ); } @@ -1970,32 +1392,7 @@ void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) void cClientHandle::SendWeather(eWeather a_Weather) { - switch( a_Weather ) - { - case eWeather_Sunny: - { - cPacket_NewInvalidState WeatherPacket; - WeatherPacket.m_Reason = 2; // stop rain - Send(WeatherPacket); - break; - } - - case eWeather_Rain: - { - cPacket_NewInvalidState WeatherPacket; - WeatherPacket.m_Reason = 1; // begin rain - Send(WeatherPacket); - break; - } - - case eWeather_ThunderStorm: - { - cPacket_NewInvalidState WeatherPacket; - WeatherPacket.m_Reason = 1; // begin rain - Send(WeatherPacket); - break; - } - } + m_Protocol->SendWeather(a_Weather); } @@ -2004,9 +1401,7 @@ void cClientHandle::SendWeather(eWeather a_Weather) void cClientHandle::SendTimeUpdate(Int64 a_WorldTime) { - cPacket_TimeUpdate tu; - tu.m_Time = a_WorldTime; - Send(tu); + m_Protocol->SendTimeUpdate(a_WorldTime); } @@ -2015,11 +1410,7 @@ void cClientHandle::SendTimeUpdate(Int64 a_WorldTime) void cClientHandle::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) { - cPacket_Thunderbolt ThunderboltPacket; - ThunderboltPacket.m_xLBPos = a_BlockX; - ThunderboltPacket.m_yLBPos = a_BlockY; - ThunderboltPacket.m_zLBPos = a_BlockZ; - Send(ThunderboltPacket); + m_Protocol->SendThunderbolt(a_BlockX, a_BlockY, a_BlockZ); } @@ -2028,13 +1419,32 @@ void cClientHandle::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { - // Send the pre-chunk: - cPacket_PreChunk pre(a_ChunkX, a_ChunkZ, true); - Send(pre); + // Check chunks being sent, erase them from m_ChunksToSend: + bool Found = false; + cCSLock Lock(m_CSChunkLists); + for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end(); ++itr) + { + if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ)) + { + m_ChunksToSend.erase(itr); + + // TODO: _X: Decouple this from packet sending, it creates a deadlock possibility + // -- postpone till Tick() instead, using a bool flag + CheckIfWorldDownloaded(); + + Found = true; + break; + } + } // for itr - m_ChunksToSend[] + if (!Found) + { + // This just sometimes happens. If you have a reliably replicatable situation for this, go ahead and fix it + // It's not a big issue anyway, just means that some chunks may be compressed several times + // LOGD("Refusing to send chunk [%d, %d] to client \"%s\" at [%d, %d].", ChunkX, ChunkZ, m_Username.c_str(), m_Player->GetChunkX(), m_Player->GetChunkZ()); + return; + } - // Send the data: - cPacket_MapChunk mc(a_ChunkX, a_ChunkZ, a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_2_5)); - Send(mc); + m_Protocol->SendChunkData(a_ChunkX, a_ChunkZ, a_Serializer); } @@ -2075,8 +1485,7 @@ void cClientHandle::SendConfirmPosition(void) if (!cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::HOOK_PLAYER_JOIN, 1, m_Player)) { // Broadcast that this player has joined the game! Yay~ - cPacket_Chat Joined(m_Username + " joined the game!"); - cRoot::Get()->GetServer()->Broadcast(Joined, this); + cRoot::Get()->GetServer()->BroadcastChat(m_Username + " joined the game!", this); } m_ConfirmPosition = m_Player->GetPosition(); @@ -2140,194 +1549,68 @@ void cClientHandle::AddWantedChunk(int a_ChunkX, int a_ChunkZ) -void cClientHandle::DataReceived(const char * a_Data, int a_Size) +void cClientHandle::PacketBufferFull(void) { - // Data is received from the client - - if (!m_ReceivedData.Write(a_Data, a_Size)) - { - // Too much data in the incoming queue, the server is probably too busy, kick the client: - LOGERROR("Too much data in queue for client \"%s\" @ %s, kicking them.", m_Username.c_str(), m_Socket.GetIPString().c_str()); - SendDisconnect("Server busy"); - // TODO: QueueDestroy(); - cSleep::MilliSleep(1000); // Give packet some time to be received - Destroy(); - return; - } + // Too much data in the incoming queue, the server is probably too busy, kick the client: + LOGERROR("Too much data in queue for client \"%s\" @ %s, kicking them.", m_Username.c_str(), m_Socket.GetIPString().c_str()); + SendDisconnect("Server busy"); + // TODO: QueueDestroy(); + cSleep::MilliSleep(1000); // Give packet some time to be received + Destroy(); +} - // Parse and handle all complete packets in m_ReceivedData: - while (m_ReceivedData.CanReadBytes(1)) - { - unsigned char PacketType; - m_ReceivedData.ReadByte(PacketType); - cPacket* pPacket = m_PacketMap[PacketType]; - if (pPacket == NULL) - { - LOGERROR("Unknown packet type 0x%02x from client \"%s\" @ %s", PacketType, m_Username.c_str(), m_Socket.GetIPString().c_str()); - AString Reason; - Printf(Reason, "[C->S] Unknown PacketID: 0x%02x", PacketType); - SendDisconnect(Reason); - // TODO: QueueDestroy(); - cSleep::MilliSleep(1000); // Give packet some time to be received - Destroy(); - return; - } - - int NumBytes = pPacket->Parse(m_ReceivedData); - if (NumBytes == PACKET_ERROR) - { - LOGERROR("Protocol error while parsing packet type 0x%02x; disconnecting client \"%s\"", PacketType, m_Username.c_str()); - SendDisconnect("Protocol error"); - // TODO: QueueDestroy(); - cSleep::MilliSleep(1000); // Give packet some time to be received - Destroy(); - return; - } - else if (NumBytes == PACKET_INCOMPLETE) - { - // Not a complete packet - m_ReceivedData.ResetRead(); - break; - } - else - { - // Packet parsed successfully, add it to internal queue: - HandlePacket(pPacket); - // Erase the packet from the buffer: - m_ReceivedData.CommitRead(); - } - } // while (!Received.CanReadBytes(1)) + + + +void cClientHandle::PacketUnknown(unsigned char a_PacketType) +{ + LOGERROR("Unknown packet type 0x%02x from client \"%s\" @ %s", a_PacketType, m_Username.c_str(), m_Socket.GetIPString().c_str()); + + AString Reason; + Printf(Reason, "[C->S] Unknown PacketID: 0x%02x", a_PacketType); + SendDisconnect(Reason); + // TODO: QueueDestroy(); + cSleep::MilliSleep(1000); // Give packet some time to be received + Destroy(); } -void cClientHandle::GetOutgoingData(AString & a_Data) +void cClientHandle::PacketError(unsigned char a_PacketType) { - // Data can be sent to client - - cCSLock Lock(m_CSPackets); - if (m_PendingNrmSendPackets.size() + m_PendingLowSendPackets.size() > MAX_OUTGOING_PACKETS) - { - LOGERROR("ERROR: Too many packets in queue for player %s !!", m_Username.c_str()); - SendDisconnect("Too many packets in queue."); - - // DEBUG: Dump all outstanding packets' types to the log: - int Idx = 0; - int ChunkX = m_Player->GetChunkX(); - int ChunkZ = m_Player->GetChunkZ(); - for (PacketList::const_iterator itr = m_PendingNrmSendPackets.begin(); itr != m_PendingNrmSendPackets.end(); ++itr) - { - switch ((*itr)->m_PacketID) - { - case E_MAP_CHUNK: - { - int x = ((cPacket_MapChunk *)(*itr))->m_PosX; - int z = ((cPacket_MapChunk *)(*itr))->m_PosZ; - bool IsWanted = (abs(x - ChunkX) <= m_ViewDistance) && (abs(z - ChunkZ) <= m_ViewDistance); - LOG("Packet %4d: type %2x (MapChunk: %d, %d, %s)", - Idx++, (*itr)->m_PacketID, - x, z, - IsWanted ? "wanted" : "unwanted" - ); - break; - } - - case E_PRE_CHUNK: - { - int x = ((cPacket_PreChunk *)(*itr))->m_PosX; - int z = ((cPacket_PreChunk *)(*itr))->m_PosZ; - bool IsWanted = (abs(x - ChunkX) <= m_ViewDistance) && (abs(z - ChunkZ) <= m_ViewDistance); - bool Loading = ((cPacket_PreChunk *)(*itr))->m_bLoad; - LOG("Packet %4d: type %2x (PreChunk: %d, %d, %s, %s)", - Idx++, (*itr)->m_PacketID, - x, z, - Loading ? "loading" : "unloading", - IsWanted ? "wanted" : "unwanted" - ); - break; - } - - case E_BLOCK_CHANGE: - { - int x = ((cPacket_BlockChange *)(*itr))->m_PosX; - int z = ((cPacket_BlockChange *)(*itr))->m_PosZ; - char ToBlock = ((cPacket_BlockChange *)(*itr))->m_BlockType; - int y, cx, cz; - cChunkDef::AbsoluteToRelative(x, y, z, cx, cz); - bool IsWanted = (abs(cx - ChunkX) <= m_ViewDistance) && (abs(cz - ChunkZ) <= m_ViewDistance); - LOG("Packet %4d: type %2x (BlockChange: [%d, %d], %s chunk; to block %d)", - Idx++, (*itr)->m_PacketID, - cx, cz, - IsWanted ? "wanted" : "unwanted", - ToBlock - ); - break; - } - - case E_MULTI_BLOCK: - { - int cx = ((cPacket_MultiBlock *)(*itr))->m_ChunkX; - int cz = ((cPacket_MultiBlock *)(*itr))->m_ChunkZ; - int NumBlocks = ((cPacket_MultiBlock *)(*itr))->m_NumBlocks; - bool IsWanted = (abs(cx - ChunkX) <= m_ViewDistance) && (abs(cz - ChunkZ) <= m_ViewDistance); - LOG("Packet %4d: type %2x (MultiBlock: [%d, %d], %s chunk, %d blocks)", - Idx++, (*itr)->m_PacketID, - cx, cz, - IsWanted ? "wanted" : "unwanted", - NumBlocks - ); - break; - } - - default: - { - LOG("Packet %4d: type %2x", Idx++, (*itr)->m_PacketID); - break; - } - } - } - - Lock.Unlock(); - Destroy(); - return; - } - - if ((m_PendingNrmSendPackets.size() == 0) && (m_PendingLowSendPackets.size() == 0)) - { - return; - } + LOGERROR("Protocol error while parsing packet type 0x%02x; disconnecting client \"%s\"", a_PacketType, m_Username.c_str()); + SendDisconnect("Protocol error"); + // TODO: QueueDestroy(); + cSleep::MilliSleep(1000); // Give packet some time to be received + Destroy(); +} - if (m_PendingNrmSendPackets.size() > MAX_OUTGOING_PACKETS / 2) - { - LOGINFO("Suspiciously many pending packets: %i; client \"%s\", LastType: 0x%02x", m_PendingNrmSendPackets.size(), m_Username.c_str(), (*m_PendingNrmSendPackets.rbegin())->m_PacketID); - } - AString Data; - Data.reserve(1100); - // Serialize normal-priority packets up to 1000 bytes - while (!m_PendingNrmSendPackets.empty() && (Data.size() < 1000)) - { - m_PendingNrmSendPackets.front()->Serialize(Data); - // LOGD("Sending packet 0x%02x", m_PendingNrmSendPackets.front()->m_PacketID); - delete m_PendingNrmSendPackets.front(); - m_PendingNrmSendPackets.erase(m_PendingNrmSendPackets.begin()); - } - // Serialize one low-priority packet: - if (!m_PendingLowSendPackets.empty() && Data.empty()) - { - m_PendingLowSendPackets.front()->Serialize(Data); - delete m_PendingLowSendPackets.front(); - m_PendingLowSendPackets.erase(m_PendingLowSendPackets.begin()); - } - Lock.Unlock(); - - a_Data.append(Data); + + + +void cClientHandle::DataReceived(const char * a_Data, int a_Size) +{ + // Data is received from the client, hand it off to the protocol: + m_Protocol->DataReceived(a_Data, a_Size); + m_TimeLastPacket = cWorld::GetTime(); +} + + + + + +void cClientHandle::GetOutgoingData(AString & a_Data) +{ + // Data can be sent to client + m_OutgoingData.ReadAll(a_Data); + m_OutgoingData.CommitRead(); // Disconnect player after all packets have been sent - if (m_bKicking && (m_PendingNrmSendPackets.size() + m_PendingLowSendPackets.size() == 0)) + if (m_bKicking && a_Data.empty()) { Destroy(); } diff --git a/source/cClientHandle.h b/source/cClientHandle.h index 1c7cfa75f..c2e5fa83c 100644 --- a/source/cClientHandle.h +++ b/source/cClientHandle.h @@ -12,7 +12,6 @@ #define CCLIENTHANDLE_H_INCLUDED #include "Defines.h" -#include "packets/cPacket.h" #include "Vector3d.h" #include "cSocketThreads.h" #include "ChunkDef.h" @@ -29,15 +28,15 @@ -class cPlayer; -class cRedstone; +class cChunkDataSerializer; class cInventory; -class cWindow; +class cMonster; class cPawn; class cPickup; -class cMonster; -class cChunkDataSerializer; - +class cPlayer; +class cProtocol; +class cRedstone; +class cWindow; @@ -83,8 +82,6 @@ public: bool IsPlaying(void) const {return (m_State == csPlaying); } - void Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority = E_PRIORITY_NORMAL); - void SendDisconnect(const AString & a_Reason); void SendHandshake (const AString & a_ServerName); void SendInventorySlot(int a_WindowID, short a_SlotNum, const cItem & a_Item); @@ -96,7 +93,7 @@ public: void SendWholeInventory(const cInventory & a_Inventory); void SendWholeInventory(const cWindow & a_Window); void SendTeleportEntity(const cEntity & a_Entity); - void SendPlayerListItem(const cPlayer & a_Player); + void SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline); void SendPlayerPosition(void); void SendRelEntMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ); void SendRelEntMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ); @@ -105,7 +102,7 @@ public: void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2); void SendHealth (void); void SendRespawn(void); - void SendGameMode(char a_GameMode); + void SendGameMode(eGameMode a_GameMode); void SendDestroyEntity(const cEntity & a_Entity); void SendPlayerMoveLook(void); void SendEntityStatus(const cEntity & a_Entity, char a_Status); @@ -138,7 +135,45 @@ public: /// Adds the chunk specified to the list of chunks wanted for sending (m_ChunksToSend) void AddWantedChunk(int a_ChunkX, int a_ChunkZ); + + // Calls that cProtocol descendants use to report state: + void PacketBufferFull(void); + void PacketUnknown(unsigned char a_PacketType); + void PacketError(unsigned char a_PacketType); + // Calls that cProtocol descendants use for handling packets: + // Packets handled in csConnected: + void HandlePing (void); + void HandleHandshake (const AString & a_Username); + void HandleLogin (int a_ProtocolVersion, const AString & a_Username); + void HandleUnexpectedPacket(int a_PacketType); // the default case -> kick + + // Packets handled while in csConfirmingPos: + void HandleMoveLookConfirm(double a_PosX, double a_PosY, double a_PosZ); // While !m_bPositionConfirmed + + // Packets handled while in csPlaying: + void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem); + void HandlePlayerPos (double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround); + void HandleBlockDig (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status); + void HandleBlockPlace (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, const cItem & a_HeldItem); + void HandleChat (const AString & a_Message); + void HandlePlayerLook (float a_Rotation, float a_Pitch, bool a_IsOnGround); + void HandlePlayerMoveLook (double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround); // While m_bPositionConfirmed (normal gameplay) + void HandleAnimation (char a_Animation); + void HandleSlotSelected (short a_SlotNum); + void HandleWindowClose (char a_WindowID); + void HandleWindowClick (char a_WindowID, short a_SlotNum, bool a_IsRightClick, bool a_IsShiftPressed, const cItem & a_HeldItem); + void HandleUpdateSign ( + 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 + ); + void HandleUseEntity (int a_TargetEntityID, bool a_IsLeftClick); + void HandleRespawn (void); + void HandleDisconnect (const AString & a_Reason); + void HandleKeepAlive (int a_KeepAliveID); + + void SendData(const char * a_Data, int a_Size); private: int m_ViewDistance; // Number of chunks the player can see in each direction; 4 is the minimum ( http://wiki.vg/Protocol_FAQ#.E2.80.A6all_connecting_clients_spasm_and_jerk_uncontrollably.21 ) @@ -148,25 +183,21 @@ private: int m_ProtocolVersion; AString m_Username; AString m_Password; - - cByteBuffer m_ReceivedData; // Accumulator for the data received from the socket, waiting to be parsed; accessed from the cSocketThreads' thread only! - - cCriticalSection m_CSPackets; - PacketList m_PendingNrmSendPackets; - PacketList m_PendingLowSendPackets; cCriticalSection m_CSChunkLists; cChunkCoordsList m_LoadedChunks; // Chunks that the player belongs to cChunkCoordsList m_ChunksToSend; // Chunks that need to be sent to the player (queued because they weren't generated yet or there's not enough time to send them) - cSocket m_Socket; + cSocket m_Socket; + cProtocol * m_Protocol; + + cCriticalSection m_CSOutgoingData; + cByteBuffer m_OutgoingData; cCriticalSection m_CriticalSection; Vector3d m_ConfirmPosition; - cPacket * m_PacketMap[256]; - bool m_bDestroyed; cPlayer * m_Player; bool m_bKicking; @@ -198,39 +229,6 @@ private: bool m_bKeepThreadGoing; - void HandlePacket(cPacket * a_Packet); - - // Packets handled in csConnected: - void HandlePing (void); - void HandleHandshake (const AString & a_Username); - void HandleLogin (int a_ProtocolVersion, const AString & a_Username); - void HandleUnexpectedPacket(int a_PacketType); // the default case -> kick - - // Packets handled while in csConfirmingPos: - void HandleMoveLookConfirm(double a_PosX, double a_PosY, double a_PosZ); // While !m_bPositionConfirmed - - // Packets handled while in csPlaying: - void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem); - void HandlePlayerPos (double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround); - void HandleBlockDig (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status); - void HandleBlockPlace (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, const cItem & a_HeldItem); - void HandleChat (const AString & a_Message); - void HandlePlayerLook (float a_Rotation, float a_Pitch, bool a_IsOnGround); - void HandlePlayerMoveLook (double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround); // While m_bPositionConfirmed (normal gameplay) - void HandleAnimation (char a_Animation); - void HandleSlotSelected (short a_SlotNum); - void HandleWindowClose (char a_WindowID); - void HandleWindowClick (char a_WindowID, short a_SlotNum, bool a_IsRightClick, bool a_IsShiftPressed, const cItem & a_HeldItem); - void HandleUpdateSign ( - 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 - ); - void HandleUseEntity (int a_TargetEntityID, bool a_IsLeftClick); - void HandleRespawn (void); - void HandleDisconnect (const AString & a_Reason); - void HandleKeepAlive (int a_KeepAliveID); - /* /// Handles rclk with a dye; returns true if the dye is to be be consumed bool HandleDyes(cPacket_BlockPlace * a_Packet); diff --git a/source/cServer.cpp b/source/cServer.cpp index 162512f24..330a69873 100644 --- a/source/cServer.cpp +++ b/source/cServer.cpp @@ -283,24 +283,6 @@ cServer::~cServer() -// TODO - Need to modify this or something, so it broadcasts to all worlds? And move this to cWorld? -void cServer::Broadcast(const cPacket & a_Packet, cClientHandle * a_Exclude) -{ - cCSLock Lock(m_CSClients); - for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr) - { - if ((*itr == a_Exclude) || !(*itr)->IsLoggedIn()) - { - continue; - } - (*itr)->Send(a_Packet); - } -} - - - - - void cServer::BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSClients); diff --git a/source/cServer.h b/source/cServer.h index e80d0927e..48a39db7d 100644 --- a/source/cServer.h +++ b/source/cServer.h @@ -38,7 +38,6 @@ public: //tolua_export bool IsConnected(){return m_bIsConnected;} // returns connection status void StartListenClient(); // Listen to client - void Broadcast(const cPacket & a_Packet, cClientHandle* a_Exclude = NULL); void BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude = NULL); bool Tick(float a_Dt); diff --git a/source/cSocketThreads.cpp b/source/cSocketThreads.cpp index 08ca4fcc7..e1fdd8f24 100644 --- a/source/cSocketThreads.cpp +++ b/source/cSocketThreads.cpp @@ -18,7 +18,6 @@ cSocketThreads::cSocketThreads(void) { - LOG("cSocketThreads startup"); } @@ -55,7 +54,7 @@ bool cSocketThreads::AddClient(cSocket * a_Socket, cCallback * a_Client) } // No thread has free space, create a new one: - LOG("Creating a new cSocketThread (currently have %d)", m_Threads.size()); + LOGD("Creating a new cSocketThread (currently have %d)", m_Threads.size()); cSocketThread * Thread = new cSocketThread(this); if (!Thread->Start()) { diff --git a/source/cSocketThreads.h b/source/cSocketThreads.h index c90a4ede3..4f4e4bbe6 100644 --- a/source/cSocketThreads.h +++ b/source/cSocketThreads.h @@ -19,7 +19,7 @@ This means that the socket can be written to several times before finally closin -/// How many clients should one thread handle? (must be less than FD_SETSIZE - 1 for your platform) +/// How many clients should one thread handle? (must be less than FD_SETSIZE for your platform) #define MAX_SLOTS 63 @@ -38,7 +38,7 @@ This means that the socket can be written to several times before finally closin // Check MAX_SLOTS: #if MAX_SLOTS >= FD_SETSIZE - #error "MAX_SLOTS must be less than FD_SETSIZE - 1 for your platform! (otherwise select() won't work)" + #error "MAX_SLOTS must be less than FD_SETSIZE for your platform! (otherwise select() won't work)" #endif diff --git a/source/cWindow.h b/source/cWindow.h index 36fc60f62..77dc608a4 100644 --- a/source/cWindow.h +++ b/source/cWindow.h @@ -92,8 +92,8 @@ private: void Destroy(); - int m_WindowID; - int m_WindowType; + char m_WindowID; + int m_WindowType; AString m_WindowTitle; cWindowOwner * m_Owner; diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 8eb4530a3..ee41a6aa1 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -1213,41 +1213,6 @@ const double & cWorld::GetSpawnY(void) -void cWorld::Broadcast( const cPacket & a_Packet, cClientHandle * a_Exclude) -{ - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) - { - cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) - { - continue; - } - ch->Send( a_Packet ); - } -} - - - - - -void cWorld::BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const cPacket & a_Packet, cClientHandle * a_Exclude) -{ - m_ChunkMap->BroadcastToChunk(a_ChunkX, a_ChunkY, a_ChunkZ, a_Packet, a_Exclude); -} - - - - - -void cWorld::BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude) -{ - m_ChunkMap->BroadcastToChunkOfBlock(a_X, a_Y, a_Z, a_Packet, a_Exclude); -} - - - - void cWorld::BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude) { @@ -1447,6 +1412,24 @@ void cWorld::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer +void cWorld::BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude) +{ + cCSLock Lock(m_CSPlayers); + for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + { + cClientHandle * ch = (*itr)->GetClientHandle(); + if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + { + continue; + } + ch->SendPlayerListItem(a_Player, a_IsOnline); + } +} + + + + + void cWorld::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude) { m_ChunkMap->BroadcastBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Exclude); @@ -1767,7 +1750,7 @@ void cWorld::SendPlayerList(cPlayer * a_DestPlayer) cClientHandle * ch = (*itr)->GetClientHandle(); if ((ch != NULL) && !ch->IsDestroyed()) { - a_DestPlayer->GetClientHandle()->SendPlayerListItem(*(*itr)); + a_DestPlayer->GetClientHandle()->SendPlayerListItem(*(*itr), true); } } } diff --git a/source/cWorld.h b/source/cWorld.h index f168ab182..688ce5857 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -25,7 +25,6 @@ -class cPacket; class cRedstone; class cFireSimulator; class cWaterSimulator; @@ -59,7 +58,7 @@ class cWorld //tolua_export { //tolua_export public: - OBSOLETE static cWorld* GetWorld(); + OBSOLETE static cWorld * GetWorld(); // Return time in seconds inline static float GetTime() //tolua_export @@ -74,10 +73,6 @@ public: int GetHeight( int a_X, int a_Z ); //tolua_export - void Broadcast(const cPacket & a_Packet, cClientHandle * a_Exclude = NULL); - void BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const cPacket & a_Packet, cClientHandle * a_Exclude = NULL); - void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL); - void BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude = NULL); void BroadcastPlayerAnimation(const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL); void BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL); @@ -96,6 +91,7 @@ public: void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL); void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); + void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL); /// If there is a block entity at the specified coods, sends it to all clients except a_Exclude void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); @@ -175,9 +171,6 @@ public: void AddEntity( cEntity* a_Entity ); - /// Add an entity to the chunk specified; broadcasts the a_SpawnPacket to all clients of that chunk - void AddEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ, cPacket * a_SpawnPacket); - /// Removes the entity from the chunk specified void RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); diff --git a/source/packets/cPacket.h b/source/packets/cPacket.h index 1d6e8506f..bc0f052e8 100644 --- a/source/packets/cPacket.h +++ b/source/packets/cPacket.h @@ -9,9 +9,12 @@ -#define PACKET_INCOMPLETE -2 -#define PACKET_ERROR -1 -#define PACKET_OK 1 +enum +{ + PACKET_INCOMPLETE = -2, + PACKET_ERROR = -1, + PACKET_OK = 1, +} ; diff --git a/source/packets/cPacket_13.h b/source/packets/cPacket_13.h index 24caf5cc0..c9f274b38 100644 --- a/source/packets/cPacket_13.h +++ b/source/packets/cPacket_13.h @@ -18,7 +18,7 @@ public: cPacket_13() : m_EntityID( 0 ) , m_ActionID( 0 ) - { m_PacketID = E_PACKET_13; } + { m_PacketID = E_PACKET_ENTITY_ACTION; } virtual cPacket* Clone() const { return new cPacket_13( *this ); } virtual int Parse(cByteBuffer & a_Buffer) override; diff --git a/source/packets/cPacket_Player.cpp b/source/packets/cPacket_Player.cpp index 2136d63e6..bcfcbfee6 100644 --- a/source/packets/cPacket_Player.cpp +++ b/source/packets/cPacket_Player.cpp @@ -202,15 +202,15 @@ void cPacket_PlayerMoveLook::Serialize(AString & a_Data) const /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cPacket_PlayerPosition: -cPacket_PlayerPosition::cPacket_PlayerPosition(cPlayer * a_Player) +cPacket_PlayerPosition::cPacket_PlayerPosition(const cPlayer & a_Player) { m_PacketID = E_PLAYERPOS; - m_PosX = a_Player->GetPosX(); - m_PosY = a_Player->GetPosY(); - m_PosZ = a_Player->GetPosZ(); - m_Stance = a_Player->GetStance(); - m_IsOnGround = a_Player->IsOnGround(); + m_PosX = a_Player.GetPosX(); + m_PosY = a_Player.GetPosY(); + m_PosZ = a_Player.GetPosZ(); + m_Stance = a_Player.GetStance(); + m_IsOnGround = a_Player.IsOnGround(); } diff --git a/source/packets/cPacket_Player.h b/source/packets/cPacket_Player.h index af2dbcc34..9d80eedc9 100644 --- a/source/packets/cPacket_Player.h +++ b/source/packets/cPacket_Player.h @@ -131,7 +131,7 @@ public: class cPacket_PlayerPosition : public cPacket { public: - cPacket_PlayerPosition( cPlayer* a_Player ); + cPacket_PlayerPosition(const cPlayer & a_Player); cPacket_PlayerPosition() : m_PosX( 0.0 ) , m_PosY( 0.0 ) -- cgit v1.2.3