From 66f4c9e0c08762fb4668792999c6200e9fd78c89 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Mon, 27 Aug 2012 17:31:16 +0000 Subject: Cut out all packet handling to a separate cProtocol descendant git-svn-id: http://mc-server.googlecode.com/svn/trunk@796 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cClientHandle.cpp | 1067 ++++++++-------------------------------------- 1 file changed, 175 insertions(+), 892 deletions(-) (limited to 'source/cClientHandle.cpp') diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 21d1f1722..a939dc786 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -40,50 +40,7 @@ #include "cAuthenticator.h" #include "MersenneTwister.h" -#include "packets/cPacket_13.h" -#include "packets/cPacket_ArmAnim.h" -#include "packets/cPacket_BlockAction.h" -#include "packets/cPacket_BlockChange.h" -#include "packets/cPacket_BlockDig.h" -#include "packets/cPacket_BlockPlace.h" -#include "packets/cPacket_Chat.h" -#include "packets/cPacket_CollectItem.h" -#include "packets/cPacket_CreativeInventoryAction.h" -#include "packets/cPacket_DestroyEntity.h" -#include "packets/cPacket_Disconnect.h" -#include "packets/cPacket_EntityEquipment.h" -#include "packets/cPacket_EntityLook.h" -#include "packets/cPacket_EntityStatus.h" -#include "packets/cPacket_Flying.h" -#include "packets/cPacket_Handshake.h" -#include "packets/cPacket_InventoryProgressBar.h" -#include "packets/cPacket_InventorySlot.h" -#include "packets/cPacket_ItemSwitch.h" -#include "packets/cPacket_KeepAlive.h" -#include "packets/cPacket_Login.h" -#include "packets/cPacket_MapChunk.h" -#include "packets/cPacket_Metadata.h" -#include "packets/cPacket_MultiBlock.h" -#include "packets/cPacket_NamedEntitySpawn.h" -#include "packets/cPacket_NewInvalidState.h" -#include "packets/cPacket_PickupSpawn.h" -#include "packets/cPacket_Ping.h" -#include "packets/cPacket_Player.h" -#include "packets/cPacket_PreChunk.h" -#include "packets/cPacket_RelativeEntityMove.h" -#include "packets/cPacket_RelativeEntityMoveLook.h" -#include "packets/cPacket_Respawn.h" -#include "packets/cPacket_SpawnMob.h" -#include "packets/cPacket_TeleportEntity.h" -#include "packets/cPacket_Thunderbolt.h" -#include "packets/cPacket_TimeUpdate.h" -#include "packets/cPacket_UpdateHealth.h" -#include "packets/cPacket_UpdateSign.h" -#include "packets/cPacket_UseEntity.h" -#include "packets/cPacket_WholeInventory.h" -#include "packets/cPacket_WindowClick.h" -#include "packets/cPacket_WindowClose.h" -#include "packets/cPacket_WindowOpen.h" +#include "Protocol125.h" @@ -126,8 +83,8 @@ int cClientHandle::s_ClientCount = 0; cClientHandle::cClientHandle(const cSocket & a_Socket, int a_ViewDistance) : m_ViewDistance(a_ViewDistance) , m_ProtocolVersion(MCS_PROTOCOL_VERSION) - , m_ReceivedData(64 KiB) , m_Socket(a_Socket) + , m_OutgoingData(64 KiB) , m_bDestroyed(false) , m_Player(NULL) , m_bKicking(false) @@ -139,44 +96,15 @@ cClientHandle::cClientHandle(const cSocket & a_Socket, int a_ViewDistance) , m_LastStreamedChunkZ(0x7fffffff) , m_UniqueID(0) { + m_Protocol = new cProtocol125(this); + s_ClientCount++; // Not protected by CS because clients are always constructed from the same thread m_UniqueID = s_ClientCount; cTimer t1; m_LastPingTime = t1.GetNowTime(); - // All the packets that can be received from the client - for (int i = 0; i < ARRAYCOUNT(m_PacketMap); ++i) - { - m_PacketMap[i] = NULL; - } - m_PacketMap[E_KEEP_ALIVE] = new cPacket_KeepAlive; - m_PacketMap[E_HANDSHAKE] = new cPacket_Handshake; - m_PacketMap[E_LOGIN] = new cPacket_Login; - m_PacketMap[E_PLAYERPOS] = new cPacket_PlayerPosition; - m_PacketMap[E_PLAYERLOOK] = new cPacket_PlayerLook; - m_PacketMap[E_PLAYERMOVELOOK] = new cPacket_PlayerMoveLook; - m_PacketMap[E_PLAYER_ABILITIES] = new cPacket_PlayerAbilities; - m_PacketMap[E_CHAT] = new cPacket_Chat; - m_PacketMap[E_ANIMATION] = new cPacket_ArmAnim; - m_PacketMap[E_FLYING] = new cPacket_Flying; - m_PacketMap[E_BLOCK_DIG] = new cPacket_BlockDig; - m_PacketMap[E_BLOCK_PLACE] = new cPacket_BlockPlace; - m_PacketMap[E_DISCONNECT] = new cPacket_Disconnect; - m_PacketMap[E_ITEM_SWITCH] = new cPacket_ItemSwitch; - m_PacketMap[E_ENTITY_EQUIPMENT] = new cPacket_EntityEquipment; - m_PacketMap[E_CREATIVE_INVENTORY_ACTION] = new cPacket_CreativeInventoryAction; - m_PacketMap[E_NEW_INVALID_STATE] = new cPacket_NewInvalidState; - m_PacketMap[E_PICKUP_SPAWN] = new cPacket_PickupSpawn; - m_PacketMap[E_USE_ENTITY] = new cPacket_UseEntity; - m_PacketMap[E_WINDOW_CLOSE] = new cPacket_WindowClose; - m_PacketMap[E_WINDOW_CLICK] = new cPacket_WindowClick; - m_PacketMap[E_PACKET_13] = new cPacket_13; - m_PacketMap[E_UPDATE_SIGN] = new cPacket_UpdateSign; - m_PacketMap[E_RESPAWN] = new cPacket_Respawn; - m_PacketMap[E_PING] = new cPacket_Ping; - - LOG("New ClientHandle created at %p", this); + LOGD("New ClientHandle created at %p", this); } @@ -185,7 +113,7 @@ cClientHandle::cClientHandle(const cSocket & a_Socket, int a_ViewDistance) cClientHandle::~cClientHandle() { - LOG("Deleting client \"%s\" at %p", GetUsername().c_str(), this); + LOGD("Deleting client \"%s\" at %p", GetUsername().c_str(), this); // Remove from cSocketThreads, we're not to be called anymore: cRoot::Get()->GetServer()->ClientDestroying(this); @@ -202,13 +130,11 @@ cClientHandle::~cClientHandle() if (!m_Username.empty() && (World != NULL)) { // Send the Offline PlayerList packet: - AString NameColor = (m_Player ? m_Player->GetColor() : ""); - cPacket_PlayerListItem PlayerList(NameColor + GetUsername(), false, (short)9999); - World->Broadcast(PlayerList, this); + World->BroadcastPlayerListItem(*m_Player, false, this); // Send the Chat packet: - cPacket_Chat Left(m_Username + " left the game!"); - World->Broadcast(Left, this); + AString Left(m_Username + " left the game!"); + World->BroadcastChat(Left, this); } if (World != NULL) { @@ -229,30 +155,14 @@ cClientHandle::~cClientHandle() m_Player->Destroy(); m_Player = NULL; } - for (int i = 0; i < ARRAYCOUNT(m_PacketMap); i++) - { - delete m_PacketMap[i]; - } // Queue all remaining outgoing packets to cSocketThreads: { - cCSLock Lock(m_CSPackets); - for (PacketList::iterator itr = m_PendingNrmSendPackets.begin(); itr != m_PendingNrmSendPackets.end(); ++itr) - { - AString Data; - (*itr)->Serialize(Data); - cRoot::Get()->GetServer()->WriteToClient(&m_Socket, Data); - delete *itr; - } - m_PendingNrmSendPackets.clear(); - for (PacketList::iterator itr = m_PendingLowSendPackets.begin(); itr != m_PendingLowSendPackets.end(); ++itr) - { - AString Data; - (*itr)->Serialize(Data); - cRoot::Get()->GetServer()->WriteToClient(&m_Socket, Data); - delete *itr; - } - m_PendingLowSendPackets.clear(); + cCSLock Lock(m_CSOutgoingData); + AString Data; + m_OutgoingData.ReadAll(Data); + m_OutgoingData.CommitRead(); + cRoot::Get()->GetServer()->WriteToClient(&m_Socket, Data); } // Queue the socket to close as soon as it sends all outgoing data: @@ -262,7 +172,10 @@ cClientHandle::~cClientHandle() // TODO: The socket needs to stay alive, someone else has to own it cRoot::Get()->GetServer()->RemoveClient(&m_Socket); - LOG("ClientHandle at %p deleted", this); + delete m_Protocol; + m_Protocol = NULL; + + LOGD("ClientHandle at %p deleted", this); } @@ -320,33 +233,26 @@ void cClientHandle::Authenticate(void) World = cRoot::Get()->GetDefaultWorld(); } - if(m_Player->GetGameMode() == eGameMode_NotSet) + if (m_Player->GetGameMode() == eGameMode_NotSet) + { m_Player->LoginSetGameMode(World->GetGameMode()); + } m_Player->SetIP (m_Socket.GetIPString()); cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::HOOK_PLAYER_SPAWN, 1, m_Player); // Return a server login packet - cPacket_Login LoginResponse; - LoginResponse.m_ProtocolVersion = m_Player->GetUniqueID(); - //LoginResponse.m_Username = ""; - LoginResponse.m_ServerMode = m_Player->GetGameMode(); // set gamemode from player. - LoginResponse.m_Dimension = 0; - LoginResponse.m_MaxPlayers = (unsigned char)cRoot::Get()->GetDefaultWorld()->GetMaxPlayers(); - LoginResponse.m_Difficulty = 2; - Send(LoginResponse); + m_Protocol->SendLogin(*m_Player); // Send Weather if raining: if ((World->GetWeather() == 1) || (World->GetWeather() == 2)) { - cPacket_NewInvalidState RainPacket; - RainPacket.m_Reason = 1; //begin rain - Send(RainPacket); + m_Protocol->SendWeather(World->GetWeather()); } // Send time - Send(cPacket_TimeUpdate(World->GetWorldTime())); + m_Protocol->SendTimeUpdate(World->GetWorldTime()); // Send inventory m_Player->GetInventory().SendWholeInventory(this); @@ -422,7 +328,7 @@ void cClientHandle::StreamChunks(void) for (cChunkCoordsList::iterator itr = RemoveChunks.begin(); itr != RemoveChunks.end(); ++itr) { World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ, this); - Send(cPacket_PreChunk(itr->m_ChunkX, itr->m_ChunkZ, false)); + m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - RemoveChunks[] // Add all chunks that are in range and not yet in m_LoadedChunks: @@ -502,232 +408,6 @@ void cClientHandle::RemoveFromAllChunks() -void cClientHandle::HandlePacket(cPacket * a_Packet) -{ - // TODO: _X: This function will get out-sourced into a separate cProtocol class - // and the switch statements will be split into virtual functions of that class - // Therefore I keep this function huge and untidy for the time being - // ( http://forum.mc-server.org/showthread.php?tid=524 ) - - // LOGD("Recv packet %02x", a_Packet->m_PacketID); - - m_TimeLastPacket = cWorld::GetTime(); - - // LOG("Recv packet 0x%02x from client \"%s\" (\"%s\")", a_Packet->m_PacketID, m_Socket.GetIPString().c_str(), m_Username.c_str()); - - if (m_bKicking) - { - return; - } - - switch (m_State) - { - case csConnected: - { - switch (a_Packet->m_PacketID) - { - case E_NEW_INVALID_STATE: // New/Invalid State packet received. I'm guessing the client only sends it when there's a problem with the bed? - { - LOGINFO("Got New Invalid State packet"); - break; - } - case E_PING: HandlePing (); break; - case E_HANDSHAKE: - { - cPacket_Handshake * Handshake = reinterpret_cast(a_Packet); - HandleHandshake(Handshake->m_Username); - break; - } - case E_LOGIN: - { - cPacket_Login * Login = reinterpret_cast(a_Packet); - HandleLogin(Login->m_ProtocolVersion, Login->m_Username); - break; - } - - // Ignored packets: - case E_PLAYERLOOK: - case E_CHAT: - case E_PLAYERMOVELOOK: - case E_PLAYERPOS: - case E_KEEP_ALIVE: break; - default: HandleUnexpectedPacket(a_Packet->m_PacketID); break; - } // switch (PacketType) - break; - } // case csConnected - - case csAuthenticating: - { - // Waiting for external authentication, no packets are handled - switch (a_Packet->m_PacketID) - { - // Ignored packets: - case E_KEEP_ALIVE: - case E_CHAT: - case E_FLYING: - case E_PLAYERLOOK: - case E_PLAYERMOVELOOK: - case E_PLAYERPOS: break; - - default: HandleUnexpectedPacket(a_Packet->m_PacketID); break; - } - break; - } - - case csDownloadingWorld: - { - // Waiting for chunks to stream to client, no packets are handled - switch (a_Packet->m_PacketID) - { - // Ignored packets: - case E_KEEP_ALIVE: - case E_CHAT: - case E_FLYING: - case E_PLAYERLOOK: - case E_PLAYERMOVELOOK: - case E_PLAYERPOS: break; - - default: HandleUnexpectedPacket(a_Packet->m_PacketID); break; - } - break; - } - - case csConfirmingPos: - { - switch (a_Packet->m_PacketID) - { - // Ignored packets: - case E_KEEP_ALIVE: - case E_CHAT: - case E_FLYING: - case E_PLAYERLOOK: - case E_PLAYERPOS: break; - - case E_PLAYERMOVELOOK: - { - cPacket_PlayerMoveLook * MoveLook = reinterpret_cast(a_Packet); - HandleMoveLookConfirm(MoveLook->m_PosX, MoveLook->m_PosY, MoveLook->m_PosZ); - break; - } - - default: - { - HandleUnexpectedPacket(a_Packet->m_PacketID); - break; - } - } // switch (PacketType) - break; - } // case csConfirmingPos - - case csPlaying: - { - switch (a_Packet->m_PacketID) - { - case E_CREATIVE_INVENTORY_ACTION: - { - cPacket_CreativeInventoryAction * cia = reinterpret_cast(a_Packet); - HandleCreativeInventory(cia->m_SlotNum, cia->m_ClickedItem); - break; - } - case E_PLAYERPOS: - { - cPacket_PlayerPosition * pp = reinterpret_cast(a_Packet); - HandlePlayerPos(pp->m_PosX, pp->m_PosY, pp->m_PosZ, pp->m_Stance, pp->m_IsOnGround); - break; - } - case E_BLOCK_DIG: - { - cPacket_BlockDig * bd = reinterpret_cast(a_Packet); - HandleBlockDig(bd->m_PosX, bd->m_PosY, bd->m_PosZ, bd->m_Direction, bd->m_Status); - break; - } - case E_BLOCK_PLACE: - { - cPacket_BlockPlace * bp = reinterpret_cast(a_Packet); - HandleBlockPlace(bp->m_PosX, bp->m_PosY, bp->m_PosZ, bp->m_Direction, bp->m_HeldItem); - break; - } - case E_CHAT: - { - cPacket_Chat * ch = reinterpret_cast(a_Packet); - HandleChat(ch->m_Message); - break; - } - case E_PLAYERLOOK: - { - cPacket_PlayerLook * pl = reinterpret_cast(a_Packet); - HandlePlayerLook(pl->m_Rotation, pl->m_Pitch, pl->m_IsOnGround); - break; - } - case E_PLAYERMOVELOOK: - { - cPacket_PlayerMoveLook * pml = reinterpret_cast(a_Packet); - HandlePlayerMoveLook(pml->m_PosX, pml->m_PosY, pml->m_PosZ, pml->m_Stance, pml->m_Rotation, pml->m_Pitch, pml->m_IsOnGround); - break; - } - case E_ANIMATION: - { - cPacket_ArmAnim * aa = reinterpret_cast(a_Packet); - HandleAnimation(aa->m_Animation); - break; - } - case E_SLOT_SELECTED: - { - cPacket_ItemSwitch * isw = reinterpret_cast(a_Packet); - HandleSlotSelected(isw->m_SlotNum); - break; - } - case E_WINDOW_CLOSE: - { - cPacket_WindowClose * wc = reinterpret_cast(a_Packet); - HandleWindowClose(wc->m_WindowID); - break; - } - case E_WINDOW_CLICK: - { - cPacket_WindowClick * wc = reinterpret_cast(a_Packet); - HandleWindowClick(wc->m_WindowID, wc->m_SlotNum, wc->m_IsRightClick, wc->m_IsShiftPressed, wc->m_HeldItem); - break; - } - case E_UPDATE_SIGN: - { - cPacket_UpdateSign * us = reinterpret_cast(a_Packet); - HandleUpdateSign(us->m_BlockX, us->m_BlockY, us->m_BlockZ, us->m_Line1, us->m_Line2, us->m_Line3, us->m_Line4); - break; - } - case E_USE_ENTITY: - { - cPacket_UseEntity * ue = reinterpret_cast(a_Packet); - HandleUseEntity(ue->m_TargetEntityID, ue->m_IsLeftClick); - break; - } - case E_RESPAWN: - { - HandleRespawn(); - break; - } - case E_DISCONNECT: - { - cPacket_Disconnect * dc = reinterpret_cast(a_Packet); - HandleDisconnect(dc->m_Reason); - break; - } - case E_KEEP_ALIVE: - { - cPacket_KeepAlive * ka = reinterpret_cast(a_Packet); - HandleKeepAlive(ka->m_KeepAliveID); - break; - } - } // switch (Packet type) - break; - } // case csPlaying - } // switch (m_State) -} - - - - - void cClientHandle::HandlePing(void) { // Somebody tries to retrieve information about the server @@ -763,11 +443,10 @@ void cClientHandle::HandleHandshake(const AString & a_Username) Kick("The server is currently full :(-- Try again later"); return; } - cPacket_Chat Connecting(m_Username + " is connecting."); - cRoot::Get()->GetServer()->Broadcast(Connecting, this); + cRoot::Get()->GetServer()->BroadcastChat(m_Username + " is connecting.", this); SendHandshake(cRoot::Get()->GetServer()->GetServerID()); - LOG("User \"%s\" was sent a handshake", m_Username.c_str()); + LOGD("User \"%s\" was sent a handshake", m_Username.c_str()); } @@ -1148,6 +827,11 @@ void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_ return; } */ + if (m_State != csPlaying) + { + // Ignore this packet unles the player is fully in: + return; + } m_Player->MoveTo(Vector3d(a_PosX, a_PosY, a_PosZ)); m_Player->SetStance (a_Stance); @@ -1297,6 +981,25 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID) +void cClientHandle::SendData(const char * a_Data, int a_Size) +{ + { + cCSLock Lock(m_CSOutgoingData); + if (!m_OutgoingData.Write(a_Data, a_Size)) + { + // Client has too much outgoing data queued, drop them silently: + Destroy(); + } + } + + // Notify SocketThreads that we have something to write: + cRoot::Get()->GetServer()->NotifyClientWrite(this); +} + + + + + bool cClientHandle::CheckBlockInteractionsRate(void) { ASSERT(m_Player != NULL); @@ -1345,9 +1048,8 @@ void cClientHandle::Tick(float a_Dt) if (m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime()) { m_PingID++; - cPacket_KeepAlive Ping(m_PingID); m_PingStartTime = t1.GetNowTime(); - Send(Ping); + m_Protocol->SendKeepAlive(m_PingID); m_LastPingTime = m_PingStartTime; } } @@ -1356,155 +1058,10 @@ void cClientHandle::Tick(float a_Dt) -void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* = E_PRIORITY_NORMAL */) -{ - if (m_bKicking) return; // Don't add more packets if player is getting kicked anyway - - // If it is the packet spawning myself for myself, drop it silently: - if (a_Packet.m_PacketID == E_NAMED_ENTITY_SPAWN) - { - if (((cPacket_NamedEntitySpawn &)a_Packet).m_UniqueID == m_Player->GetUniqueID()) - { - return; - } - } - - // Filter out packets that don't belong to a csDownloadingWorld state: - if (m_State == csDownloadingWorld) - { - switch (a_Packet.m_PacketID) - { - case E_PLAYERMOVELOOK: - case E_KEEP_ALIVE: - case E_PRE_CHUNK: - case E_MAP_CHUNK: - { - // Allow - break; - } - default: return; - } - } - - // Filter out map chunks that the client doesn't want anymore: - if (a_Packet.m_PacketID == E_MAP_CHUNK) - { - // Check chunks being sent, erase them from m_ChunksToSend: - int ChunkX = ((cPacket_MapChunk &)a_Packet).m_PosX; - int ChunkZ = ((cPacket_MapChunk &)a_Packet).m_PosZ; - bool Found = false; - cCSLock Lock(m_CSChunkLists); - for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end(); ++itr) - { - if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) - { - m_ChunksToSend.erase(itr); - - // TODO: _X: Decouple this from packet sending, it creates a deadlock possibility - // -- postpone till Tick() instead, using a bool flag - CheckIfWorldDownloaded(); - - Found = true; - break; - } - } // for itr - m_ChunksToSend[] - if (!Found) - { - // This just sometimes happens. If you have a reliably replicatable situation for this, go ahead and fix it - // It's not a big issue anyway, just means that some chunks may be compressed several times - // LOGD("Refusing to send chunk [%d, %d] to client \"%s\" at [%d, %d].", ChunkX, ChunkZ, m_Username.c_str(), m_Player->GetChunkX(), m_Player->GetChunkZ()); - return; - } - } - - // Filter out pre chunks that the client doesn't want anymore: - if ((a_Packet.m_PacketID == E_PRE_CHUNK) && ((cPacket_PreChunk &)a_Packet).m_bLoad) - { - int ChunkX = ((cPacket_PreChunk &)a_Packet).m_PosX; - int ChunkZ = ((cPacket_PreChunk &)a_Packet).m_PosZ; - bool Found = false; - cCSLock Lock(m_CSChunkLists); - for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end(); ++itr) - { - if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) - { - Found = true; - break; - } - } // for itr - m_ChunksToSend[] - if (!Found) - { - // This just sometimes happens. If you have a reliably replicatable situation for this, go ahead and fix it - // It's not a big issue anyway, just means that some chunks may be compressed several times - // LOGD("Refusing to send PREchunk [%d, %d] to client \"%s\" at [%d, %d].", ChunkX, ChunkZ, m_Username.c_str(), m_Player->GetChunkX(), m_Player->GetChunkZ()); - return; - } - } - - // Optimize away multiple queued RelativeEntityMoveLook packets: - static int NumRelEntMoveLookTotal = 0; - static int NumRelEntMoveLookRemoved = 0; - cCSLock Lock(m_CSPackets); - if (a_Priority == E_PRIORITY_NORMAL) - { - if (a_Packet.m_PacketID == E_REL_ENT_MOVE_LOOK) - { - NumRelEntMoveLookTotal++; - PacketList & Packets = m_PendingNrmSendPackets; - const cPacket_RelativeEntityMoveLook & ThisPacketData = reinterpret_cast< const cPacket_RelativeEntityMoveLook &>(a_Packet); - for (PacketList::iterator itr = Packets.begin(); itr != Packets.end(); ++itr) - { - bool bBreak = false; - switch ((*itr)->m_PacketID) - { - case E_REL_ENT_MOVE_LOOK: - { - cPacket_RelativeEntityMoveLook * PacketData = reinterpret_cast< cPacket_RelativeEntityMoveLook *>(*itr); - if (ThisPacketData.m_UniqueID == PacketData->m_UniqueID) - { - Packets.erase(itr); - bBreak = true; - delete PacketData; - NumRelEntMoveLookRemoved++; - break; - } - break; - } // case E_REL_END_MOVE_LOOK - } // switch (*itr -> Packet type) - if (bBreak) - { - break; - } - } // for itr - Packets[] - if ((NumRelEntMoveLookTotal % 1000) == 10) // print out a debug statistics every 1000 packets sent - { - LOGD("RelEntMoveLook optimization: removed %d out of %d packets, saved %d bytes (%d KiB) of bandwidth", - NumRelEntMoveLookRemoved, NumRelEntMoveLookTotal, - NumRelEntMoveLookRemoved * sizeof(cPacket_RelativeEntityMoveLook), - NumRelEntMoveLookRemoved * sizeof(cPacket_RelativeEntityMoveLook) / 1024 - ); - } - } // if (E_REL_ENT_MOVE_LOOK - m_PendingNrmSendPackets.push_back(a_Packet.Clone()); - } - else if (a_Priority == E_PRIORITY_LOW) - { - m_PendingLowSendPackets.push_back(a_Packet.Clone()); - } - Lock.Unlock(); - - // Notify SocketThreads that we have something to write: - cRoot::Get()->GetServer()->NotifyClientWrite(this); -} - - - - - void cClientHandle::SendDisconnect(const AString & a_Reason) { - cPacket_Disconnect DC(a_Reason); - Send(DC); // TODO: Send it immediately to the socket, bypassing any packet buffers (? is it safe? packet boundaries...) + LOGD("Sending a DC"); + m_Protocol->SendDisconnect(a_Reason); } @@ -1513,9 +1070,7 @@ void cClientHandle::SendDisconnect(const AString & a_Reason) void cClientHandle::SendHandshake(const AString & a_ServerName) { - cPacket_Handshake Handshake; - Handshake.m_Username = a_ServerName; - Send(Handshake); + m_Protocol->SendHandshake(a_ServerName); } @@ -1524,13 +1079,7 @@ void cClientHandle::SendHandshake(const AString & a_ServerName) void cClientHandle::SendInventorySlot(int a_WindowID, short a_SlotNum, const cItem & a_Item) { - cPacket_InventorySlot Packet; - Packet.m_WindowID = (char)a_WindowID; - Packet.m_SlotNum = a_SlotNum; - Packet.m_ItemID = (short)(a_Item.m_ItemID); - Packet.m_ItemCount = a_Item.m_ItemCount; - Packet.m_ItemUses = a_Item.m_ItemHealth; - Send(Packet); + m_Protocol->SendInventorySlot(a_WindowID, a_SlotNum, a_Item); } @@ -1539,8 +1088,7 @@ void cClientHandle::SendInventorySlot(int a_WindowID, short a_SlotNum, const cIt void cClientHandle::SendChat(const AString & a_Message) { - cPacket_Chat Chat(a_Message); - Send(Chat); + m_Protocol->SendChat(a_Message); } @@ -1549,10 +1097,7 @@ void cClientHandle::SendChat(const AString & a_Message) void cClientHandle::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation) { - cPacket_ArmAnim Anim; - Anim.m_EntityID = a_Player.GetUniqueID(); - Anim.m_Animation = a_Animation; - Send(Anim); + m_Protocol->SendPlayerAnimation(a_Player, a_Animation); } @@ -1561,12 +1106,7 @@ void cClientHandle::SendPlayerAnimation(const cPlayer & a_Player, char a_Animati void cClientHandle::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) { - cPacket_EntityEquipment ee; - ee.m_UniqueID = a_Entity.GetUniqueID(); - ee.m_SlotNum = a_SlotNum; - ee.m_ItemType = a_Item.m_ItemType; - ee.m_ItemDamage = a_Item.m_ItemDamage; - Send(ee); + m_Protocol->SendEntityEquipment(a_Entity, a_SlotNum, a_Item); } @@ -1575,12 +1115,7 @@ void cClientHandle::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNu void cClientHandle::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) { - cPacket_WindowOpen WindowOpen; - WindowOpen.m_WindowID = a_WindowID; - WindowOpen.m_InventoryType = a_WindowType; - WindowOpen.m_WindowTitle = a_WindowTitle; - WindowOpen.m_NumSlots = a_NumSlots; - Send(WindowOpen); + m_Protocol->SendWindowOpen(a_WindowID, a_WindowType, a_WindowTitle, a_NumSlots); } @@ -1589,9 +1124,7 @@ void cClientHandle::SendWindowOpen(char a_WindowID, char a_WindowType, const ASt void cClientHandle::SendWindowClose(char a_WindowID) { - cPacket_WindowClose wc; - wc.m_WindowID = a_WindowID; - Send(wc); + m_Protocol->SendWindowClose(a_WindowID); } @@ -1600,8 +1133,7 @@ void cClientHandle::SendWindowClose(char a_WindowID) void cClientHandle::SendWholeInventory(const cInventory & a_Inventory) { - cPacket_WholeInventory wi(a_Inventory); - Send(wi); + m_Protocol->SendWholeInventory(a_Inventory); } @@ -1610,8 +1142,7 @@ void cClientHandle::SendWholeInventory(const cInventory & a_Inventory) void cClientHandle::SendWholeInventory(const cWindow & a_Window) { - cPacket_WholeInventory wi(a_Window); - Send(wi); + m_Protocol->SendWholeInventory(a_Window); } @@ -1620,18 +1151,16 @@ void cClientHandle::SendWholeInventory(const cWindow & a_Window) void cClientHandle::SendTeleportEntity(const cEntity & a_Entity) { - cPacket_TeleportEntity te(a_Entity); - Send(te); + m_Protocol->SendTeleportEntity(a_Entity); } -void cClientHandle::SendPlayerListItem(const cPlayer & a_Player) +void cClientHandle::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) { - cPacket_PlayerListItem pli(a_Player.GetColor() + a_Player.GetName(), true, a_Player.GetClientHandle()->GetPing()); - Send(pli); + m_Protocol->SendPlayerListItem(a_Player, a_IsOnline); } @@ -1640,8 +1169,7 @@ void cClientHandle::SendPlayerListItem(const cPlayer & a_Player) void cClientHandle::SendPlayerPosition(void) { - cPacket_PlayerPosition pp(m_Player); - Send(pp); + m_Protocol->SendPlayerPosition(); } @@ -1652,14 +1180,7 @@ void cClientHandle::SendRelEntMoveLook(const cEntity & a_Entity, char a_RelX, ch { ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self - cPacket_RelativeEntityMoveLook reml; - reml.m_UniqueID = a_Entity.GetUniqueID(); - reml.m_MoveX = a_RelX; - reml.m_MoveY = a_RelY; - reml.m_MoveZ = a_RelZ; - reml.m_Yaw = (char)((a_Entity.GetRotation() / 360.f) * 256); - reml.m_Pitch = (char)((a_Entity.GetPitch() / 360.f) * 256); - Send(reml); + m_Protocol->SendRelEntMoveLook(a_Entity, a_RelX, a_RelY, a_RelZ); } @@ -1670,12 +1191,7 @@ void cClientHandle::SendRelEntMove(const cEntity & a_Entity, char a_RelX, char a { ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self - cPacket_RelativeEntityMove rem; - rem.m_UniqueID = a_Entity.GetUniqueID(); - rem.m_MoveX = a_RelX; - rem.m_MoveY = a_RelY; - rem.m_MoveZ = a_RelZ; - Send(rem); + m_Protocol->SendRelEntMove(a_Entity, a_RelX, a_RelY, a_RelZ); } @@ -1686,11 +1202,7 @@ void cClientHandle::SendEntLook(const cEntity & a_Entity) { ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self - cPacket_EntityLook el; - el.m_UniqueID = a_Entity.GetUniqueID(); - el.m_Rotation = (char)((a_Entity.GetRotation() / 360.f) * 256); - el.m_Pitch = (char)((a_Entity.GetPitch() / 360.f) * 256); - Send(el); + m_Protocol->SendEntLook(a_Entity); } @@ -1701,8 +1213,7 @@ void cClientHandle::SendEntHeadLook(const cEntity & a_Entity) { ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self - cPacket_EntityHeadLook ehl(a_Entity); - Send(ehl); + m_Protocol->SendEntHeadLook(a_Entity); } @@ -1711,13 +1222,7 @@ void cClientHandle::SendEntHeadLook(const cEntity & a_Entity) void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) { - cPacket_BlockAction ba; - ba.m_BlockX = a_BlockX; - ba.m_BlockY = (short)a_BlockY; - ba.m_BlockZ = a_BlockZ; - ba.m_Byte1 = a_Byte1; - ba.m_Byte2 = a_Byte2; - Send(ba); + m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2); } @@ -1726,11 +1231,7 @@ void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, ch void cClientHandle::SendHealth(void) { - cPacket_UpdateHealth Health; - Health.m_Health = m_Player->GetHealth(); - Health.m_Food = m_Player->GetFoodLevel(); - Health.m_Saturation = m_Player->GetFoodSaturationLevel(); - Send(Health); + m_Protocol->SendHealth(); } @@ -1739,21 +1240,16 @@ void cClientHandle::SendHealth(void) void cClientHandle::SendRespawn(void) { - cPacket_Respawn Packet; - Packet.m_CreativeMode = (char)m_Player->GetGameMode(); // Set GameMode packet based on Player's GameMode; - Send(Packet); + m_Protocol->SendRespawn(); } -void cClientHandle::SendGameMode(char a_GameMode) +void cClientHandle::SendGameMode(eGameMode a_GameMode) { - cPacket_NewInvalidState nis; - nis.m_Reason = 3; - nis.m_GameMode = a_GameMode; - Send(nis); + m_Protocol->SendGameMode(a_GameMode); } @@ -1762,9 +1258,7 @@ void cClientHandle::SendGameMode(char a_GameMode) void cClientHandle::SendDestroyEntity(const cEntity & a_Entity) { - cPacket_DestroyEntity de; - de.m_UniqueID = a_Entity.GetUniqueID(); - Send(de); + m_Protocol->SendDestroyEntity(a_Entity); } @@ -1773,13 +1267,12 @@ void cClientHandle::SendDestroyEntity(const cEntity & a_Entity) void cClientHandle::SendPlayerMoveLook(void) { - cPacket_PlayerMoveLook pml(*m_Player); /* LOGD("Sending PlayerMoveLook: {%0.2f, %0.2f, %0.2f}, stance %0.2f, OnGround: %d", m_Player->GetPosX(), m_Player->GetPosY(), m_Player->GetPosZ(), m_Player->GetStance(), m_Player->IsOnGround() ? 1 : 0 ); */ - Send(pml); + m_Protocol->SendPlayerMoveLook(); } @@ -1788,10 +1281,7 @@ void cClientHandle::SendPlayerMoveLook(void) void cClientHandle::SendEntityStatus(const cEntity & a_Entity, char a_Status) { - cPacket_EntityStatus es; - es.m_Status = a_Status; - es.m_UniqueID = a_Entity.GetUniqueID(); - Send(es); + m_Protocol->SendEntityStatus(a_Entity, a_Status); } @@ -1800,8 +1290,7 @@ void cClientHandle::SendEntityStatus(const cEntity & a_Entity, char a_Status) void cClientHandle::SendMetadata(const cPawn & a_Pawn) { - cPacket_Metadata md(a_Pawn.GetMetaData(), a_Pawn.GetUniqueID()); - Send(md); + m_Protocol->SendMetadata(a_Pawn); } @@ -1810,12 +1299,7 @@ void cClientHandle::SendMetadata(const cPawn & a_Pawn) void cClientHandle::SendInventoryProgress(char a_WindowID, short a_ProgressBar, short a_Value) { - cPacket_InventoryProgressBar Progress; - Progress.m_WindowID = a_WindowID; - Progress.m_ProgressBar = a_ProgressBar; - Progress.m_Value = a_Value; - Progress.m_WindowID = a_WindowID; - Send(Progress); + m_Protocol->SendInventoryProgress(a_WindowID, a_ProgressBar, a_Value); } @@ -1824,17 +1308,13 @@ void cClientHandle::SendInventoryProgress(char a_WindowID, short a_ProgressBar, void cClientHandle::SendPlayerSpawn(const cPlayer & a_Player) { - cPacket_NamedEntitySpawn SpawnPacket; - SpawnPacket.m_UniqueID = a_Player.GetUniqueID(); - SpawnPacket.m_PlayerName = a_Player.GetName(); - SpawnPacket.m_PosX = (int)(a_Player.GetPosX() * 32); - SpawnPacket.m_PosY = (int)(a_Player.GetPosY() * 32); - SpawnPacket.m_PosZ = (int)(a_Player.GetPosZ() * 32); - SpawnPacket.m_Rotation = (char)((a_Player.GetRot().x / 360.f) * 256); - SpawnPacket.m_Pitch = (char)((a_Player.GetRot().y / 360.f) * 256); - const cItem & HeldItem = a_Player.GetEquippedItem(); - SpawnPacket.m_CurrentItem = HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType; // Unlike -1 in inventory, the named entity packet uses 0 for "empty" - Send(SpawnPacket); + if (a_Player.GetUniqueID() == m_Player->GetUniqueID()) + { + // Do NOT send this packet to myself + return; + } + + m_Protocol->SendPlayerSpawn(a_Player); } @@ -1843,18 +1323,7 @@ void cClientHandle::SendPlayerSpawn(const cPlayer & a_Player) void cClientHandle::SendPickupSpawn(const cPickup & a_Pickup) { - cPacket_PickupSpawn PickupSpawn; - PickupSpawn.m_UniqueID = a_Pickup.GetUniqueID(); - PickupSpawn.m_ItemType = a_Pickup.GetItem()->m_ItemType; - PickupSpawn.m_ItemCount = a_Pickup.GetItem()->m_ItemCount; - PickupSpawn.m_ItemDamage = a_Pickup.GetItem()->m_ItemHealth; - PickupSpawn.m_PosX = (int) (a_Pickup.GetPosX() * 32); - PickupSpawn.m_PosY = (int) (a_Pickup.GetPosY() * 32); - PickupSpawn.m_PosZ = (int) (a_Pickup.GetPosZ() * 32); - PickupSpawn.m_Rotation = (char)(a_Pickup.GetSpeed().x * 8); - PickupSpawn.m_Pitch = (char)(a_Pickup.GetSpeed().y * 8); - PickupSpawn.m_Roll = (char)(a_Pickup.GetSpeed().z * 8); - Send(PickupSpawn); + m_Protocol->SendPickupSpawn(a_Pickup); } @@ -1863,16 +1332,7 @@ void cClientHandle::SendPickupSpawn(const cPickup & a_Pickup) void cClientHandle::SendSpawnMob(const cMonster & a_Mob) { - cPacket_SpawnMob Spawn; - Spawn.m_UniqueID = a_Mob.GetUniqueID(); - Spawn.m_Type = a_Mob.GetMobType(); - Spawn.m_Pos = ((Vector3i)(a_Mob.GetPosition())) * 32; - Spawn.m_Yaw = 0; - Spawn.m_Pitch = 0; - Spawn.m_MetaDataSize = 1; - Spawn.m_MetaData = new char[Spawn.m_MetaDataSize]; - Spawn.m_MetaData[0] = 0x7f; // not on fire/crouching/riding - Send(Spawn); + m_Protocol->SendSpawnMob(a_Mob); } @@ -1884,15 +1344,10 @@ void cClientHandle::SendUpdateSign( const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4 ) { - cPacket_UpdateSign us; - us.m_BlockX = a_BlockX; - us.m_BlockY = a_BlockY; - us.m_BlockZ = a_BlockZ; - us.m_Line1 = a_Line1; - us.m_Line2 = a_Line2; - us.m_Line3 = a_Line3; - us.m_Line4 = a_Line4; - Send(us); + m_Protocol->SendUpdateSign( + a_BlockX, a_BlockY, a_BlockZ, + a_Line1, a_Line2, a_Line3, a_Line4 + ); } @@ -1901,10 +1356,7 @@ void cClientHandle::SendUpdateSign( void cClientHandle::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) { - cPacket_CollectItem ci; - ci.m_CollectedID = a_Pickup.GetUniqueID(); - ci.m_CollectorID = a_Player.GetUniqueID(); - Send(ci); + m_Protocol->SendCollectPickup(a_Pickup, a_Player); } @@ -1913,13 +1365,7 @@ void cClientHandle::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & void cClientHandle::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - cPacket_BlockChange BlockChange; - BlockChange.m_PosX = a_BlockX; - BlockChange.m_PosY = (unsigned char)a_BlockY; - BlockChange.m_PosZ = a_BlockZ; - BlockChange.m_BlockType = a_BlockType; - BlockChange.m_BlockMeta = a_BlockMeta; - Send(BlockChange); + m_Protocol->SendBlockChange(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); } @@ -1928,27 +1374,7 @@ void cClientHandle::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BL void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) { - if (a_Changes.size() == 1) - { - // Special packet for single-block changes - const sSetBlock & blk = a_Changes.front(); - SendBlockChange(a_ChunkX * cChunkDef::Width + blk.x, blk.y, a_ChunkZ * cChunkDef::Height + blk.z, blk.BlockType, blk.BlockMeta); - return; - } - - cPacket_MultiBlock MultiBlock; - MultiBlock.m_ChunkX = a_ChunkX; - MultiBlock.m_ChunkZ = a_ChunkZ; - MultiBlock.m_NumBlocks = (short)a_Changes.size(); - MultiBlock.m_Data = new cPacket_MultiBlock::sBlockChange[a_Changes.size()]; - int i = 0; - for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr, i++) - { - unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12); - unsigned int Blocks = itr->BlockMeta | (itr->BlockType << 4); - MultiBlock.m_Data[i].Data = Coords << 16 | Blocks; - } - Send(MultiBlock); + m_Protocol->SendBlockChanges(a_ChunkX, a_ChunkZ, a_Changes); } @@ -1957,11 +1383,7 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) { - cPacket_PreChunk UnloadPacket; - UnloadPacket.m_PosX = a_ChunkX; - UnloadPacket.m_PosZ = a_ChunkZ; - UnloadPacket.m_bLoad = false; // Unload - Send(UnloadPacket); + m_Protocol->SendUnloadChunk(a_ChunkX, a_ChunkZ); } @@ -1970,32 +1392,7 @@ void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) void cClientHandle::SendWeather(eWeather a_Weather) { - switch( a_Weather ) - { - case eWeather_Sunny: - { - cPacket_NewInvalidState WeatherPacket; - WeatherPacket.m_Reason = 2; // stop rain - Send(WeatherPacket); - break; - } - - case eWeather_Rain: - { - cPacket_NewInvalidState WeatherPacket; - WeatherPacket.m_Reason = 1; // begin rain - Send(WeatherPacket); - break; - } - - case eWeather_ThunderStorm: - { - cPacket_NewInvalidState WeatherPacket; - WeatherPacket.m_Reason = 1; // begin rain - Send(WeatherPacket); - break; - } - } + m_Protocol->SendWeather(a_Weather); } @@ -2004,9 +1401,7 @@ void cClientHandle::SendWeather(eWeather a_Weather) void cClientHandle::SendTimeUpdate(Int64 a_WorldTime) { - cPacket_TimeUpdate tu; - tu.m_Time = a_WorldTime; - Send(tu); + m_Protocol->SendTimeUpdate(a_WorldTime); } @@ -2015,11 +1410,7 @@ void cClientHandle::SendTimeUpdate(Int64 a_WorldTime) void cClientHandle::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) { - cPacket_Thunderbolt ThunderboltPacket; - ThunderboltPacket.m_xLBPos = a_BlockX; - ThunderboltPacket.m_yLBPos = a_BlockY; - ThunderboltPacket.m_zLBPos = a_BlockZ; - Send(ThunderboltPacket); + m_Protocol->SendThunderbolt(a_BlockX, a_BlockY, a_BlockZ); } @@ -2028,13 +1419,32 @@ void cClientHandle::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { - // Send the pre-chunk: - cPacket_PreChunk pre(a_ChunkX, a_ChunkZ, true); - Send(pre); + // Check chunks being sent, erase them from m_ChunksToSend: + bool Found = false; + cCSLock Lock(m_CSChunkLists); + for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end(); ++itr) + { + if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ)) + { + m_ChunksToSend.erase(itr); + + // TODO: _X: Decouple this from packet sending, it creates a deadlock possibility + // -- postpone till Tick() instead, using a bool flag + CheckIfWorldDownloaded(); + + Found = true; + break; + } + } // for itr - m_ChunksToSend[] + if (!Found) + { + // This just sometimes happens. If you have a reliably replicatable situation for this, go ahead and fix it + // It's not a big issue anyway, just means that some chunks may be compressed several times + // LOGD("Refusing to send chunk [%d, %d] to client \"%s\" at [%d, %d].", ChunkX, ChunkZ, m_Username.c_str(), m_Player->GetChunkX(), m_Player->GetChunkZ()); + return; + } - // Send the data: - cPacket_MapChunk mc(a_ChunkX, a_ChunkZ, a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_2_5)); - Send(mc); + m_Protocol->SendChunkData(a_ChunkX, a_ChunkZ, a_Serializer); } @@ -2075,8 +1485,7 @@ void cClientHandle::SendConfirmPosition(void) if (!cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::HOOK_PLAYER_JOIN, 1, m_Player)) { // Broadcast that this player has joined the game! Yay~ - cPacket_Chat Joined(m_Username + " joined the game!"); - cRoot::Get()->GetServer()->Broadcast(Joined, this); + cRoot::Get()->GetServer()->BroadcastChat(m_Username + " joined the game!", this); } m_ConfirmPosition = m_Player->GetPosition(); @@ -2140,194 +1549,68 @@ void cClientHandle::AddWantedChunk(int a_ChunkX, int a_ChunkZ) -void cClientHandle::DataReceived(const char * a_Data, int a_Size) +void cClientHandle::PacketBufferFull(void) { - // Data is received from the client - - if (!m_ReceivedData.Write(a_Data, a_Size)) - { - // Too much data in the incoming queue, the server is probably too busy, kick the client: - LOGERROR("Too much data in queue for client \"%s\" @ %s, kicking them.", m_Username.c_str(), m_Socket.GetIPString().c_str()); - SendDisconnect("Server busy"); - // TODO: QueueDestroy(); - cSleep::MilliSleep(1000); // Give packet some time to be received - Destroy(); - return; - } + // Too much data in the incoming queue, the server is probably too busy, kick the client: + LOGERROR("Too much data in queue for client \"%s\" @ %s, kicking them.", m_Username.c_str(), m_Socket.GetIPString().c_str()); + SendDisconnect("Server busy"); + // TODO: QueueDestroy(); + cSleep::MilliSleep(1000); // Give packet some time to be received + Destroy(); +} - // Parse and handle all complete packets in m_ReceivedData: - while (m_ReceivedData.CanReadBytes(1)) - { - unsigned char PacketType; - m_ReceivedData.ReadByte(PacketType); - cPacket* pPacket = m_PacketMap[PacketType]; - if (pPacket == NULL) - { - LOGERROR("Unknown packet type 0x%02x from client \"%s\" @ %s", PacketType, m_Username.c_str(), m_Socket.GetIPString().c_str()); - AString Reason; - Printf(Reason, "[C->S] Unknown PacketID: 0x%02x", PacketType); - SendDisconnect(Reason); - // TODO: QueueDestroy(); - cSleep::MilliSleep(1000); // Give packet some time to be received - Destroy(); - return; - } - - int NumBytes = pPacket->Parse(m_ReceivedData); - if (NumBytes == PACKET_ERROR) - { - LOGERROR("Protocol error while parsing packet type 0x%02x; disconnecting client \"%s\"", PacketType, m_Username.c_str()); - SendDisconnect("Protocol error"); - // TODO: QueueDestroy(); - cSleep::MilliSleep(1000); // Give packet some time to be received - Destroy(); - return; - } - else if (NumBytes == PACKET_INCOMPLETE) - { - // Not a complete packet - m_ReceivedData.ResetRead(); - break; - } - else - { - // Packet parsed successfully, add it to internal queue: - HandlePacket(pPacket); - // Erase the packet from the buffer: - m_ReceivedData.CommitRead(); - } - } // while (!Received.CanReadBytes(1)) + + + +void cClientHandle::PacketUnknown(unsigned char a_PacketType) +{ + LOGERROR("Unknown packet type 0x%02x from client \"%s\" @ %s", a_PacketType, m_Username.c_str(), m_Socket.GetIPString().c_str()); + + AString Reason; + Printf(Reason, "[C->S] Unknown PacketID: 0x%02x", a_PacketType); + SendDisconnect(Reason); + // TODO: QueueDestroy(); + cSleep::MilliSleep(1000); // Give packet some time to be received + Destroy(); } -void cClientHandle::GetOutgoingData(AString & a_Data) +void cClientHandle::PacketError(unsigned char a_PacketType) { - // Data can be sent to client - - cCSLock Lock(m_CSPackets); - if (m_PendingNrmSendPackets.size() + m_PendingLowSendPackets.size() > MAX_OUTGOING_PACKETS) - { - LOGERROR("ERROR: Too many packets in queue for player %s !!", m_Username.c_str()); - SendDisconnect("Too many packets in queue."); - - // DEBUG: Dump all outstanding packets' types to the log: - int Idx = 0; - int ChunkX = m_Player->GetChunkX(); - int ChunkZ = m_Player->GetChunkZ(); - for (PacketList::const_iterator itr = m_PendingNrmSendPackets.begin(); itr != m_PendingNrmSendPackets.end(); ++itr) - { - switch ((*itr)->m_PacketID) - { - case E_MAP_CHUNK: - { - int x = ((cPacket_MapChunk *)(*itr))->m_PosX; - int z = ((cPacket_MapChunk *)(*itr))->m_PosZ; - bool IsWanted = (abs(x - ChunkX) <= m_ViewDistance) && (abs(z - ChunkZ) <= m_ViewDistance); - LOG("Packet %4d: type %2x (MapChunk: %d, %d, %s)", - Idx++, (*itr)->m_PacketID, - x, z, - IsWanted ? "wanted" : "unwanted" - ); - break; - } - - case E_PRE_CHUNK: - { - int x = ((cPacket_PreChunk *)(*itr))->m_PosX; - int z = ((cPacket_PreChunk *)(*itr))->m_PosZ; - bool IsWanted = (abs(x - ChunkX) <= m_ViewDistance) && (abs(z - ChunkZ) <= m_ViewDistance); - bool Loading = ((cPacket_PreChunk *)(*itr))->m_bLoad; - LOG("Packet %4d: type %2x (PreChunk: %d, %d, %s, %s)", - Idx++, (*itr)->m_PacketID, - x, z, - Loading ? "loading" : "unloading", - IsWanted ? "wanted" : "unwanted" - ); - break; - } - - case E_BLOCK_CHANGE: - { - int x = ((cPacket_BlockChange *)(*itr))->m_PosX; - int z = ((cPacket_BlockChange *)(*itr))->m_PosZ; - char ToBlock = ((cPacket_BlockChange *)(*itr))->m_BlockType; - int y, cx, cz; - cChunkDef::AbsoluteToRelative(x, y, z, cx, cz); - bool IsWanted = (abs(cx - ChunkX) <= m_ViewDistance) && (abs(cz - ChunkZ) <= m_ViewDistance); - LOG("Packet %4d: type %2x (BlockChange: [%d, %d], %s chunk; to block %d)", - Idx++, (*itr)->m_PacketID, - cx, cz, - IsWanted ? "wanted" : "unwanted", - ToBlock - ); - break; - } - - case E_MULTI_BLOCK: - { - int cx = ((cPacket_MultiBlock *)(*itr))->m_ChunkX; - int cz = ((cPacket_MultiBlock *)(*itr))->m_ChunkZ; - int NumBlocks = ((cPacket_MultiBlock *)(*itr))->m_NumBlocks; - bool IsWanted = (abs(cx - ChunkX) <= m_ViewDistance) && (abs(cz - ChunkZ) <= m_ViewDistance); - LOG("Packet %4d: type %2x (MultiBlock: [%d, %d], %s chunk, %d blocks)", - Idx++, (*itr)->m_PacketID, - cx, cz, - IsWanted ? "wanted" : "unwanted", - NumBlocks - ); - break; - } - - default: - { - LOG("Packet %4d: type %2x", Idx++, (*itr)->m_PacketID); - break; - } - } - } - - Lock.Unlock(); - Destroy(); - return; - } - - if ((m_PendingNrmSendPackets.size() == 0) && (m_PendingLowSendPackets.size() == 0)) - { - return; - } + LOGERROR("Protocol error while parsing packet type 0x%02x; disconnecting client \"%s\"", a_PacketType, m_Username.c_str()); + SendDisconnect("Protocol error"); + // TODO: QueueDestroy(); + cSleep::MilliSleep(1000); // Give packet some time to be received + Destroy(); +} - if (m_PendingNrmSendPackets.size() > MAX_OUTGOING_PACKETS / 2) - { - LOGINFO("Suspiciously many pending packets: %i; client \"%s\", LastType: 0x%02x", m_PendingNrmSendPackets.size(), m_Username.c_str(), (*m_PendingNrmSendPackets.rbegin())->m_PacketID); - } - AString Data; - Data.reserve(1100); - // Serialize normal-priority packets up to 1000 bytes - while (!m_PendingNrmSendPackets.empty() && (Data.size() < 1000)) - { - m_PendingNrmSendPackets.front()->Serialize(Data); - // LOGD("Sending packet 0x%02x", m_PendingNrmSendPackets.front()->m_PacketID); - delete m_PendingNrmSendPackets.front(); - m_PendingNrmSendPackets.erase(m_PendingNrmSendPackets.begin()); - } - // Serialize one low-priority packet: - if (!m_PendingLowSendPackets.empty() && Data.empty()) - { - m_PendingLowSendPackets.front()->Serialize(Data); - delete m_PendingLowSendPackets.front(); - m_PendingLowSendPackets.erase(m_PendingLowSendPackets.begin()); - } - Lock.Unlock(); - - a_Data.append(Data); + + + +void cClientHandle::DataReceived(const char * a_Data, int a_Size) +{ + // Data is received from the client, hand it off to the protocol: + m_Protocol->DataReceived(a_Data, a_Size); + m_TimeLastPacket = cWorld::GetTime(); +} + + + + + +void cClientHandle::GetOutgoingData(AString & a_Data) +{ + // Data can be sent to client + m_OutgoingData.ReadAll(a_Data); + m_OutgoingData.CommitRead(); // Disconnect player after all packets have been sent - if (m_bKicking && (m_PendingNrmSendPackets.size() + m_PendingLowSendPackets.size() == 0)) + if (m_bKicking && a_Data.empty()) { Destroy(); } -- cgit v1.2.3