summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/Bindings.cpp4
-rw-r--r--source/Bindings.h2
-rw-r--r--source/ByteBuffer.cpp9
-rw-r--r--source/ByteBuffer.h3
-rw-r--r--source/PacketID.h2
-rw-r--r--source/Protocol.h95
-rw-r--r--source/Protocol125.cpp1104
-rw-r--r--source/Protocol125.h126
-rw-r--r--source/ProtocolRecognizer.h78
-rw-r--r--source/cChunk.cpp109
-rw-r--r--source/cChunkMap.cpp38
-rw-r--r--source/cChunkMap.h8
-rw-r--r--source/cClientHandle.cpp1067
-rw-r--r--source/cClientHandle.h104
-rw-r--r--source/cServer.cpp18
-rw-r--r--source/cServer.h1
-rw-r--r--source/cSocketThreads.cpp3
-rw-r--r--source/cSocketThreads.h4
-rw-r--r--source/cWindow.h4
-rw-r--r--source/cWorld.cpp55
-rw-r--r--source/cWorld.h11
-rw-r--r--source/packets/cPacket.h9
-rw-r--r--source/packets/cPacket_13.h2
-rw-r--r--source/packets/cPacket_Player.cpp12
-rw-r--r--source/packets/cPacket_Player.h2
25 files changed, 1685 insertions, 1185 deletions
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<cPacket_Handshake *>(a_Packet);
- HandleHandshake(Handshake->m_Username);
- break;
- }
- case E_LOGIN:
- {
- cPacket_Login * Login = reinterpret_cast<cPacket_Login *>(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<cPacket_PlayerMoveLook *>(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<cPacket_CreativeInventoryAction *>(a_Packet);
- HandleCreativeInventory(cia->m_SlotNum, cia->m_ClickedItem);
- break;
- }
- case E_PLAYERPOS:
- {
- cPacket_PlayerPosition * pp = reinterpret_cast<cPacket_PlayerPosition *>(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<cPacket_BlockDig *>(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<cPacket_BlockPlace *>(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<cPacket_Chat *>(a_Packet);
- HandleChat(ch->m_Message);
- break;
- }
- case E_PLAYERLOOK:
- {
- cPacket_PlayerLook * pl = reinterpret_cast<cPacket_PlayerLook *>(a_Packet);
- HandlePlayerLook(pl->m_Rotation, pl->m_Pitch, pl->m_IsOnGround);
- break;
- }
- case E_PLAYERMOVELOOK:
- {
- cPacket_PlayerMoveLook * pml = reinterpret_cast<cPacket_PlayerMoveLook *>(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<cPacket_ArmAnim *>(a_Packet);
- HandleAnimation(aa->m_Animation);
- break;
- }
- case E_SLOT_SELECTED:
- {
- cPacket_ItemSwitch * isw = reinterpret_cast<cPacket_ItemSwitch *>(a_Packet);
- HandleSlotSelected(isw->m_SlotNum);
- break;
- }
- case E_WINDOW_CLOSE:
- {
- cPacket_WindowClose * wc = reinterpret_cast<cPacket_WindowClose *>(a_Packet);
- HandleWindowClose(wc->m_WindowID);
- break;
- }
- case E_WINDOW_CLICK:
- {
- cPacket_WindowClick * wc = reinterpret_cast<cPacket_WindowClick *>(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<cPacket_UpdateSign *>(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<cPacket_UseEntity *>(a_Packet);
- HandleUseEntity(ue->m_TargetEntityID, ue->m_IsLeftClick);
- break;
- }
- case E_RESPAWN:
- {
- HandleRespawn();
- break;
- }
- case E_DISCONNECT:
- {
- cPacket_Disconnect * dc = reinterpret_cast<cPacket_Disconnect *>(a_Packet);
- HandleDisconnect(dc->m_Reason);
- break;
- }
- case E_KEEP_ALIVE:
- {
- cPacket_KeepAlive * ka = reinterpret_cast<cPacket_KeepAlive *>(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 )