From 393ca0221dfdb6dabadcf293fea86a830453c938 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 18 Feb 2014 20:50:08 +0200 Subject: [PATCH] Map decorators; Map clients --- src/ClientHandle.cpp | 22 ++- src/ClientHandle.h | 2 + src/Items/ItemMap.h | 4 +- src/Map.cpp | 238 +++++++++++++++++++++++++--- src/Map.h | 75 ++++++++- src/Protocol/Protocol.h | 3 +- src/Protocol/Protocol125.cpp | 25 +++ src/Protocol/Protocol125.h | 1 + src/Protocol/Protocol17x.cpp | 20 +++ src/Protocol/Protocol17x.h | 1 + src/Protocol/ProtocolRecognizer.cpp | 10 ++ src/Protocol/ProtocolRecognizer.h | 1 + 12 files changed, 354 insertions(+), 48 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index a2cbaefff..efc5a9f64 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1190,19 +1190,6 @@ void cClientHandle::HandleSlotSelected(short a_SlotNum) { m_Player->GetInventory().SetEquippedSlotNum(a_SlotNum); m_Player->GetWorld()->BroadcastEntityEquipment(*m_Player, 0, m_Player->GetInventory().GetEquippedItem(), this); - - const cItem & Item = m_Player->GetInventory().GetEquippedItem(); - if (Item.m_ItemType == E_ITEM_MAP) - { - // TODO 2014-02-14 xdot: Do not hardcode this. - cMap * Map = m_Player->GetWorld()->GetMapData(Item.m_ItemDamage); - - if (Map != NULL) - { - // TODO 2014-02-14 xdot: Optimization - Do not send the whole map. - Map->SendTo(*this); - } - } } @@ -2079,6 +2066,15 @@ void cClientHandle::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Col +void cClientHandle::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators) +{ + m_Protocol->SendMapDecorators(a_ID, a_Decorators); +} + + + + + void cClientHandle::SendMapInfo(int a_ID, unsigned int a_Scale) { m_Protocol->SendMapInfo(a_ID, a_Scale); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index a714cf8b9..a613a76e8 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -17,6 +17,7 @@ #include "ChunkDef.h" #include "ByteBuffer.h" #include "Scoreboard.h" +#include "Map.h" @@ -110,6 +111,7 @@ public: void SendHealth (void); void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item); void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length); + void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators); void SendMapInfo (int a_ID, unsigned int a_Scale); void SendPickupSpawn (const cPickup & a_Pickup); void SendEntityAnimation (const cEntity & a_Entity, char a_Animation); diff --git a/src/Items/ItemMap.h b/src/Items/ItemMap.h index c3e605547..9bb16b189 100644 --- a/src/Items/ItemMap.h +++ b/src/Items/ItemMap.h @@ -36,8 +36,8 @@ public: return; } - // Map->AddTrackedPlayer(a_Player); - Map->UpdateRadius(*a_Player, DEFAULT_RADIUS); + + Map->UpdateClient(a_Player); } } ; diff --git a/src/Map.cpp b/src/Map.cpp index e85c23d3a..f32d232fa 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -14,6 +14,111 @@ +cMapDecorator::cMapDecorator(cMap * a_Map, eType a_Type, int a_X, int a_Z, unsigned int a_Rot) + : m_Map(a_Map) + , m_Type(a_Type) + , m_PixelX(a_X) + , m_PixelZ(a_Z) + , m_Rot(a_Rot) + , m_Player(NULL) +{ +} + + + + + +cMapDecorator::cMapDecorator(cMap * a_Map, cPlayer * a_Player) + : m_Map(a_Map) + , m_Type(E_TYPE_PLAYER) + , m_Player(a_Player) +{ + Update(); +} + + + + + +template +T Clamp(T a_X, T a_Min, T a_Max) +{ + return std::min(std::max(a_X, a_Min), a_Max); +} + + + + + +void cMapDecorator::Update(void) +{ + ASSERT(m_Map != NULL); + unsigned int PixelWidth = m_Map->GetPixelWidth(); + + int InsideWidth = (m_Map->GetWidth() / 2) - 1; + int InsideHeight = (m_Map->GetHeight() / 2) - 1; + + if (m_Player) + { + int PixelX = (m_Player->GetPosX() - m_Map->GetCenterX()) / PixelWidth; + int PixelZ = (m_Player->GetPosZ() - m_Map->GetCenterZ()) / PixelWidth; + + // Center of pixel + m_PixelX = (2 * PixelX) + 1; + m_PixelZ = (2 * PixelZ) + 1; + + // 1px border + if ((PixelX > -InsideWidth) && (PixelX <= InsideWidth) && (PixelZ > -InsideHeight) && (PixelZ <= InsideHeight)) + { + double Yaw = m_Player->GetYaw(); + + m_Rot = (Yaw * 16) / 360; + + if (m_Map->GetDimension() == dimNether) + { + Int64 WorldAge = m_Player->GetWorld()->GetWorldAge(); + + // TODO 2014-02-18 xdot: Random rotations + } + + m_Type = E_TYPE_PLAYER; + } + else + { + if ((abs(PixelX) > 320.0) || (abs(PixelZ) > 320.0)) + { + // TODO 2014-02-18 xdot: Remove decorator + } + + m_Rot = 0; + + m_Type = E_TYPE_PLAYER_OUTSIDE; + + // Move to border + if (PixelX <= -InsideWidth) + { + m_PixelX = (2 * -InsideWidth) + 1; + } + if (PixelZ <= -InsideHeight) + { + m_PixelZ = (2 * -InsideHeight) + 1; + } + if (PixelX > InsideWidth) + { + m_PixelX = (2 * InsideWidth) + 1; + } + if (PixelZ > InsideHeight) + { + m_PixelZ = (2 * InsideHeight) + 1; + } + } + } +} + + + + + cMap::cMap(unsigned int a_ID, cWorld * a_World) : m_ID(a_ID) , m_Width(cChunkDef::Width * 8) @@ -50,16 +155,6 @@ cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, un -template -T Clamp(T a_X, T a_Min, T a_Max) -{ - return std::min(std::max(a_X, a_Min), a_Max); -} - - - - - void cMap::UpdateRadius(int a_PixelX, int a_PixelZ, unsigned int a_Radius) { int PixelRadius = a_Radius / GetPixelWidth(); @@ -174,33 +269,117 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z) -void cMap::UpdateTrackedPlayers(void) +void cMap::UpdateDecorators(void) { - cTrackedPlayerList NewList; - - for (cTrackedPlayerList::iterator it = m_TrackedPlayers.begin(); it != m_TrackedPlayers.end(); ++it) + for (cMapDecoratorList::iterator it = m_Decorators.begin(); it != m_Decorators.end(); ++it) { - cPlayer * Player = *it; - - UpdateRadius(*Player, DEFAULT_RADIUS); - - if (true) - { - NewList.insert(Player); - } + it->Update(); } - - std::swap(m_TrackedPlayers, NewList); } -void cMap::AddTrackedPlayer(cPlayer * a_Player) +void cMap::UpdateClient(cPlayer * a_Player) { ASSERT(a_Player != NULL); - m_TrackedPlayers.insert(a_Player); + cClientHandle * Handle = a_Player->GetClientHandle(); + + if (Handle == NULL) + { + return; + } + + Int64 WorldAge = a_Player->GetWorld()->GetWorldAge(); + + // Remove invalid clients + for (cMapClientList::iterator it = m_Clients.begin(); it != m_Clients.end();) + { + // Check if client is active + if (it->m_LastUpdate < WorldAge - 5) + { + // Remove associated decorators + for (cMapDecoratorList::iterator it2 = m_Decorators.begin(); it2 != m_Decorators.end();) + { + if (it2->GetPlayer()->GetClientHandle() == Handle) + { + // Erase decorator + cMapDecoratorList::iterator temp = it2; + ++it2; + m_Decorators.erase(temp); + } + else + { + ++it2; + } + } + + // Erase client + cMapClientList::iterator temp = it; + ++it; + m_Clients.erase(temp); + } + else + { + ++it; + } + } + + // Linear search for client state + for (cMapClientList::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it) + { + if (it->m_Handle == Handle) + { + it->m_LastUpdate = WorldAge; + + if (it->m_SendInfo) + { + Handle->SendMapInfo(m_ID, m_Scale); + + it->m_SendInfo = false; + + return; + } + + ++it->m_NextDecoratorUpdate; + + if (it->m_NextDecoratorUpdate >= 4) + { + UpdateDecorators(); + + Handle->SendMapDecorators(m_ID, m_Decorators); + + it->m_NextDecoratorUpdate = 0; + } + else + { + ++it->m_DataUpdate; + + unsigned int Y = (it->m_DataUpdate * 11) % m_Width; + + const Byte * Colors = &m_Data[Y * m_Height]; + + Handle->SendMapColumn(m_ID, Y, 0, Colors, m_Height); + } + + return; + } + } + + // New player, construct a new client state + cMapClient MapClient; + + MapClient.m_LastUpdate = WorldAge; + MapClient.m_SendInfo = true; + MapClient.m_Handle = a_Player->GetClientHandle(); + + m_Clients.push_back(MapClient); + + // Insert new decorator + cMapDecorator PlayerDecorator(this, a_Player); + + m_Decorators.push_back(PlayerDecorator); } @@ -267,6 +446,11 @@ void cMap::SetScale(unsigned int a_Scale) } m_Scale = a_Scale; + + for (cMapClientList::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it) + { + it->m_SendInfo = true; + } } @@ -283,6 +467,8 @@ void cMap::SendTo(cClientHandle & a_Client) a_Client.SendMapColumn(m_ID, i, 0, Colors, m_Height); } + + a_Client.SendMapDecorators(m_ID, m_Decorators); } diff --git a/src/Map.h b/src/Map.h index 805dfb845..76e459621 100644 --- a/src/Map.h +++ b/src/Map.h @@ -22,6 +22,55 @@ class cClientHandle; class cWorld; class cPlayer; +class cMap; + + + + + +class cMapDecorator +{ +public: + enum eType + { + E_TYPE_PLAYER = 0x00, + E_TYPE_ITEM_FRAME = 0x01, + E_TYPE_PLAYER_OUTSIDE = 0x06 + }; + + +public: + + cMapDecorator(cMap * a_Map, eType a_Type, int a_X, int a_Z, unsigned int a_Rot); + + cMapDecorator(cMap * a_Map, cPlayer * a_Player); + + void Update(void); + + unsigned int GetPixelX(void) const { return m_PixelX; } + unsigned int GetPixelZ(void) const { return m_PixelZ; } + unsigned int GetRot(void) const { return m_Rot; } + + eType GetType(void) const { return m_Type; } + + cPlayer * GetPlayer(void) { return m_Player; } + + +protected: + + cMap * m_Map; + + eType m_Type; + + unsigned int m_PixelX; + unsigned int m_PixelZ; + + unsigned int m_Rot; + + cPlayer * m_Player; +}; + +typedef std::list cMapDecoratorList; @@ -38,7 +87,19 @@ public: typedef std::vector cColorList; - static const unsigned int DEFAULT_RADIUS = 128; + struct cMapClient + { + cClientHandle * m_Handle; + + bool m_SendInfo; + + unsigned int m_NextDecoratorUpdate; + + Int64 m_DataUpdate; + Int64 m_LastUpdate; + }; + + typedef std::list cMapClientList; public: @@ -56,9 +117,8 @@ public: void UpdateRadius(cPlayer & a_Player, unsigned int a_Radius); - void UpdateTrackedPlayers(void); - - void AddTrackedPlayer(cPlayer * a_Player); + /** Send next update packet and remove invalid decorators */ + void UpdateClient(cPlayer * a_Player); // tolua_begin @@ -98,6 +158,9 @@ public: private: + /** Update the associated decorators. */ + void UpdateDecorators(void); + /** Update the specified pixel. */ bool UpdatePixel(unsigned int a_X, unsigned int a_Z); @@ -117,9 +180,9 @@ private: cWorld * m_World; - typedef std::set cTrackedPlayerList; + cMapDecoratorList m_Decorators; - cTrackedPlayerList m_TrackedPlayers; + cMapClientList m_Clients; AString m_Name; diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 5f89799e1..4a1601487 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -13,6 +13,7 @@ #include "../Defines.h" #include "../Endianness.h" #include "../Scoreboard.h" +#include "../Map.h" @@ -28,7 +29,6 @@ class cWorld; class cMonster; class cChunkDataSerializer; class cFallingBlock; -class cMap; @@ -81,6 +81,7 @@ public: virtual void SendKeepAlive (int a_PingID) = 0; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0; virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) = 0; + virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) = 0; virtual void SendMapInfo (int a_ID, unsigned int a_Scale) = 0; virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0; virtual void SendPlayerAbilities (void) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index edb22fae6..220fa18cf 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -602,6 +602,31 @@ void cProtocol125::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo +void cProtocol125::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators) +{ + cCSLock Lock(m_CSPacket); + + WriteByte (PACKET_ITEM_DATA); + WriteShort(E_ITEM_MAP); + WriteShort(a_ID); + WriteShort(1 + (3 * a_Decorators.size())); + + WriteByte(1); + + for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it) + { + WriteByte((it->GetType() << 4) | (it->GetRot() & 0xf)); + WriteByte(it->GetPixelX()); + WriteByte(it->GetPixelZ()); + } + + Flush(); +} + + + + + void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup) { diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 467aee002..1eeb15120 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -55,6 +55,7 @@ public: virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override; + virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override; virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override {} // This protocol doesn't support such message virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 4acc61586..38b4ed786 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -516,6 +516,26 @@ void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo +void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators) +{ + cPacketizer Pkt(*this, 0x34); + Pkt.WriteVarInt(a_ID); + Pkt.WriteShort (1 + (3 * a_Decorators.size())); + + Pkt.WriteByte(1); + + for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it) + { + Pkt.WriteByte((it->GetType() << 4) | (it->GetRot() & 0xf)); + Pkt.WriteByte(it->GetPixelX()); + Pkt.WriteByte(it->GetPixelZ()); + } +} + + + + + void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale) { cPacketizer Pkt(*this, 0x34); diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 0e50db45d..4edf51d2f 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -77,6 +77,7 @@ public: virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override; + virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override; virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendPlayerAbilities (void) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 447fa516b..0a9369c0d 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -396,6 +396,16 @@ void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * +void cProtocolRecognizer::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendMapDecorators(a_ID, a_Decorators); +} + + + + + void cProtocolRecognizer::SendMapInfo(int a_ID, unsigned int a_Scale) { ASSERT(m_Protocol != NULL); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 3c37d5138..ff4549ff5 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -90,6 +90,7 @@ public: virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override; + virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override; virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override; virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) override;