From 92e85cc96030285bba74837759925866c1be7235 Mon Sep 17 00:00:00 2001
From: andrew
Date: Thu, 13 Feb 2014 17:13:09 +0200
Subject: Implementation of in-game maps
---
src/ClientHandle.cpp | 18 ++++
src/ClientHandle.h | 2 +
src/Map.cpp | 149 ++++++++++++++++++++++++++++
src/Map.h | 95 ++++++++++++++++++
src/Protocol/Protocol.h | 3 +
src/Protocol/Protocol125.cpp | 27 ++++++
src/Protocol/Protocol125.h | 2 +
src/Protocol/Protocol17x.cpp | 35 +++++++
src/Protocol/Protocol17x.h | 2 +
src/Protocol/ProtocolRecognizer.cpp | 20 ++++
src/Protocol/ProtocolRecognizer.h | 2 +
src/WorldStorage/MapSerializer.cpp | 189 ++++++++++++++++++++++++++++++++++++
src/WorldStorage/MapSerializer.h | 52 ++++++++++
13 files changed, 596 insertions(+)
create mode 100644 src/Map.cpp
create mode 100644 src/Map.h
create mode 100644 src/WorldStorage/MapSerializer.cpp
create mode 100644 src/WorldStorage/MapSerializer.h
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 1b3ebc3d4..8e44a61fd 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -2057,6 +2057,24 @@ void cClientHandle::SendInventorySlot(char a_WindowID, short a_SlotNum, const cI
+void cClientHandle::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
+{
+ m_Protocol->SendMapColumn(a_ID, a_X, a_Y, a_Colors, a_Length);
+}
+
+
+
+
+
+void cClientHandle::SendMapInfo(int a_ID, unsigned int a_Scale)
+{
+ m_Protocol->SendMapInfo(a_ID, a_Scale);
+}
+
+
+
+
+
void cClientHandle::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)
{
m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount);
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index d9a86d983..b1f13954b 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -109,6 +109,8 @@ public:
void SendGameMode (eGameMode a_GameMode);
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) override;
+ void SendMapInfo (int a_ID, unsigned int a_Scale) override;
void SendPickupSpawn (const cPickup & a_Pickup);
void SendEntityAnimation (const cEntity & a_Entity, char a_Animation);
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);
diff --git a/src/Map.cpp b/src/Map.cpp
new file mode 100644
index 000000000..f1b690698
--- /dev/null
+++ b/src/Map.cpp
@@ -0,0 +1,149 @@
+
+// Map.cpp
+
+#include "Globals.h"
+
+#include "Map.h"
+
+#include "ClientHandle.h"
+#include "World.h"
+
+
+
+
+
+cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale)
+ : m_ID(a_ID)
+ , m_Width(128)
+ , m_Height(128)
+ , m_Scale(a_Scale)
+ , m_CenterX(a_CenterX)
+ , m_CenterZ(a_CenterZ)
+ , m_World(a_World)
+{
+ m_Data.assign(m_Width * m_Height, 0);
+
+ UpdateMap();
+}
+
+
+
+
+
+void cMap::UpdateMap(void)
+{
+ // ASSERT(m_World != NULL);
+
+ // TODO
+
+ for (unsigned int X = 0; X < m_Width; ++X)
+ {
+ for (unsigned int Y = 0; Y < m_Height; ++Y)
+ {
+ // Debug
+ m_Data[Y + X * m_Height] = rand() % 100;
+ }
+ }
+}
+
+
+
+
+
+eDimension cMap::GetDimension(void) const
+{
+ ASSERT(m_World != NULL);
+ return m_World->GetDimension();
+}
+
+
+
+
+
+
+void cMap::Resize(unsigned int a_Width, unsigned int a_Height)
+{
+ if ((m_Width == a_Width) && (m_Height == a_Height))
+ {
+ return;
+ }
+
+ m_Width = a_Width;
+ m_Height = a_Height;
+
+ m_Data.assign(m_Width * m_Height, 0);
+
+ UpdateMap();
+}
+
+
+
+
+
+void cMap::SetPosition(int a_CenterX, int a_CenterZ)
+{
+ if ((m_CenterX == a_CenterX) && (m_CenterZ == a_CenterZ))
+ {
+ return;
+ }
+
+ m_CenterX = a_CenterX;
+ m_CenterZ = a_CenterZ;
+
+ UpdateMap();
+}
+
+
+
+
+
+void cMap::SetScale(unsigned int a_Scale)
+{
+ if (m_Scale == a_Scale)
+ {
+ return;
+ }
+
+ m_Scale = a_Scale;
+
+ UpdateMap();
+}
+
+
+
+
+
+void cMap::SendTo(cClientHandle & a_Client)
+{
+ a_Client.SendMapInfo(m_ID, m_Scale);
+
+ for (unsigned int i = 0; i < m_Width; ++i)
+ {
+ const Byte* Colors = &m_Data[i * m_Height];
+
+ a_Client.SendMapColumn(m_ID, i, 0, Colors, m_Height);
+ }
+}
+
+
+
+
+
+unsigned int cMap::GetNumPixels(void) const
+{
+ return m_Width * m_Height;
+}
+
+
+
+
+
+unsigned int cMap::GetNumBlocksPerPixel(void) const
+{
+ return pow(2, m_Scale);
+}
+
+
+
+
+
diff --git a/src/Map.h b/src/Map.h
new file mode 100644
index 000000000..80bbd4ab4
--- /dev/null
+++ b/src/Map.h
@@ -0,0 +1,95 @@
+
+// Map.h
+
+// Implementation of in-game coloured maps
+
+
+
+
+
+#pragma once
+
+
+
+
+
+#include "BlockID.h"
+
+
+
+
+
+class cClientHandle;
+class cWorld;
+
+
+
+
+
+class cMap
+{
+public:
+
+ typedef Byte ColorID;
+
+ typedef std::vector cColorList;
+
+
+public:
+
+ cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale = 3);
+
+ /** Update the map (Query the world) */
+ void UpdateMap(void);
+
+ /** Send this map to the specified client. */
+ void SendTo(cClientHandle & a_Client);
+
+ void Resize(unsigned int a_Width, unsigned int a_Height);
+
+ void SetPosition(int a_CenterX, int a_CenterZ);
+
+ void SetScale(unsigned int a_Scale);
+
+ unsigned int GetWidth (void) const { return m_Width; }
+ unsigned int GetHeight(void) const { return m_Height; }
+
+ unsigned int GetScale(void) const { return m_Scale; }
+
+ int GetCenterX(void) const { return m_CenterX; }
+ int GetCenterZ(void) const { return m_CenterZ; }
+
+ unsigned int GetID(void) const { return m_ID; }
+
+ cWorld * GetWorld(void) { return m_World; }
+
+ eDimension GetDimension(void) const;
+
+ const cColorList & GetData(void) const { return m_Data; }
+
+ unsigned int GetNumPixels(void) const;
+
+ unsigned int GetNumBlocksPerPixel(void) const;
+
+
+private:
+
+ unsigned int m_ID;
+
+ unsigned int m_Width;
+ unsigned int m_Height;
+
+ /** The zoom level, 2^scale square blocks per pixel */
+ unsigned int m_Scale;
+
+ int m_CenterX;
+ int m_CenterZ;
+
+ /** Column-major array of colours */
+ cColorList m_Data;
+
+ cWorld * m_World;
+
+ friend class cMapSerializer;
+
+};
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 791082537..5f89799e1 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -28,6 +28,7 @@ class cWorld;
class cMonster;
class cChunkDataSerializer;
class cFallingBlock;
+class cMap;
@@ -79,6 +80,8 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0;
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 SendMapInfo (int a_ID, unsigned int a_Scale) = 0;
virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0;
virtual void SendPlayerAbilities (void) = 0;
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0;
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 73d21161c..edb22fae6 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -95,6 +95,7 @@ enum
PACKET_WINDOW_PROPERTY = 0x69,
PACKET_CREATIVE_INVENTORY_ACTION = 0x6B,
PACKET_UPDATE_SIGN = 0x82,
+ PACKET_ITEM_DATA = 0x83,
PACKET_PLAYER_LIST_ITEM = 0xC9,
PACKET_PLAYER_ABILITIES = 0xca,
PACKET_PLUGIN_MESSAGE = 0xfa,
@@ -576,6 +577,32 @@ void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
+void cProtocol125::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
+{
+ cCSLock Lock(m_CSPacket);
+
+ WriteByte (PACKET_ITEM_DATA);
+ WriteShort(E_ITEM_MAP);
+ WriteShort(a_ID);
+ WriteShort(3 + a_Length);
+
+ WriteByte(0);
+ WriteByte(a_X);
+ WriteByte(a_Y);
+
+ for (unsigned int i = 0; i < a_Length; ++i)
+ {
+ WriteByte(a_Colors[i]);
+ }
+
+ Flush();
+}
+
+
+
+
+
+
void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup)
{
cCSLock Lock(m_CSPacket);
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index cd15ab518..467aee002 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -54,6 +54,8 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
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 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;
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 7eaf106cf..4acc61586 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -496,6 +496,41 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
+void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
+{
+ cPacketizer Pkt(*this, 0x34);
+ Pkt.WriteVarInt(a_ID);
+ Pkt.WriteShort (3 + a_Length);
+
+ Pkt.WriteByte(0);
+ Pkt.WriteByte(a_X);
+ Pkt.WriteByte(a_Y);
+
+ for (unsigned int i = 0; i < a_Length; ++i)
+ {
+ Pkt.WriteByte(a_Colors[i]);
+ }
+}
+
+
+
+
+
+void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale)
+{
+ cPacketizer Pkt(*this, 0x34);
+ Pkt.WriteVarInt(a_ID);
+ Pkt.WriteShort (2);
+
+ Pkt.WriteByte(2);
+ Pkt.WriteByte(a_Scale);
+}
+
+
+
+
+
+
void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
{
{
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 6a75e41c8..0e50db45d 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -76,6 +76,8 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
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 SendMapInfo (int a_ID, unsigned int a_Scale) override;
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override;
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 32409c2aa..447fa516b 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -386,6 +386,26 @@ void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_W
+void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
+{
+ ASSERT(m_Protocol != NULL);
+ m_Protocol->SendMapColumn(a_ID, a_X, a_Y, a_Colors, a_Length);
+}
+
+
+
+
+
+void cProtocolRecognizer::SendMapInfo(int a_ID, unsigned int a_Scale)
+{
+ ASSERT(m_Protocol != NULL);
+ m_Protocol->SendMapInfo(a_ID, a_Scale);
+}
+
+
+
+
+
void cProtocolRecognizer::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)
{
ASSERT(m_Protocol != NULL);
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index f58c66d10..3c37d5138 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -89,6 +89,8 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
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 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;
virtual void SendPlayerAbilities (void) override;
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
new file mode 100644
index 000000000..ea0d3ec47
--- /dev/null
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -0,0 +1,189 @@
+
+// MapSerializer.cpp
+
+
+#include "Globals.h"
+#include "MapSerializer.h"
+#include "../StringCompression.h"
+#include "zlib/zlib.h"
+#include "FastNBT.h"
+
+#include "../Map.h"
+
+
+
+
+
+cMapSerializer::cMapSerializer(const AString& a_WorldName, cMap * a_Map)
+ : m_Map(a_Map)
+{
+ AString DataPath;
+ Printf(DataPath, "%s/data", a_WorldName.c_str());
+
+ Printf(m_Path, "%s/map_%i.dat", DataPath.c_str(), a_Map->GetID());
+
+ cFile::CreateFolder(FILE_IO_PREFIX + DataPath);
+}
+
+
+
+
+
+bool cMapSerializer::Load(void)
+{
+ AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path);
+ if (Data.empty())
+ {
+ return false;
+ }
+
+ AString Uncompressed;
+ int res = UncompressStringGZIP(Data.data(), Data.size(), Uncompressed);
+
+ if (res != Z_OK)
+ {
+ return false;
+ }
+
+ // Parse the NBT data:
+ cParsedNBT NBT(Uncompressed.data(), Uncompressed.size());
+ if (!NBT.IsValid())
+ {
+ // NBT Parsing failed
+ return false;
+ }
+
+ return LoadMapFromNBT(NBT);
+}
+
+
+
+
+
+bool cMapSerializer::Save(void)
+{
+ cFastNBTWriter Writer;
+
+ SaveMapToNBT(Writer);
+
+ Writer.Finish();
+
+ #ifdef _DEBUG
+ cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size());
+ ASSERT(TestParse.IsValid());
+ #endif // _DEBUG
+
+ cFile File;
+ if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite))
+ {
+ return false;
+ }
+
+ AString Compressed;
+ int res = CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
+
+ if (res != Z_OK)
+ {
+ return false;
+ }
+
+ File.Write(Compressed.data(), Compressed.size());
+ File.Close();
+
+ return true;
+}
+
+
+
+
+
+void cMapSerializer::SaveMapToNBT(cFastNBTWriter & a_Writer)
+{
+ a_Writer.BeginCompound("data");
+
+ a_Writer.AddByte("scale", m_Map->GetScale());
+ a_Writer.AddByte("dimension", (int) m_Map->GetDimension());
+
+ a_Writer.AddShort("width", m_Map->GetWidth());
+ a_Writer.AddShort("height", m_Map->GetHeight());
+
+ a_Writer.AddInt("xCenter", m_Map->GetCenterX());
+ a_Writer.AddInt("zCenter", m_Map->GetCenterZ());
+
+ // Potential bug - The internal representation may change
+ const cMap::cColorList & Data = m_Map->GetData();
+ a_Writer.AddByteArray("colors", (char *) Data.data(), Data.size());
+
+ a_Writer.EndCompound();
+}
+
+
+
+
+
+bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
+{
+ int Data = a_NBT.FindChildByName(0, "data");
+ if (Data < 0)
+ {
+ return false;
+ }
+
+ int CurrLine = a_NBT.FindChildByName(Data, "scale");
+ if (CurrLine >= 0)
+ {
+ unsigned int Scale = a_NBT.GetByte(CurrLine);
+ m_Map->m_Scale = Scale;
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "dimension");
+ if (CurrLine >= 0)
+ {
+ eDimension Dimension = (eDimension) a_NBT.GetByte(CurrLine);
+
+ // ASSERT(Dimension == m_World.GetDimension());
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "width");
+ if (CurrLine >= 0)
+ {
+ unsigned int Width = a_NBT.GetShort(CurrLine);
+ m_Map->m_Width = Width;
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "height");
+ if (CurrLine >= 0)
+ {
+ unsigned int Height = a_NBT.GetShort(CurrLine);
+ m_Map->m_Height = Height;
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "xCenter");
+ if (CurrLine >= 0)
+ {
+ int CenterX = a_NBT.GetInt(CurrLine);
+ m_Map->m_CenterX = CenterX;
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "zCenter");
+ if (CurrLine >= 0)
+ {
+ int CenterZ = a_NBT.GetInt(CurrLine);
+ m_Map->m_CenterZ = CenterZ;
+ }
+
+ unsigned int NumPixels = m_Map->GetNumPixels();
+ m_Map->m_Data.resize(NumPixels);
+
+ // TODO xdot: Parse the byte array.
+
+ return true;
+}
+
+
+
+
+
+
+
+
diff --git a/src/WorldStorage/MapSerializer.h b/src/WorldStorage/MapSerializer.h
new file mode 100644
index 000000000..71791a2fb
--- /dev/null
+++ b/src/WorldStorage/MapSerializer.h
@@ -0,0 +1,52 @@
+
+// MapSerializer.h
+
+// Declares the cMapSerializer class that is used for saving maps into NBT format used by Anvil
+
+
+
+
+
+#pragma once
+
+
+
+
+
+// fwd:
+class cFastNBTWriter;
+class cParsedNBT;
+class cMap;
+
+
+
+
+class cMapSerializer
+{
+public:
+
+ cMapSerializer(const AString& a_WorldName, cMap * a_Map);
+
+ /// Try to load the scoreboard
+ bool Load(void);
+
+ /// Try to save the scoreboard
+ bool Save(void);
+
+
+private:
+
+ void SaveMapToNBT(cFastNBTWriter & a_Writer);
+
+ bool LoadMapFromNBT(const cParsedNBT & a_NBT);
+
+ cMap * m_Map;
+
+ AString m_Path;
+
+
+} ;
+
+
+
+
--
cgit v1.2.3
From 32b465b8e1e1a6fa9e966a1376209f292331d4ae Mon Sep 17 00:00:00 2001
From: andrew
Date: Thu, 13 Feb 2014 21:36:24 +0200
Subject: IDCount Serialization
---
src/ClientHandle.h | 4 +-
src/Map.cpp | 18 +++++++++
src/Map.h | 3 ++
src/World.cpp | 54 ++++++++++++++++++++++++++
src/World.h | 11 ++++++
src/WorldStorage/MapSerializer.cpp | 79 +++++++++++++++++++++++++++++++++++++-
src/WorldStorage/MapSerializer.h | 25 ++++++++++++
7 files changed, 191 insertions(+), 3 deletions(-)
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index b1f13954b..a714cf8b9 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -109,8 +109,8 @@ public:
void SendGameMode (eGameMode a_GameMode);
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) override;
- void SendMapInfo (int a_ID, unsigned int a_Scale) override;
+ void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length);
+ void SendMapInfo (int a_ID, unsigned int a_Scale);
void SendPickupSpawn (const cPickup & a_Pickup);
void SendEntityAnimation (const cEntity & a_Entity, char a_Animation);
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);
diff --git a/src/Map.cpp b/src/Map.cpp
index f1b690698..f99b01752 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -12,6 +12,24 @@
+cMap::cMap(unsigned int a_ID, cWorld * a_World)
+ : m_ID(a_ID)
+ , m_Width(128)
+ , m_Height(128)
+ , m_Scale(3)
+ , m_CenterX(0)
+ , m_CenterZ(0)
+ , m_World(a_World)
+{
+ m_Data.assign(m_Width * m_Height, 0);
+
+ // Do not update map
+}
+
+
+
+
+
cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale)
: m_ID(a_ID)
, m_Width(128)
diff --git a/src/Map.h b/src/Map.h
index 80bbd4ab4..dbb15afdd 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -37,6 +37,9 @@ public:
public:
+ /// Construct an empty map
+ cMap(unsigned int a_ID, cWorld * a_World);
+
cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale = 3);
/** Update the map (Query the world) */
diff --git a/src/World.cpp b/src/World.cpp
index f8c1091f0..a308778df 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -11,7 +11,9 @@
#include "ChunkMap.h"
#include "Generating/ChunkDesc.h"
#include "OSSupport/Timer.h"
+
#include "WorldStorage/ScoreboardSerializer.h"
+#include "WorldStorage/MapSerializer.h"
// Entities (except mobs):
#include "Entities/ExpOrb.h"
@@ -261,6 +263,8 @@ cWorld::cWorld(const AString & a_WorldName) :
// Load the scoreboard
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
Serializer.Load();
+
+ LoadMapData();
}
@@ -284,6 +288,8 @@ cWorld::~cWorld()
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
Serializer.Save();
+ SaveMapData();
+
delete m_ChunkMap;
}
@@ -2945,6 +2951,54 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
+
+void cWorld::LoadMapData(void)
+{
+ cIDCountSerializer IDSerializer(GetName());
+
+ IDSerializer.Load();
+
+ unsigned int MapCount = IDSerializer.GetMapCount();
+
+ m_MapData.clear();
+
+ for (unsigned int i = 0; i < MapCount; ++i)
+ {
+ cMap Map(i, this);
+
+ cMapSerializer Serializer(GetName(), &Map);
+
+ Serializer.Load();
+
+ m_MapData.push_back(Map);
+ }
+}
+
+
+
+
+
+void cWorld::SaveMapData(void)
+{
+ cIDCountSerializer IDSerializer(GetName());
+
+ IDSerializer.SetMapCount(m_MapData.size());
+
+ IDSerializer.Save();
+
+ for (cMapList::iterator it = m_MapData.begin(); it != m_MapData.end(); ++it)
+ {
+ cMap & Map = *it;
+
+ cMapSerializer Serializer(GetName(), &Map);
+
+ Serializer.Save();
+ }
+}
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cWorld::cTaskSaveAllChunks:
diff --git a/src/World.h b/src/World.h
index fa83fe73e..02e56a247 100644
--- a/src/World.h
+++ b/src/World.h
@@ -24,6 +24,7 @@
#include "Entities/ProjectileEntity.h"
#include "ForEachChunkProvider.h"
#include "Scoreboard.h"
+#include "Map.h"
#include "Blocks/WorldInterface.h"
#include "Blocks/BroadcastInterface.h"
@@ -811,6 +812,10 @@ private:
cChunkGenerator m_Generator;
cScoreboard m_Scoreboard;
+
+ typedef std::vector cMapList;
+
+ cMapList m_MapData;
/** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
cChunkGeneratorCallbacks m_GeneratorCallbacks;
@@ -876,6 +881,12 @@ private:
/** Creates a new redstone simulator.*/
cRedstoneSimulator * InitializeRedstoneSimulator(cIniFile & a_IniFile);
+
+ /** Loads the map data from the disk */
+ void LoadMapData(void);
+
+ /** Saves the map data to the disk */
+ void SaveMapData(void);
}; // tolua_export
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
index ea0d3ec47..aab4c7816 100644
--- a/src/WorldStorage/MapSerializer.cpp
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -9,6 +9,7 @@
#include "FastNBT.h"
#include "../Map.h"
+#include "../World.h"
@@ -141,7 +142,7 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
{
eDimension Dimension = (eDimension) a_NBT.GetByte(CurrLine);
- // ASSERT(Dimension == m_World.GetDimension());
+ ASSERT(Dimension == m_Map->m_World->GetDimension());
}
CurrLine = a_NBT.FindChildByName(Data, "width");
@@ -184,6 +185,82 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
+cIDCountSerializer::cIDCountSerializer(const AString & a_WorldName) : m_MapCount(0)
+{
+ AString DataPath;
+ Printf(DataPath, "%s/data", a_WorldName.c_str());
+
+ Printf(m_Path, "%s/idcounts.dat", DataPath.c_str());
+
+ cFile::CreateFolder(FILE_IO_PREFIX + DataPath);
+}
+
+
+
+
+
+bool cIDCountSerializer::Load(void)
+{
+ AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path);
+ if (Data.empty())
+ {
+ return false;
+ }
+
+ // NOTE: idcounts.dat is not compressed (raw format)
+
+ // Parse the NBT data:
+ cParsedNBT NBT(Data.data(), Data.size());
+ if (!NBT.IsValid())
+ {
+ // NBT Parsing failed
+ return false;
+ }
+
+ int CurrLine = NBT.FindChildByName(0, "map");
+ if (CurrLine >= 0)
+ {
+ m_MapCount = (int)NBT.GetShort(CurrLine);
+ }
+
+ return true;
+}
+
+
+
+
+
+bool cIDCountSerializer::Save(void)
+{
+ cFastNBTWriter Writer;
+
+ Writer.AddShort("map", m_MapCount);
+
+ Writer.Finish();
+
+ #ifdef _DEBUG
+ cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size());
+ ASSERT(TestParse.IsValid());
+ #endif // _DEBUG
+
+ cFile File;
+ if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite))
+ {
+ return false;
+ }
+
+ // NOTE: idcounts.dat is not compressed (raw format)
+
+ File.Write(Writer.GetResult().data(), Writer.GetResult().size());
+ File.Close();
+
+ return true;
+}
+
+
+
+
+
diff --git a/src/WorldStorage/MapSerializer.h b/src/WorldStorage/MapSerializer.h
index 71791a2fb..d9da107bc 100644
--- a/src/WorldStorage/MapSerializer.h
+++ b/src/WorldStorage/MapSerializer.h
@@ -50,3 +50,28 @@ private:
+class cIDCountSerializer
+{
+public:
+
+ cIDCountSerializer(const AString & a_WorldName);
+
+ bool Load(void);
+
+ bool Save(void);
+
+ inline unsigned int GetMapCount(void) const { return m_MapCount; }
+
+ inline void SetMapCount(unsigned int a_MapCount) { m_MapCount = a_MapCount; }
+
+
+private:
+
+ AString m_Path;
+
+ unsigned int m_MapCount;
+};
+
+
+
+
--
cgit v1.2.3
From 5b92b877bcc0c5072dbea98b6c54106f954aa758 Mon Sep 17 00:00:00 2001
From: andrew
Date: Fri, 14 Feb 2014 16:21:16 +0200
Subject: Send map when selected
---
src/Bindings/AllToLua.pkg | 1 +
src/ClientHandle.cpp | 13 +++++++++++
src/Map.cpp | 47 +++++++++++++++++++++++---------------
src/Map.h | 20 ++++++++++++----
src/World.cpp | 45 ++++++++++++++++++++++++++++++++++--
src/World.h | 6 +++++
src/WorldStorage/MapSerializer.cpp | 9 +++++---
7 files changed, 114 insertions(+), 27 deletions(-)
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index f65aed9bb..335acff95 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -47,6 +47,7 @@ $cfile "../ItemGrid.h"
$cfile "../BlockEntities/BlockEntity.h"
$cfile "../BlockEntities/BlockEntityWithItems.h"
$cfile "../BlockEntities/ChestEntity.h"
+$cfile "../BlockEntities/CommandBlockEntity.h"
$cfile "../BlockEntities/DropSpenserEntity.h"
$cfile "../BlockEntities/DispenserEntity.h"
$cfile "../BlockEntities/DropperEntity.h"
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 8e44a61fd..a2cbaefff 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1190,6 +1190,19 @@ 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);
+ }
+ }
}
diff --git a/src/Map.cpp b/src/Map.cpp
index f99b01752..4acd9512c 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -7,6 +7,7 @@
#include "ClientHandle.h"
#include "World.h"
+#include "Chunk.h"
@@ -22,8 +23,6 @@ cMap::cMap(unsigned int a_ID, cWorld * a_World)
, m_World(a_World)
{
m_Data.assign(m_Width * m_Height, 0);
-
- // Do not update map
}
@@ -41,27 +40,45 @@ cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, un
{
m_Data.assign(m_Width * m_Height, 0);
- UpdateMap();
+ for (unsigned int X = 0; X < m_Width; ++X)
+ {
+ for (unsigned int Y = 0; Y < m_Height; ++Y)
+ {
+ // Debug
+ m_Data[Y + X * m_Height] = rand() % 100;
+ }
+ }
}
-void cMap::UpdateMap(void)
+bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Y)
{
- // ASSERT(m_World != NULL);
+ ASSERT(m_World != NULL);
- // TODO
+ cChunk * Chunk = NULL;
- for (unsigned int X = 0; X < m_Width; ++X)
+ if (Chunk == NULL)
{
- for (unsigned int Y = 0; Y < m_Height; ++Y)
- {
- // Debug
- m_Data[Y + X * m_Height] = rand() % 100;
- }
+ return false;
}
+
+ int Height = Chunk->GetHeight(a_X, a_Y);
+
+ // TODO
+
+ return true;
+}
+
+
+
+
+
+void cMap::EraseData(void)
+{
+ m_Data.assign(m_Width * m_Height, 0);
}
@@ -90,8 +107,6 @@ void cMap::Resize(unsigned int a_Width, unsigned int a_Height)
m_Height = a_Height;
m_Data.assign(m_Width * m_Height, 0);
-
- UpdateMap();
}
@@ -107,8 +122,6 @@ void cMap::SetPosition(int a_CenterX, int a_CenterZ)
m_CenterX = a_CenterX;
m_CenterZ = a_CenterZ;
-
- UpdateMap();
}
@@ -123,8 +136,6 @@ void cMap::SetScale(unsigned int a_Scale)
}
m_Scale = a_Scale;
-
- UpdateMap();
}
diff --git a/src/Map.h b/src/Map.h
index dbb15afdd..c443445de 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -26,28 +26,33 @@ class cWorld;
+// tolua_begin
class cMap
{
public:
typedef Byte ColorID;
+ // tolua_end
+
typedef std::vector cColorList;
public:
- /// Construct an empty map
+ /** Construct an empty map. */
cMap(unsigned int a_ID, cWorld * a_World);
cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale = 3);
- /** Update the map (Query the world) */
- void UpdateMap(void);
-
/** Send this map to the specified client. */
void SendTo(cClientHandle & a_Client);
+ // tolua_begin
+
+ /** Erase pixel data */
+ void EraseData(void);
+
void Resize(unsigned int a_Width, unsigned int a_Height);
void SetPosition(int a_CenterX, int a_CenterZ);
@@ -74,9 +79,16 @@ public:
unsigned int GetNumBlocksPerPixel(void) const;
+ // tolua_end
+
private:
+ /** Update the specified pixel. */
+ bool UpdatePixel(unsigned int a_X, unsigned int a_Y);
+
+ void PixelToWorldCoords(unsigned int a_X, unsigned int a_Y, int & a_WorldX, int & a_WorldY);
+
unsigned int m_ID;
unsigned int m_Width;
diff --git a/src/World.cpp b/src/World.cpp
index a308778df..2a3e53332 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1554,6 +1554,42 @@ bool cWorld::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock
+cMap * cWorld::GetMapData(unsigned int a_ID)
+{
+ if (a_ID < m_MapData.size())
+ {
+ return &m_MapData[a_ID];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+
+
+
+cMap * cWorld::CreateMap(int a_CenterX, int a_CenterY, int a_Scale)
+{
+ if (m_MapData.size() >= 65536)
+ {
+ LOGD("cWorld::CreateMap - Too many maps in use");
+
+ return NULL;
+ }
+
+ cMap Map(m_MapData.size(), a_CenterX, a_CenterY, this, a_Scale);
+
+ m_MapData.push_back(Map);
+
+ return &m_MapData[Map.GetID()];
+}
+
+
+
+
+
void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed, bool IsPlayerCreated)
{
MTRand r1;
@@ -2958,7 +2994,7 @@ void cWorld::LoadMapData(void)
IDSerializer.Load();
- unsigned int MapCount = IDSerializer.GetMapCount();
+ unsigned int MapCount = IDSerializer.GetMapCount() + 1;
m_MapData.clear();
@@ -2980,9 +3016,14 @@ void cWorld::LoadMapData(void)
void cWorld::SaveMapData(void)
{
+ if (m_MapData.empty())
+ {
+ return;
+ }
+
cIDCountSerializer IDSerializer(GetName());
- IDSerializer.SetMapCount(m_MapData.size());
+ IDSerializer.SetMapCount(m_MapData.size() - 1);
IDSerializer.Save();
diff --git a/src/World.h b/src/World.h
index 02e56a247..a9b1ca2cb 100644
--- a/src/World.h
+++ b/src/World.h
@@ -552,6 +552,12 @@ public:
bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; }
void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; }
+
+ /** Returns the map with the specified ID, NULL if out of range. */
+ cMap * GetMapData(unsigned int a_ID);
+
+ /** Creates a new map. Returns NULL on error */
+ cMap * CreateMap(int a_CenterX, int a_CenterY, int a_Scale = 3);
// tolua_end
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
index aab4c7816..6dab19d4f 100644
--- a/src/WorldStorage/MapSerializer.cpp
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -111,7 +111,6 @@ void cMapSerializer::SaveMapToNBT(cFastNBTWriter & a_Writer)
a_Writer.AddInt("xCenter", m_Map->GetCenterX());
a_Writer.AddInt("zCenter", m_Map->GetCenterZ());
- // Potential bug - The internal representation may change
const cMap::cColorList & Data = m_Map->GetData();
a_Writer.AddByteArray("colors", (char *) Data.data(), Data.size());
@@ -134,7 +133,7 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
if (CurrLine >= 0)
{
unsigned int Scale = a_NBT.GetByte(CurrLine);
- m_Map->m_Scale = Scale;
+ m_Map->SetScale(Scale);
}
CurrLine = a_NBT.FindChildByName(Data, "dimension");
@@ -176,7 +175,11 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
unsigned int NumPixels = m_Map->GetNumPixels();
m_Map->m_Data.resize(NumPixels);
- // TODO xdot: Parse the byte array.
+ CurrLine = a_NBT.FindChildByName(Data, "colors");
+ if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_ByteArray))
+ {
+ memcpy(m_Map->m_Data.data(), a_NBT.GetData(CurrLine), NumPixels);
+ }
return true;
}
--
cgit v1.2.3
From c7fb00085854ed76b8b8945968de0505b8fbe8a2 Mon Sep 17 00:00:00 2001
From: andrew
Date: Fri, 14 Feb 2014 17:38:22 +0200
Subject: EmptyMap item handler
---
MCServer/crafting.txt | 2 +-
src/Items/ItemEmptyMap.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
src/Items/ItemHandler.cpp | 2 ++
src/Map.cpp | 8 ++++----
4 files changed, 53 insertions(+), 5 deletions(-)
create mode 100644 src/Items/ItemEmptyMap.h
diff --git a/MCServer/crafting.txt b/MCServer/crafting.txt
index fe9a465d0..92abe24cb 100644
--- a/MCServer/crafting.txt
+++ b/MCServer/crafting.txt
@@ -156,7 +156,7 @@ Lighter = IronIngot, 1:1 | Flint, 2:2
Lighter = IronIngot, 2:1 | Flint, 1:2
Bucket = IronIngot, 1:1, 2:2, 3:1
Compass = IronIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
-Map = Paper, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Compass, 2:2
+EmptyMap = Paper, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Compass, 2:2
Watch = GoldIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
FishingRod = Stick, 1:3, 2:2, 3:1 | String, 3:2, 3:3
FishingRod = Stick, 3:3, 2:2, 1:1 | String, 1:2, 1:3
diff --git a/src/Items/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h
new file mode 100644
index 000000000..5516033a0
--- /dev/null
+++ b/src/Items/ItemEmptyMap.h
@@ -0,0 +1,46 @@
+
+// ItemEmptyMap.h
+
+
+
+
+
+#pragma once
+
+#include "../Entities/Entity.h"
+#include "../Item.h"
+
+
+
+
+
+class cItemEmptyMapHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemEmptyMapHandler() :
+ super(E_ITEM_EMPTY_MAP)
+ {
+ }
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
+ {
+ UNUSED(a_Item);
+ UNUSED(a_BlockX);
+ UNUSED(a_BlockZ);
+ UNUSED(a_Dir);
+
+ // The map center is fixed at the central point of the 8x8 block of chunks you are standing in when you right-click it.
+
+ const int RegionWidth = cChunkDef::Width * 8;
+
+ int CenterX = round(a_Player->GetPosX() / (float) RegionWidth) * RegionWidth;
+ int CenterZ = round(a_Player->GetPosZ() / (float) RegionWidth) * RegionWidth;
+
+ a_World->CreateMap(CenterX, CenterZ, 0);
+
+ return true;
+ }
+} ;
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 19913ab24..755766d64 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -18,6 +18,7 @@
#include "ItemComparator.h"
#include "ItemDoor.h"
#include "ItemDye.h"
+#include "ItemEmptyMap.h"
#include "ItemFishingRod.h"
#include "ItemFlowerPot.h"
#include "ItemFood.h"
@@ -100,6 +101,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType);
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
case E_ITEM_EGG: return new cItemEggHandler();
+ case E_ITEM_EMPTY_MAP: return new cItemEmptyMapHandler();
case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler();
case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler();
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
diff --git a/src/Map.cpp b/src/Map.cpp
index 4acd9512c..497cc9659 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -15,8 +15,8 @@
cMap::cMap(unsigned int a_ID, cWorld * a_World)
: m_ID(a_ID)
- , m_Width(128)
- , m_Height(128)
+ , m_Width(cChunkDef::Width * 8)
+ , m_Height(cChunkDef::Width * 8)
, m_Scale(3)
, m_CenterX(0)
, m_CenterZ(0)
@@ -31,8 +31,8 @@ cMap::cMap(unsigned int a_ID, cWorld * a_World)
cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale)
: m_ID(a_ID)
- , m_Width(128)
- , m_Height(128)
+ , m_Width(cChunkDef::Width * 8)
+ , m_Height(cChunkDef::Width * 8)
, m_Scale(a_Scale)
, m_CenterX(a_CenterX)
, m_CenterZ(a_CenterZ)
--
cgit v1.2.3
From cf96e69716e0ccd0657cf275720bb11b915361c4 Mon Sep 17 00:00:00 2001
From: andrew
Date: Sat, 15 Feb 2014 20:06:47 +0200
Subject: cMap::UpdateRadius
---
src/ClientHandle.cpp | 2 +
src/Items/ItemEmptyMap.h | 6 ++-
src/Map.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++-----
src/Map.h | 17 +++++--
4 files changed, 121 insertions(+), 16 deletions(-)
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index a2cbaefff..ff8775771 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1199,6 +1199,8 @@ void cClientHandle::HandleSlotSelected(short a_SlotNum)
if (Map != NULL)
{
+ Map->UpdateRadius(*m_Player, 128); // Temporary
+
// TODO 2014-02-14 xdot: Optimization - Do not send the whole map.
Map->SendTo(*this);
}
diff --git a/src/Items/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h
index 5516033a0..24d31151b 100644
--- a/src/Items/ItemEmptyMap.h
+++ b/src/Items/ItemEmptyMap.h
@@ -18,6 +18,8 @@ class cItemEmptyMapHandler :
public cItemHandler
{
typedef cItemHandler super;
+
+ static const unsigned int DEFAULT_SCALE = 0;
public:
cItemEmptyMapHandler() :
@@ -34,12 +36,12 @@ public:
// The map center is fixed at the central point of the 8x8 block of chunks you are standing in when you right-click it.
- const int RegionWidth = cChunkDef::Width * 8;
+ const int RegionWidth = cChunkDef::Width * 8 * pow(2, DEFAULT_SCALE);
int CenterX = round(a_Player->GetPosX() / (float) RegionWidth) * RegionWidth;
int CenterZ = round(a_Player->GetPosZ() / (float) RegionWidth) * RegionWidth;
- a_World->CreateMap(CenterX, CenterZ, 0);
+ a_World->CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
return true;
}
diff --git a/src/Map.cpp b/src/Map.cpp
index 497cc9659..e0f991693 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -8,6 +8,7 @@
#include "ClientHandle.h"
#include "World.h"
#include "Chunk.h"
+#include "Entities/Player.h"
@@ -23,6 +24,8 @@ cMap::cMap(unsigned int a_ID, cWorld * a_World)
, m_World(a_World)
{
m_Data.assign(m_Width * m_Height, 0);
+
+ Printf(m_Name, "map_%i", m_ID);
}
@@ -40,12 +43,34 @@ cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, un
{
m_Data.assign(m_Width * m_Height, 0);
- for (unsigned int X = 0; X < m_Width; ++X)
+ Printf(m_Name, "map_%i", m_ID);
+}
+
+
+
+
+
+void cMap::UpdateRadius(int a_PixelX, int a_PixelZ, unsigned int a_Radius)
+{
+ int PixelRadius = a_Radius / GetPixelWidth();
+
+ unsigned int StartX = std::max(a_PixelX - PixelRadius, 0);
+ unsigned int StartZ = std::max(a_PixelZ - PixelRadius, 0);
+
+ unsigned int EndX = std::min(a_PixelX + PixelRadius, (int)m_Width);
+ unsigned int EndZ = std::min(a_PixelZ + PixelRadius, (int)m_Height);
+
+ for (unsigned int X = StartX; X < EndX; ++X)
{
- for (unsigned int Y = 0; Y < m_Height; ++Y)
+ for (unsigned int Z = StartZ; Z < EndZ; ++Z)
{
- // Debug
- m_Data[Y + X * m_Height] = rand() % 100;
+ int dX = X - a_PixelX;
+ int dZ = Z - a_PixelZ;
+
+ if ((dX * dX) + (dZ * dZ) < (PixelRadius * PixelRadius))
+ {
+ UpdatePixel(X, Z);
+ }
}
}
}
@@ -54,20 +79,85 @@ cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, un
+void cMap::UpdateRadius(cPlayer & a_Player, unsigned int a_Radius)
+{
+ unsigned int PixelWidth = GetPixelWidth();
+
+ int PixelX = (a_Player.GetPosX() - m_CenterX) / PixelWidth + (m_Width / 2);
+ int PixelZ = (a_Player.GetPosZ() - m_CenterZ) / PixelWidth + (m_Height / 2);
+
+ UpdateRadius(PixelX, PixelZ, a_Radius);
+}
+
+
+
+
+
bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Y)
{
ASSERT(m_World != NULL);
- cChunk * Chunk = NULL;
+ unsigned int PixelWidth = GetPixelWidth();
+
+ int BlockX = m_CenterX + ((a_X - m_Width) * PixelWidth);
+ int BlockZ = m_CenterZ + ((a_Y - m_Height) * PixelWidth);
+
+ int ChunkX, ChunkY, ChunkZ;
+ m_World->BlockToChunk(BlockX, 0, BlockZ, ChunkX, ChunkY, ChunkZ);
- if (Chunk == NULL)
+ int RelX = BlockX - (ChunkX * cChunkDef::Width);
+ int RelZ = BlockZ - (ChunkZ * cChunkDef::Width);
+
+ class cCalculatePixelCb :
+ public cChunkCallback
{
- return false;
- }
+ cMap * m_Map;
+
+ int m_RelX, m_RelZ;
+
+ ColorID m_PixelData;
+
+ public:
+ cCalculatePixelCb(cMap * a_Map, int a_RelX, int a_RelZ)
+ : m_Map(a_Map), m_RelX(a_RelX), m_RelZ(a_RelZ), m_PixelData(0) {}
+
+ virtual bool Item(cChunk * a_Chunk) override
+ {
+ if (a_Chunk == NULL)
+ {
+ return false;
+ }
- int Height = Chunk->GetHeight(a_X, a_Y);
+ unsigned int PixelWidth = m_Map->GetPixelWidth();
+
+ for (unsigned int X = m_RelX; X < m_RelX + PixelWidth; ++X)
+ {
+ for (unsigned int Z = m_RelZ; Z < m_RelZ + PixelWidth; ++Z)
+ {
+ int Height = a_Chunk->GetHeight(X, Z);
+
+ if (Height > 0)
+ {
+ // TODO
+ }
+ }
+ }
+
+ m_PixelData = 8; // Debug
+
+ return false;
+ }
+
+ ColorID GetPixelData(void) const
+ {
+ return m_PixelData;
+ }
+ } CalculatePixelCb(this, RelX, RelZ);
+
+ ASSERT(m_World != NULL);
+ m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb);
- // TODO
+ m_Data[a_Y + (a_X * m_Height)] = CalculatePixelCb.GetPixelData();
return true;
}
@@ -167,7 +257,7 @@ unsigned int cMap::GetNumPixels(void) const
-unsigned int cMap::GetNumBlocksPerPixel(void) const
+unsigned int cMap::GetPixelWidth(void) const
{
return pow(2, m_Scale);
}
diff --git a/src/Map.h b/src/Map.h
index c443445de..4134d53a1 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -21,6 +21,7 @@
class cClientHandle;
class cWorld;
+class cPlayer;
@@ -48,6 +49,11 @@ public:
/** Send this map to the specified client. */
void SendTo(cClientHandle & a_Client);
+ /** Update a circular region with the specified radius and center (in pixels). */
+ void UpdateRadius(int a_PixelX, int a_PixelZ, unsigned int a_Radius);
+
+ void UpdateRadius(cPlayer & a_Player, unsigned int a_Radius);
+
// tolua_begin
/** Erase pixel data */
@@ -71,13 +77,15 @@ public:
cWorld * GetWorld(void) { return m_World; }
+ AString GetName(void) { return m_Name; }
+
eDimension GetDimension(void) const;
const cColorList & GetData(void) const { return m_Data; }
unsigned int GetNumPixels(void) const;
- unsigned int GetNumBlocksPerPixel(void) const;
+ unsigned int GetPixelWidth(void) const;
// tolua_end
@@ -87,8 +95,6 @@ private:
/** Update the specified pixel. */
bool UpdatePixel(unsigned int a_X, unsigned int a_Y);
- void PixelToWorldCoords(unsigned int a_X, unsigned int a_Y, int & a_WorldX, int & a_WorldY);
-
unsigned int m_ID;
unsigned int m_Width;
@@ -105,6 +111,11 @@ private:
cWorld * m_World;
+ //typedef std::vector cPlayerList;
+ //cPlayerList m_TrackedPlayers;
+
+ AString m_Name;
+
friend class cMapSerializer;
};
--
cgit v1.2.3
From 3b24bc870bb39a8b8812ed307250e1188b9ff788 Mon Sep 17 00:00:00 2001
From: andrew
Date: Mon, 17 Feb 2014 16:27:12 +0200
Subject: Map item handler; Fixed several bugs
---
src/ClientHandle.cpp | 2 --
src/Entities/Player.cpp | 3 ++
src/Inventory.cpp | 25 +++++++++++++++
src/Inventory.h | 3 ++
src/Items/ItemEmptyMap.h | 16 +++++++++-
src/Items/ItemHandler.cpp | 2 ++
src/Items/ItemHandler.h | 8 +++++
src/Items/ItemMap.h | 43 ++++++++++++++++++++++++++
src/Map.cpp | 63 +++++++++++++++++++++++++++++++-------
src/Map.h | 13 ++++++--
src/World.cpp | 28 ++++++++++++-----
src/WorldStorage/MapSerializer.cpp | 11 +++++--
src/WorldStorage/MapSerializer.h | 7 +++--
13 files changed, 195 insertions(+), 29 deletions(-)
create mode 100644 src/Items/ItemMap.h
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index ff8775771..a2cbaefff 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1199,8 +1199,6 @@ void cClientHandle::HandleSlotSelected(short a_SlotNum)
if (Map != NULL)
{
- Map->UpdateRadius(*m_Player, 128); // Temporary
-
// TODO 2014-02-14 xdot: Optimization - Do not send the whole map.
Map->SendTo(*this);
}
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 286d43cf6..fdf8d4303 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -254,6 +254,9 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
HandleFloater();
}
+ // Update items (e.g. Maps)
+ m_Inventory.UpdateItems();
+
// Send Player List (Once per m_LastPlayerListTime/1000 ms)
cTimer t1;
if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime())
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index 0e1cedc85..7f434adfd 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -515,6 +515,31 @@ bool cInventory::AddToBar( cItem & a_Item, const int a_Offset, const int a_Size,
+void cInventory::UpdateItems(void)
+{
+ const cItem & Slot = GetEquippedItem();
+
+ if (Slot.IsEmpty())
+ {
+ return;
+ }
+
+ switch (Slot.m_ItemType)
+ {
+ case E_ITEM_MAP:
+ {
+ ItemHandler(Slot.m_ItemType)->OnUpdate(m_Owner.GetWorld(), &m_Owner, Slot);
+ break;
+ }
+
+ default: break;
+ }
+}
+
+
+
+
+
void cInventory::SaveToJson(Json::Value & a_Value)
{
// The JSON originally included the 4 crafting slots and the result, so we have to put empty items there, too:
diff --git a/src/Inventory.h b/src/Inventory.h
index 3c6a19de8..fd2089a13 100644
--- a/src/Inventory.h
+++ b/src/Inventory.h
@@ -150,6 +150,9 @@ public:
/// Sends the slot contents to the owner
void SendSlot(int a_SlotNum);
+ /// Update items (e.g. Maps)
+ void UpdateItems(void);
+
/// Converts an armor slot number into the ID for the EntityEquipment packet
static int ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum);
diff --git a/src/Items/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h
index 24d31151b..b06cf9d13 100644
--- a/src/Items/ItemEmptyMap.h
+++ b/src/Items/ItemEmptyMap.h
@@ -41,7 +41,21 @@ public:
int CenterX = round(a_Player->GetPosX() / (float) RegionWidth) * RegionWidth;
int CenterZ = round(a_Player->GetPosZ() / (float) RegionWidth) * RegionWidth;
- a_World->CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
+ cMap * NewMap = a_World->CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
+
+ // Remove empty map from inventory
+ if (!a_Player->GetInventory().RemoveOneEquippedItem())
+ {
+ ASSERT(!"Inventory mismatch");
+ return true;
+ }
+
+ if (NewMap == NULL)
+ {
+ return true;
+ }
+
+ a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, NewMap->GetID()), true, true);
return true;
}
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 755766d64..cab8dec97 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -25,6 +25,7 @@
#include "ItemHoe.h"
#include "ItemLeaves.h"
#include "ItemLighter.h"
+#include "ItemMap.h"
#include "ItemMinecart.h"
#include "ItemNetherWart.h"
#include "ItemPickaxe.h"
@@ -107,6 +108,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
+ case E_ITEM_MAP: return new cItemMapHandler();
case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType);
case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType);
case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType);
diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h
index 1a6bb044f..ef3f37a7a 100644
--- a/src/Items/ItemHandler.h
+++ b/src/Items/ItemHandler.h
@@ -32,6 +32,14 @@ public:
UNUSED(a_BlockZ);
UNUSED(a_BlockFace);
}
+
+ /// Called every tick while the item is on the player's inventory (Used by maps) - For now, called only for equipped items
+ virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item)
+ {
+ UNUSED(a_World);
+ UNUSED(a_Player);
+ UNUSED(a_Item);
+ }
/// Called while the player diggs a block using this item
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
diff --git a/src/Items/ItemMap.h b/src/Items/ItemMap.h
new file mode 100644
index 000000000..c3e605547
--- /dev/null
+++ b/src/Items/ItemMap.h
@@ -0,0 +1,43 @@
+
+// ItemMap.h
+
+
+
+
+
+#pragma once
+
+#include "../Entities/Entity.h"
+#include "../Item.h"
+
+
+
+
+
+class cItemMapHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+ static const unsigned int DEFAULT_RADIUS = 128;
+
+public:
+ cItemMapHandler() :
+ super(E_ITEM_MAP)
+ {
+ }
+
+ virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item)
+ {
+ cMap * Map = a_World->GetMapData(a_Item.m_ItemDamage);
+
+ if (Map == NULL)
+ {
+ return;
+ }
+
+ // Map->AddTrackedPlayer(a_Player);
+
+ Map->UpdateRadius(*a_Player, DEFAULT_RADIUS);
+ }
+} ;
diff --git a/src/Map.cpp b/src/Map.cpp
index e0f991693..e85c23d3a 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -50,15 +50,25 @@ 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();
- unsigned int StartX = std::max(a_PixelX - PixelRadius, 0);
- unsigned int StartZ = std::max(a_PixelZ - PixelRadius, 0);
+ unsigned int StartX = Clamp(a_PixelX - PixelRadius, 0, (int)m_Width);
+ unsigned int StartZ = Clamp(a_PixelZ - PixelRadius, 0, (int)m_Height);
- unsigned int EndX = std::min(a_PixelX + PixelRadius, (int)m_Width);
- unsigned int EndZ = std::min(a_PixelZ + PixelRadius, (int)m_Height);
+ unsigned int EndX = Clamp(a_PixelX + PixelRadius, 0, (int)m_Width);
+ unsigned int EndZ = Clamp(a_PixelZ + PixelRadius, 0, (int)m_Height);
for (unsigned int X = StartX; X < EndX; ++X)
{
@@ -93,11 +103,9 @@ void cMap::UpdateRadius(cPlayer & a_Player, unsigned int a_Radius)
-bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Y)
+bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
{
- ASSERT(m_World != NULL);
-
- unsigned int PixelWidth = GetPixelWidth();
+ /*unsigned int PixelWidth = GetPixelWidth();
int BlockX = m_CenterX + ((a_X - m_Width) * PixelWidth);
int BlockZ = m_CenterZ + ((a_Y - m_Height) * PixelWidth);
@@ -119,7 +127,7 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Y)
public:
cCalculatePixelCb(cMap * a_Map, int a_RelX, int a_RelZ)
- : m_Map(a_Map), m_RelX(a_RelX), m_RelZ(a_RelZ), m_PixelData(0) {}
+ : m_Map(a_Map), m_RelX(a_RelX), m_RelZ(a_RelZ), m_PixelData(4) {}
virtual bool Item(cChunk * a_Chunk) override
{
@@ -155,9 +163,9 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Y)
} CalculatePixelCb(this, RelX, RelZ);
ASSERT(m_World != NULL);
- m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb);
+ m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb);*/
- m_Data[a_Y + (a_X * m_Height)] = CalculatePixelCb.GetPixelData();
+ m_Data[a_Z + (a_X * m_Height)] = 4;
return true;
}
@@ -166,6 +174,39 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Y)
+void cMap::UpdateTrackedPlayers(void)
+{
+ cTrackedPlayerList NewList;
+
+ for (cTrackedPlayerList::iterator it = m_TrackedPlayers.begin(); it != m_TrackedPlayers.end(); ++it)
+ {
+ cPlayer * Player = *it;
+
+ UpdateRadius(*Player, DEFAULT_RADIUS);
+
+ if (true)
+ {
+ NewList.insert(Player);
+ }
+ }
+
+ std::swap(m_TrackedPlayers, NewList);
+}
+
+
+
+
+
+void cMap::AddTrackedPlayer(cPlayer * a_Player)
+{
+ ASSERT(a_Player != NULL);
+ m_TrackedPlayers.insert(a_Player);
+}
+
+
+
+
+
void cMap::EraseData(void)
{
m_Data.assign(m_Width * m_Height, 0);
diff --git a/src/Map.h b/src/Map.h
index 4134d53a1..805dfb845 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -38,6 +38,8 @@ public:
typedef std::vector cColorList;
+ static const unsigned int DEFAULT_RADIUS = 128;
+
public:
@@ -54,6 +56,10 @@ public:
void UpdateRadius(cPlayer & a_Player, unsigned int a_Radius);
+ void UpdateTrackedPlayers(void);
+
+ void AddTrackedPlayer(cPlayer * a_Player);
+
// tolua_begin
/** Erase pixel data */
@@ -93,7 +99,7 @@ public:
private:
/** Update the specified pixel. */
- bool UpdatePixel(unsigned int a_X, unsigned int a_Y);
+ bool UpdatePixel(unsigned int a_X, unsigned int a_Z);
unsigned int m_ID;
@@ -111,8 +117,9 @@ private:
cWorld * m_World;
- //typedef std::vector cPlayerList;
- //cPlayerList m_TrackedPlayers;
+ typedef std::set cTrackedPlayerList;
+
+ cTrackedPlayerList m_TrackedPlayers;
AString m_Name;
diff --git a/src/World.cpp b/src/World.cpp
index 2a3e53332..55c6fbb7a 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1574,8 +1574,7 @@ cMap * cWorld::CreateMap(int a_CenterX, int a_CenterY, int a_Scale)
{
if (m_MapData.size() >= 65536)
{
- LOGD("cWorld::CreateMap - Too many maps in use");
-
+ LOGWARN("Could not craft map - Too many maps in use");
return NULL;
}
@@ -2992,9 +2991,12 @@ void cWorld::LoadMapData(void)
{
cIDCountSerializer IDSerializer(GetName());
- IDSerializer.Load();
+ if (!IDSerializer.Load())
+ {
+ return;
+ }
- unsigned int MapCount = IDSerializer.GetMapCount() + 1;
+ unsigned int MapCount = IDSerializer.GetMapCount();
m_MapData.clear();
@@ -3004,7 +3006,10 @@ void cWorld::LoadMapData(void)
cMapSerializer Serializer(GetName(), &Map);
- Serializer.Load();
+ if (!Serializer.Load())
+ {
+ LOGWARN("Could not load map #%i", Map.GetID());
+ }
m_MapData.push_back(Map);
}
@@ -3023,9 +3028,13 @@ void cWorld::SaveMapData(void)
cIDCountSerializer IDSerializer(GetName());
- IDSerializer.SetMapCount(m_MapData.size() - 1);
+ IDSerializer.SetMapCount(m_MapData.size());
- IDSerializer.Save();
+ if (!IDSerializer.Save())
+ {
+ LOGERROR("Could not save idcounts.dat");
+ return;
+ }
for (cMapList::iterator it = m_MapData.begin(); it != m_MapData.end(); ++it)
{
@@ -3033,7 +3042,10 @@ void cWorld::SaveMapData(void)
cMapSerializer Serializer(GetName(), &Map);
- Serializer.Save();
+ if (!Serializer.Save())
+ {
+ LOGWARN("Could not save map #%i", Map.GetID());
+ }
}
}
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
index 6dab19d4f..0bbe71a60 100644
--- a/src/WorldStorage/MapSerializer.cpp
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -223,7 +223,11 @@ bool cIDCountSerializer::Load(void)
int CurrLine = NBT.FindChildByName(0, "map");
if (CurrLine >= 0)
{
- m_MapCount = (int)NBT.GetShort(CurrLine);
+ m_MapCount = (int)NBT.GetShort(CurrLine) + 1;
+ }
+ else
+ {
+ m_MapCount = 0;
}
return true;
@@ -237,7 +241,10 @@ bool cIDCountSerializer::Save(void)
{
cFastNBTWriter Writer;
- Writer.AddShort("map", m_MapCount);
+ if (m_MapCount > 0)
+ {
+ Writer.AddShort("map", m_MapCount - 1);
+ }
Writer.Finish();
diff --git a/src/WorldStorage/MapSerializer.h b/src/WorldStorage/MapSerializer.h
index d9da107bc..296cc92c8 100644
--- a/src/WorldStorage/MapSerializer.h
+++ b/src/WorldStorage/MapSerializer.h
@@ -27,10 +27,10 @@ public:
cMapSerializer(const AString& a_WorldName, cMap * a_Map);
- /// Try to load the scoreboard
+ /** Try to load the scoreboard */
bool Load(void);
- /// Try to save the scoreboard
+ /** Try to save the scoreboard */
bool Save(void);
@@ -56,8 +56,10 @@ public:
cIDCountSerializer(const AString & a_WorldName);
+ /** Try to load the ID counts */
bool Load(void);
+ /** Try to save the ID counts */
bool Save(void);
inline unsigned int GetMapCount(void) const { return m_MapCount; }
@@ -70,6 +72,7 @@ private:
AString m_Path;
unsigned int m_MapCount;
+
};
--
cgit v1.2.3
From 393ca0221dfdb6dabadcf293fea86a830453c938 Mon Sep 17 00:00:00 2001
From: andrew
Date: Tue, 18 Feb 2014 20:50:08 +0200
Subject: Map decorators; Map clients
---
src/ClientHandle.cpp | 22 ++--
src/ClientHandle.h | 2 +
src/Items/ItemMap.h | 4 +-
src/Map.cpp | 232 ++++++++++++++++++++++++++++++++----
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, 351 insertions(+), 45 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)
+{
+ for (cMapDecoratorList::iterator it = m_Decorators.begin(); it != m_Decorators.end(); ++it)
+ {
+ it->Update();
+ }
+}
+
+
+
+
+
+void cMap::UpdateClient(cPlayer * a_Player)
{
- cTrackedPlayerList NewList;
+ ASSERT(a_Player != NULL);
+ cClientHandle * Handle = a_Player->GetClientHandle();
- for (cTrackedPlayerList::iterator it = m_TrackedPlayers.begin(); it != m_TrackedPlayers.end(); ++it)
+ if (Handle == NULL)
{
- cPlayer * Player = *it;
+ return;
+ }
+
+ Int64 WorldAge = a_Player->GetWorld()->GetWorldAge();
- UpdateRadius(*Player, DEFAULT_RADIUS);
+ // 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;
+ }
+ }
- if (true)
+ // Erase client
+ cMapClientList::iterator temp = it;
+ ++it;
+ m_Clients.erase(temp);
+ }
+ else
{
- NewList.insert(Player);
+ ++it;
}
}
- std::swap(m_TrackedPlayers, NewList);
-}
+ // 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;
-void cMap::AddTrackedPlayer(cPlayer * a_Player)
-{
- ASSERT(a_Player != NULL);
- m_TrackedPlayers.insert(a_Player);
+ 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;
--
cgit v1.2.3
From 4a1ac5740869356880523dde83ec0b7804689d42 Mon Sep 17 00:00:00 2001
From: andrew
Date: Wed, 19 Feb 2014 15:28:48 +0200
Subject: Documented cMap
---
src/Map.cpp | 12 ++++++++----
src/Map.h | 24 +++++++++++++++++++++---
src/WorldStorage/MapSerializer.h | 2 ++
3 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/src/Map.cpp b/src/Map.cpp
index f32d232fa..4f8924af2 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -14,7 +14,7 @@
-cMapDecorator::cMapDecorator(cMap * a_Map, eType a_Type, int a_X, int a_Z, unsigned int a_Rot)
+cMapDecorator::cMapDecorator(cMap * a_Map, eType a_Type, int a_X, int a_Z, int a_Rot)
: m_Map(a_Map)
, m_Type(a_Type)
, m_PixelX(a_X)
@@ -58,7 +58,7 @@ void cMapDecorator::Update(void)
int InsideWidth = (m_Map->GetWidth() / 2) - 1;
int InsideHeight = (m_Map->GetHeight() / 2) - 1;
- if (m_Player)
+ if (m_Player != NULL)
{
int PixelX = (m_Player->GetPosX() - m_Map->GetCenterX()) / PixelWidth;
int PixelZ = (m_Player->GetPosZ() - m_Map->GetCenterZ()) / PixelWidth;
@@ -200,7 +200,8 @@ void cMap::UpdateRadius(cPlayer & a_Player, unsigned int a_Radius)
bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
{
- /*unsigned int PixelWidth = GetPixelWidth();
+ /*
+ unsigned int PixelWidth = GetPixelWidth();
int BlockX = m_CenterX + ((a_X - m_Width) * PixelWidth);
int BlockZ = m_CenterZ + ((a_Y - m_Height) * PixelWidth);
@@ -258,7 +259,8 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
} CalculatePixelCb(this, RelX, RelZ);
ASSERT(m_World != NULL);
- m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb);*/
+ m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb);
+ */
m_Data[a_Z + (a_X * m_Height)] = 4;
@@ -346,6 +348,8 @@ void cMap::UpdateClient(cPlayer * a_Player)
if (it->m_NextDecoratorUpdate >= 4)
{
+ // TODO 2014-02-19 xdot
+ // This is dangerous as the player object may have been destroyed before the decorator is erased from the list
UpdateDecorators();
Handle->SendMapDecorators(m_ID, m_Decorators);
diff --git a/src/Map.h b/src/Map.h
index 76e459621..1a330e1c2 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -28,28 +28,36 @@ class cMap;
+/** Encapsulates a map decorator. */
class cMapDecorator
{
public:
+
enum eType
{
E_TYPE_PLAYER = 0x00,
E_TYPE_ITEM_FRAME = 0x01,
+
+ /** Player outside of the boundaries of the map. */
E_TYPE_PLAYER_OUTSIDE = 0x06
};
public:
- cMapDecorator(cMap * a_Map, eType a_Type, int a_X, int a_Z, unsigned int a_Rot);
+ /** Constructs a map decorator fixed at the specified pixel coordinates. (DEBUG) */
+ cMapDecorator(cMap * a_Map, eType a_Type, int a_X, int a_Z, int a_Rot);
+ /** Constructs a map decorator that tracks a player. */
cMapDecorator(cMap * a_Map, cPlayer * a_Player);
+ /** Updates the pixel coordinates of the decorator. */
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; }
+
+ int GetRot(void) const { return m_Rot; }
eType GetType(void) const { return m_Type; }
@@ -68,6 +76,7 @@ protected:
unsigned int m_Rot;
cPlayer * m_Player;
+
};
typedef std::list cMapDecoratorList;
@@ -77,6 +86,8 @@ typedef std::list cMapDecoratorList;
// tolua_begin
+
+/** Encapsulates an in-game world map. */
class cMap
{
public:
@@ -87,15 +98,20 @@ public:
typedef std::vector cColorList;
+ /** Encapsulates the state of a map client. */
struct cMapClient
{
cClientHandle * m_Handle;
+ /** Whether the map scale was modified and needs to be resent. */
bool m_SendInfo;
+ /** Ticks since last decorator update. */
unsigned int m_NextDecoratorUpdate;
+ /** Number of pixel data updates. */
Int64 m_DataUpdate;
+
Int64 m_LastUpdate;
};
@@ -107,14 +123,16 @@ public:
/** Construct an empty map. */
cMap(unsigned int a_ID, cWorld * a_World);
+ /** Constructs an empty map at the specified coordinates. */
cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale = 3);
- /** Send this map to the specified client. */
+ /** Send this map to the specified client. WARNING: Slow */
void SendTo(cClientHandle & a_Client);
/** Update a circular region with the specified radius and center (in pixels). */
void UpdateRadius(int a_PixelX, int a_PixelZ, unsigned int a_Radius);
+ /** Update a circular region around the specified player. */
void UpdateRadius(cPlayer & a_Player, unsigned int a_Radius);
/** Send next update packet and remove invalid decorators */
diff --git a/src/WorldStorage/MapSerializer.h b/src/WorldStorage/MapSerializer.h
index 296cc92c8..85fe917f5 100644
--- a/src/WorldStorage/MapSerializer.h
+++ b/src/WorldStorage/MapSerializer.h
@@ -21,6 +21,7 @@ class cMap;
+/** Utility class used to serialize maps. */
class cMapSerializer
{
public:
@@ -50,6 +51,7 @@ private:
+/** Utility class used to serialize item ID counts. */
class cIDCountSerializer
{
public:
--
cgit v1.2.3
From 58a708825fa7e79c9dcbe6ad1bbbb2c0c3247edc Mon Sep 17 00:00:00 2001
From: andrew
Date: Wed, 19 Feb 2014 20:57:14 +0200
Subject: cMapDecorator: Implemented random rotations
---
src/Map.cpp | 25 +++++++++++++++----------
src/Map.h | 6 +++---
2 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/src/Map.cpp b/src/Map.cpp
index 4f8924af2..a194dbd96 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -9,6 +9,7 @@
#include "World.h"
#include "Chunk.h"
#include "Entities/Player.h"
+#include "FastRandom.h"
@@ -52,14 +53,14 @@ T Clamp(T a_X, T a_Min, T 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 != NULL)
{
+ ASSERT(m_Map != NULL);
+ unsigned int PixelWidth = m_Map->GetPixelWidth();
+
+ int InsideWidth = (m_Map->GetWidth() / 2) - 1;
+ int InsideHeight = (m_Map->GetHeight() / 2) - 1;
+
int PixelX = (m_Player->GetPosX() - m_Map->GetCenterX()) / PixelWidth;
int PixelZ = (m_Player->GetPosZ() - m_Map->GetCenterZ()) / PixelWidth;
@@ -67,18 +68,22 @@ void cMapDecorator::Update(void)
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)
{
+ cFastRandom Random;
+
Int64 WorldAge = m_Player->GetWorld()->GetWorldAge();
- // TODO 2014-02-18 xdot: Random rotations
+ // TODO 2014-02-19 xdot: Refine
+ m_Rot = Random.NextInt(16, WorldAge);
+ }
+ else
+ {
+ m_Rot = (Yaw * 16) / 360;
}
m_Type = E_TYPE_PLAYER;
diff --git a/src/Map.h b/src/Map.h
index 1a330e1c2..3cf9977ab 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -51,7 +51,7 @@ public:
/** Constructs a map decorator that tracks a player. */
cMapDecorator(cMap * a_Map, cPlayer * a_Player);
- /** Updates the pixel coordinates of the decorator. */
+ /** Updates the decorator. */
void Update(void);
unsigned int GetPixelX(void) const { return m_PixelX; }
@@ -123,7 +123,7 @@ public:
/** Construct an empty map. */
cMap(unsigned int a_ID, cWorld * a_World);
- /** Constructs an empty map at the specified coordinates. */
+ /** Construct an empty map at the specified coordinates. */
cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale = 3);
/** Send this map to the specified client. WARNING: Slow */
@@ -135,7 +135,7 @@ public:
/** Update a circular region around the specified player. */
void UpdateRadius(cPlayer & a_Player, unsigned int a_Radius);
- /** Send next update packet and remove invalid decorators */
+ /** Send next update packet to the specified player and remove invalid decorators/clients. */
void UpdateClient(cPlayer * a_Player);
// tolua_begin
--
cgit v1.2.3
From f201f4f176fc908e9ddebfed86d4c8ef5582556c Mon Sep 17 00:00:00 2001
From: andrew
Date: Thu, 20 Feb 2014 16:38:37 +0200
Subject: Thread safe cMap manager
---
src/Generating/StructGen.cpp | 9 ---
src/Globals.h | 6 +-
src/Map.h | 15 +++-
src/MapManager.cpp | 178 +++++++++++++++++++++++++++++++++++++++++++
src/MapManager.h | 76 ++++++++++++++++++
src/World.cpp | 3 +-
src/World.h | 5 +-
7 files changed, 275 insertions(+), 17 deletions(-)
create mode 100644 src/MapManager.cpp
create mode 100644 src/MapManager.h
diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp
index 4efcf92f0..47945cc2b 100644
--- a/src/Generating/StructGen.cpp
+++ b/src/Generating/StructGen.cpp
@@ -51,15 +51,6 @@ const int NEST_SIZE_GRAVEL = 32;
-template T Clamp(T a_Value, T a_Min, T a_Max)
-{
- return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
-}
-
-
-
-
-
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenTrees:
diff --git a/src/Globals.h b/src/Globals.h
index 7ee045130..e4737a98a 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -235,11 +235,11 @@ public:
-/** Clamp a_X to the specified range. */
+/** Clamp X to the specified range. */
template
-T Clamp(T a_X, T a_Min, T a_Max)
+T Clamp(T a_Value, T a_Min, T a_Max)
{
- return std::min(std::max(a_X, a_Min), a_Max);
+ return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
}
diff --git a/src/Map.h b/src/Map.h
index 3cf9977ab..ce19c8d2e 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -28,7 +28,14 @@ class cMap;
-/** Encapsulates a map decorator. */
+/** Encapsulates a map decorator.
+ *
+ * A map decorator represents an object drawn on the map that can move freely.
+ * (e.g. player trackers and item frame pointers)
+ *
+ * Excluding manually placed decorators,
+ * decorators are automatically managed (allocated and freed) by their parent cMap instance.
+ */
class cMapDecorator
{
public:
@@ -98,7 +105,11 @@ public:
typedef std::vector cColorList;
- /** Encapsulates the state of a map client. */
+ /** Encapsulates the state of a map client.
+ *
+ * In order to enhance performace, maps are streamed column-by-column to each client.
+ * This structure stores the state of the stream.
+ */
struct cMapClient
{
cClientHandle * m_Handle;
diff --git a/src/MapManager.cpp b/src/MapManager.cpp
new file mode 100644
index 000000000..2fc44ccc8
--- /dev/null
+++ b/src/MapManager.cpp
@@ -0,0 +1,178 @@
+
+// MapManager.cpp
+
+#include "Globals.h"
+
+#include "MapManager.h"
+
+#include "World.h"
+#include "WorldStorage/MapSerializer.h"
+
+
+
+
+
+cMapManager::cMapManager(cWorld * a_World)
+ : m_World(a_World)
+{
+ ASSERT(m_World != NULL);
+}
+
+
+
+
+
+bool cMapManager::DoWithMap(unsigned int a_ID, cMapCallback & a_Callback)
+{
+ cCSLock Lock(m_CS);
+ cMap * Map = GetMapData(a_ID);
+
+ if (Map == NULL)
+ {
+ return false;
+ }
+ else
+ {
+ a_Callback.Item(Map);
+ return true;
+ }
+}
+
+
+
+
+
+bool cMapManager::ForEachMap(cMapCallback & a_Callback)
+{
+ cCSLock Lock(m_CS);
+ for (cMapList::iterator itr = m_MapData.begin(); itr != m_MapData.end(); ++itr)
+ {
+ cMap * Map = &(*itr);
+ if (a_Callback.Item(Map))
+ {
+ return false;
+ }
+ } // for itr - m_MapData[]
+ return true;
+}
+
+
+
+
+
+cMap * cMapManager::GetMapData(unsigned int a_ID)
+{
+ if (a_ID < m_MapData.size())
+ {
+ return &m_MapData[a_ID];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+
+
+
+cMap * cMapManager::CreateMap(int a_CenterX, int a_CenterY, int a_Scale)
+{
+ cCSLock Lock(m_CS);
+
+ if (m_MapData.size() >= 65536)
+ {
+ LOGWARN("Could not craft map - Too many maps in use");
+ return NULL;
+ }
+
+ cMap Map(m_MapData.size(), a_CenterX, a_CenterY, m_World, a_Scale);
+
+ m_MapData.push_back(Map);
+
+ return &m_MapData[Map.GetID()];
+}
+
+
+
+
+
+unsigned int cMapManager::GetNumMaps(void) const
+{
+ return m_MapData.size();
+}
+
+
+
+
+
+void cMapManager::LoadMapData(void)
+{
+ cCSLock Lock(m_CS);
+
+ cIDCountSerializer IDSerializer(m_World->GetName());
+
+ if (!IDSerializer.Load())
+ {
+ return;
+ }
+
+ unsigned int MapCount = IDSerializer.GetMapCount();
+
+ m_MapData.clear();
+
+ for (unsigned int i = 0; i < MapCount; ++i)
+ {
+ cMap Map(i, m_World);
+
+ cMapSerializer Serializer(m_World->GetName(), &Map);
+
+ if (!Serializer.Load())
+ {
+ LOGWARN("Could not load map #%i", Map.GetID());
+ }
+
+ m_MapData.push_back(Map);
+ }
+}
+
+
+
+
+
+void cMapManager::SaveMapData(void)
+{
+ cCSLock Lock(m_CS);
+
+ if (m_MapData.empty())
+ {
+ return;
+ }
+
+ cIDCountSerializer IDSerializer(m_World->GetName());
+
+ IDSerializer.SetMapCount(m_MapData.size());
+
+ if (!IDSerializer.Save())
+ {
+ LOGERROR("Could not save idcounts.dat");
+ return;
+ }
+
+ for (cMapList::iterator it = m_MapData.begin(); it != m_MapData.end(); ++it)
+ {
+ cMap & Map = *it;
+
+ cMapSerializer Serializer(m_World->GetName(), &Map);
+
+ if (!Serializer.Save())
+ {
+ LOGWARN("Could not save map #%i", Map.GetID());
+ }
+ }
+}
+
+
+
+
+
diff --git a/src/MapManager.h b/src/MapManager.h
new file mode 100644
index 000000000..05673c694
--- /dev/null
+++ b/src/MapManager.h
@@ -0,0 +1,76 @@
+
+// MapManager.h
+
+
+
+
+
+#pragma once
+
+
+
+
+
+#include "Map.h"
+
+
+
+
+typedef cItemCallback cMapCallback;
+
+
+
+
+
+/** Manages the in-game maps of a single world - Thread safe. */
+class cMapManager
+{
+public:
+
+ cMapManager(cWorld * a_World);
+
+ /** Returns the map with the specified ID, NULL if out of range.
+ *
+ * WARNING: The returned map object is not thread safe.
+ */
+ cMap * GetMapData(unsigned int a_ID);
+
+ /** Creates a new map. Returns NULL on error */
+ cMap * CreateMap(int a_CenterX, int a_CenterY, int a_Scale = 3);
+
+ /** Calls the callback for the map with the specified ID.
+ *
+ * Returns true if the map was found and the callback called, false if map not found.
+ * Callback return ignored.
+ */
+ bool DoWithMap(unsigned int a_ID, cMapCallback & a_Callback);
+
+ /** Calls the callback for each map.
+ *
+ * Returns true if all maps processed, false if the callback aborted by returning true.
+ */
+ bool ForEachMap(cMapCallback & a_Callback);
+
+ unsigned int GetNumMaps(void) const;
+
+ /** Loads the map data from the disk */
+ void LoadMapData(void);
+
+ /** Saves the map data to the disk */
+ void SaveMapData(void);
+
+
+private:
+
+ typedef std::vector cMapList;
+
+ cCriticalSection m_CS;
+
+ cMapList m_MapData;
+
+ cWorld * m_World;
+
+};
+
+
+
diff --git a/src/World.cpp b/src/World.cpp
index c1e0731c1..01fdae697 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -12,8 +12,8 @@
#include "Generating/ChunkDesc.h"
#include "OSSupport/Timer.h"
+// Serializers
#include "WorldStorage/ScoreboardSerializer.h"
-#include "WorldStorage/MapSerializer.h"
// Entities (except mobs):
#include "Entities/ExpOrb.h"
@@ -233,6 +233,7 @@ void cWorld::cTickThread::Execute(void)
// cWorld:
cWorld::cWorld(const AString & a_WorldName) :
+ cMapManager(this),
m_WorldName(a_WorldName),
m_IniFileName(m_WorldName + "/world.ini"),
m_StorageSchema("Default"),
diff --git a/src/World.h b/src/World.h
index 92fc66c8c..f05ea9b2a 100644
--- a/src/World.h
+++ b/src/World.h
@@ -24,7 +24,7 @@
#include "Entities/ProjectileEntity.h"
#include "ForEachChunkProvider.h"
#include "Scoreboard.h"
-#include "Map.h"
+#include "MapManager.h"
#include "Blocks/WorldInterface.h"
#include "Blocks/BroadcastInterface.h"
@@ -71,7 +71,8 @@ typedef cItemCallback cMobHeadBlockCallback;
class cWorld :
public cForEachChunkProvider,
public cWorldInterface,
- public cBroadcastInterface
+ public cBroadcastInterface,
+ public cMapManager
{
public:
--
cgit v1.2.3
From 8bf5d116fe4c7b2addeba2dac9a8b1fc93486444 Mon Sep 17 00:00:00 2001
From: andrew
Date: Fri, 21 Feb 2014 15:26:33 +0200
Subject: Split cMap::UpdateClient
---
src/Map.cpp | 126 ++++++++++++++++++++++++++++++++++++------------------------
src/Map.h | 61 ++++++++++++++++++-----------
2 files changed, 114 insertions(+), 73 deletions(-)
diff --git a/src/Map.cpp b/src/Map.cpp
index cb5472a22..0028a1e94 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -278,28 +278,35 @@ void cMap::UpdateDecorators(void)
-void cMap::UpdateClient(cPlayer * a_Player)
+void cMap::AddPlayer(cPlayer * a_Player, cClientHandle * a_Handle, Int64 a_WorldAge)
{
- ASSERT(a_Player != NULL);
- cClientHandle * Handle = a_Player->GetClientHandle();
+ cMapClient MapClient;
+
+ MapClient.m_LastUpdate = a_WorldAge;
+ MapClient.m_SendInfo = true;
+ MapClient.m_Handle = a_Handle;
+
+ m_Clients.push_back(MapClient);
+
+ cMapDecorator PlayerDecorator(this, a_Player);
+
+ m_Decorators.push_back(PlayerDecorator);
+}
+
+
- if (Handle == NULL)
- {
- return;
- }
- Int64 WorldAge = a_Player->GetWorld()->GetWorldAge();
- // Remove invalid clients
+void cMap::RemoveInactiveClients(Int64 a_WorldAge)
+{
for (cMapClientList::iterator it = m_Clients.begin(); it != m_Clients.end();)
{
- // Check if client is active
- if (it->m_LastUpdate < WorldAge - 5)
+ if (it->m_LastUpdate < a_WorldAge)
{
// Remove associated decorators
for (cMapDecoratorList::iterator it2 = m_Decorators.begin(); it2 != m_Decorators.end();)
{
- if (it2->GetPlayer()->GetClientHandle() == Handle)
+ if (it2->GetPlayer()->GetClientHandle() == it->m_Handle)
{
// Erase decorator
cMapDecoratorList::iterator temp = it2;
@@ -322,63 +329,82 @@ void cMap::UpdateClient(cPlayer * a_Player)
++it;
}
}
+}
- // Linear search for client state
- for (cMapClientList::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it)
+
+
+
+
+void cMap::StreamNext(cMapClient & a_Client)
+{
+ cClientHandle * Handle = a_Client.m_Handle;
+
+ if (a_Client.m_SendInfo)
{
- if (it->m_Handle == Handle)
- {
- it->m_LastUpdate = WorldAge;
+ Handle->SendMapInfo(m_ID, m_Scale);
- if (it->m_SendInfo)
- {
- Handle->SendMapInfo(m_ID, m_Scale);
+ a_Client.m_SendInfo = false;
- it->m_SendInfo = false;
+ return;
+ }
- return;
- }
+ ++a_Client.m_NextDecoratorUpdate;
- ++it->m_NextDecoratorUpdate;
+ if (a_Client.m_NextDecoratorUpdate >= 4)
+ {
+ // TODO 2014-02-19 xdot
+ // This is dangerous as the player object may have been destroyed before the decorator is erased from the list
+ UpdateDecorators();
- if (it->m_NextDecoratorUpdate >= 4)
- {
- // TODO 2014-02-19 xdot
- // This is dangerous as the player object may have been destroyed before the decorator is erased from the list
- UpdateDecorators();
+ Handle->SendMapDecorators(m_ID, m_Decorators);
- Handle->SendMapDecorators(m_ID, m_Decorators);
+ a_Client.m_NextDecoratorUpdate = 0;
+ }
+ else
+ {
+ ++a_Client.m_DataUpdate;
- it->m_NextDecoratorUpdate = 0;
- }
- else
- {
- ++it->m_DataUpdate;
+ unsigned int Y = (a_Client.m_DataUpdate * 11) % m_Width;
- unsigned int Y = (it->m_DataUpdate * 11) % m_Width;
+ const Byte * Colors = &m_Data[Y * m_Height];
- const Byte * Colors = &m_Data[Y * m_Height];
+ Handle->SendMapColumn(m_ID, Y, 0, Colors, m_Height);
+ }
+}
- Handle->SendMapColumn(m_ID, Y, 0, Colors, m_Height);
- }
- return;
- }
+
+
+
+void cMap::UpdateClient(cPlayer * a_Player)
+{
+ ASSERT(a_Player != NULL);
+ cClientHandle * Handle = a_Player->GetClientHandle();
+
+ if (Handle == NULL)
+ {
+ return;
}
- // New player, construct a new client state
- cMapClient MapClient;
+ Int64 WorldAge = a_Player->GetWorld()->GetWorldAge();
- MapClient.m_LastUpdate = WorldAge;
- MapClient.m_SendInfo = true;
- MapClient.m_Handle = a_Player->GetClientHandle();
+ RemoveInactiveClients(WorldAge - 5);
- m_Clients.push_back(MapClient);
+ // 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;
- // Insert new decorator
- cMapDecorator PlayerDecorator(this, a_Player);
+ StreamNext(*it);
- m_Decorators.push_back(PlayerDecorator);
+ return;
+ }
+ }
+
+ // New player, construct a new client state
+ AddPlayer(a_Player, Handle, WorldAge);
}
diff --git a/src/Map.h b/src/Map.h
index ce19c8d2e..01ffd19f5 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -105,29 +105,6 @@ public:
typedef std::vector cColorList;
- /** Encapsulates the state of a map client.
- *
- * In order to enhance performace, maps are streamed column-by-column to each client.
- * This structure stores the state of the stream.
- */
- struct cMapClient
- {
- cClientHandle * m_Handle;
-
- /** Whether the map scale was modified and needs to be resent. */
- bool m_SendInfo;
-
- /** Ticks since last decorator update. */
- unsigned int m_NextDecoratorUpdate;
-
- /** Number of pixel data updates. */
- Int64 m_DataUpdate;
-
- Int64 m_LastUpdate;
- };
-
- typedef std::list cMapClientList;
-
public:
@@ -185,6 +162,32 @@ public:
// tolua_end
+protected:
+
+ /** Encapsulates the state of a map client.
+ *
+ * In order to enhance performace, maps are streamed column-by-column to each client.
+ * This structure stores the state of the stream.
+ */
+ struct cMapClient
+ {
+ cClientHandle * m_Handle;
+
+ /** Whether the map scale was modified and needs to be resent. */
+ bool m_SendInfo;
+
+ /** Ticks since last decorator update. */
+ unsigned int m_NextDecoratorUpdate;
+
+ /** Number of pixel data updates. */
+ Int64 m_DataUpdate;
+
+ Int64 m_LastUpdate;
+ };
+
+ typedef std::list cMapClientList;
+
+
private:
/** Update the associated decorators. */
@@ -193,6 +196,15 @@ private:
/** Update the specified pixel. */
bool UpdatePixel(unsigned int a_X, unsigned int a_Z);
+ /** Add a new map client. */
+ void AddPlayer(cPlayer * a_Player, cClientHandle * a_Handle, Int64 a_WorldAge);
+
+ /** Remove inactive or invalid clients. */
+ void RemoveInactiveClients(Int64 a_WorldAge);
+
+ /** Send next update packet to the specified client. */
+ void StreamNext(cMapClient & a_Client);
+
unsigned int m_ID;
unsigned int m_Width;
@@ -218,3 +230,6 @@ private:
friend class cMapSerializer;
};
+
+
+
--
cgit v1.2.3
From a96eea5e66191ee02c21e3ce3f33277c516142bc Mon Sep 17 00:00:00 2001
From: andrew
Date: Sat, 22 Feb 2014 12:50:30 +0200
Subject: Semi-working implementation of cMap::UpdatePixel
---
src/Map.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------
src/Map.h | 18 +++++++++++++
2 files changed, 95 insertions(+), 11 deletions(-)
diff --git a/src/Map.cpp b/src/Map.cpp
index 0028a1e94..87fe9555f 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -123,7 +123,7 @@ cMap::cMap(unsigned int a_ID, cWorld * a_World)
, m_CenterZ(0)
, m_World(a_World)
{
- m_Data.assign(m_Width * m_Height, 0);
+ m_Data.assign(m_Width * m_Height, E_BASE_COLOR_TRANSPARENT);
Printf(m_Name, "map_%i", m_ID);
}
@@ -141,7 +141,7 @@ cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, un
, m_CenterZ(a_CenterZ)
, m_World(a_World)
{
- m_Data.assign(m_Width * m_Height, 0);
+ m_Data.assign(m_Width * m_Height, E_BASE_COLOR_TRANSPARENT);
Printf(m_Name, "map_%i", m_ID);
}
@@ -195,11 +195,10 @@ void cMap::UpdateRadius(cPlayer & a_Player, unsigned int a_Radius)
bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
{
- /*
unsigned int PixelWidth = GetPixelWidth();
- int BlockX = m_CenterX + ((a_X - m_Width) * PixelWidth);
- int BlockZ = m_CenterZ + ((a_Y - m_Height) * PixelWidth);
+ int BlockX = m_CenterX + ((a_X - (m_Width / 2)) * PixelWidth);
+ int BlockZ = m_CenterZ + ((a_Z - (m_Height / 2)) * PixelWidth);
int ChunkX, ChunkY, ChunkZ;
m_World->BlockToChunk(BlockX, 0, BlockZ, ChunkX, ChunkY, ChunkZ);
@@ -218,7 +217,7 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
public:
cCalculatePixelCb(cMap * a_Map, int a_RelX, int a_RelZ)
- : m_Map(a_Map), m_RelX(a_RelX), m_RelZ(a_RelZ), m_PixelData(4) {}
+ : m_Map(a_Map), m_RelX(a_RelX), m_RelZ(a_RelZ), m_PixelData(E_BASE_COLOR_TRANSPARENT) {}
virtual bool Item(cChunk * a_Chunk) override
{
@@ -229,20 +228,88 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
unsigned int PixelWidth = m_Map->GetPixelWidth();
+ if (m_Map->GetDimension() == dimNether)
+ {
+ // TODO 2014-02-22 xdot: Nether maps
+
+ return false;
+ }
+
+ typedef std::map ColorCountMap;
+ ColorCountMap ColorCounts;
+
+ // Count surface blocks
for (unsigned int X = m_RelX; X < m_RelX + PixelWidth; ++X)
{
for (unsigned int Z = m_RelZ; Z < m_RelZ + PixelWidth; ++Z)
{
+ unsigned int WaterDepth = 0;
+
+ BLOCKTYPE TargetBlock = E_BLOCK_AIR;
+ NIBBLETYPE TargetMeta = 0;
+
int Height = a_Chunk->GetHeight(X, Z);
- if (Height > 0)
+ while (Height > 0)
+ {
+ a_Chunk->GetBlockTypeMeta(X, Height, Z, TargetBlock, TargetMeta);
+
+ // TODO 2014-02-22 xdot: Check if block color is transparent
+ if (TargetBlock == E_BLOCK_AIR)
+ {
+ --Height;
+ continue;
+ }
+ // TODO 2014-02-22 xdot: Check if block is liquid
+ else if (false)
+ {
+ --Height;
+ ++WaterDepth;
+ continue;
+ }
+
+ break;
+ }
+
+ // TODO 2014-02-22 xdot: Query block color
+ ColorID Color = E_BASE_COLOR_BROWN;
+
+ // Debug - Temporary
+ switch (TargetBlock)
{
- // TODO
+ case E_BLOCK_GRASS:
+ {
+ Color = E_BASE_COLOR_LIGHT_GREEN; break;
+ }
+ case E_BLOCK_STATIONARY_WATER:
+ case E_BLOCK_WATER:
+ {
+ Color = E_BASE_COLOR_BLUE; break;
+ }
}
+
+ ++ColorCounts[Color];
+ }
+ }
+
+ // Find dominant color
+ ColorID PixelColor = E_BASE_COLOR_TRANSPARENT;
+
+ unsigned int MaxCount = 0;
+
+ for (ColorCountMap::iterator it = ColorCounts.begin(); it != ColorCounts.end(); ++it)
+ {
+ if (it->second > MaxCount)
+ {
+ PixelColor = it->first;
+ MaxCount = it->second;
}
}
- m_PixelData = 8; // Debug
+ // TODO 2014-02-22 xdot: Adjust brightness
+ unsigned int dColor = 1;
+
+ m_PixelData = PixelColor + dColor;
return false;
}
@@ -255,9 +322,8 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
ASSERT(m_World != NULL);
m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb);
- */
- m_Data[a_Z + (a_X * m_Height)] = 4;
+ m_Data[a_Z + (a_X * m_Height)] = CalculatePixelCb.GetPixelData();
return true;
}
diff --git a/src/Map.h b/src/Map.h
index 01ffd19f5..a86de3dd3 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -99,6 +99,24 @@ class cMap
{
public:
+ enum eBaseColor
+ {
+ E_BASE_COLOR_TRANSPARENT = 0, /* Air */
+ E_BASE_COLOR_LIGHT_GREEN = 4, /* Grass */
+ E_BASE_COLOR_LIGHT_BROWN = 8, /* Sand */
+ E_BASE_COLOR_GRAY_1 = 12, /* Cloth */
+ E_BASE_COLOR_RED = 16, /* TNT */
+ E_BASE_COLOR_PALE_BLUE = 20, /* Ice */
+ E_BASE_COLOR_GRAY_2 = 24, /* Iron */
+ E_BASE_COLOR_DARK_GREEN = 28, /* Foliage */
+ E_BASE_COLOR_WHITE = 32, /* Snow */
+ E_BASE_COLOR_LIGHT_GRAY = 36, /* Clay */
+ E_BASE_COLOR_BROWN = 40, /* Dirt */
+ E_BASE_COLOR_DARK_GRAY = 44, /* Stone */
+ E_BASE_COLOR_BLUE = 48, /* Water */
+ E_BASE_COLOR_DARK_BROWN = 52 /* Wood */
+ };
+
typedef Byte ColorID;
// tolua_end
--
cgit v1.2.3
From 866fde81ca50f223c88af77d0092a2f4e60f7ce9 Mon Sep 17 00:00:00 2001
From: andrew
Date: Sat, 22 Feb 2014 13:59:49 +0200
Subject: Documented and exported cMap
---
MCServer/Plugins/APIDump/APIDesc.lua | 49 ++++++++++++++++++++++++++++++++++++
src/Bindings/AllToLua.pkg | 1 +
src/Map.cpp | 49 +++++++++++++++++++++++++++++++-----
src/Map.h | 12 ++++++---
4 files changed, 102 insertions(+), 9 deletions(-)
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 73bb5c7fb..296a60640 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -1485,6 +1485,55 @@ a_Player:OpenWindow(Window);
Inherits = "cWindow",
}, -- cLuaWindow
+ cMap =
+ {
+ Desc = [[
+ This class encapsulates a single in-game colored map.
+
+ The contents (i.e. pixel data) of a cMap are dynamically updated by each
+ tracked {{cPlayer}} instance. Furthermore, a cMap maintains and periodically
+ updates a list of map decorators, which are objects drawn on the map that
+ can freely move (e.g. Player and item frame pointers).
+ ]],
+ Functions =
+ {
+ EraseData = { Params = "", Return = "", Notes = "Erases all pixel data." },
+ GetCenterX = { Params = "", Return = "number", Notes = "Returns the X coord of the map's center." },
+ GetCenterZ = { Params = "", Return = "number", Notes = "Returns the Y coord of the map's center." },
+ GetDimension = { Params = "", Return = "eDimension", Notes = "Returns the dimension of the associated world." },
+ GetHeight = { Params = "", Return = "number", Notes = "Returns the height of the map." },
+ GetID = { Params = "", Return = "number", Notes = "Returns the numerical ID of the map. (The item damage value)" },
+ GetName = { Params = "", Return = "string", Notes = "Returns the name of the map." },
+ GetNumPixels = { Params = "", Return = "number", Notes = "Returns the number of pixels in this map." },
+ GetPixel = { Params = "PixelX, PixelZ", Return = "ColorID", Notes = "Returns the color of the specified pixel." },
+ GetPixelWidth = { Params = "", Return = "number", Notes = "Returns the width of a single pixel in blocks." },
+ GetScale = { Params = "", Return = "number", Notes = "Returns the scale of the map. Range: [0,4]" },
+ GetWidth = { Params = "", Return = "number", Notes = "Returns the width of the map." },
+ GetWorld = { Params = "", Return = "cWorld", Notes = "Returns the associated world." },
+ Resize = { Params = "Width, Height", Return = "", Notes = "Resizes the map. WARNING: This will erase the pixel data." },
+ SetPixel = { Params = "PixelX, PixelZ, ColorID", Return = "bool", Notes = "Sets the color of the specified pixel. Returns false on error (Out of range)." },
+ SetPosition = { Params = "CenterX, CenterZ", Return = "", Notes = "Relocates the map. The pixel data will not be modified." },
+ SetScale = { Params = "number", Return = "", Notes = "Rescales the map. The pixel data will not be modified." },
+ },
+ Constants =
+ {
+ E_BASE_COLOR_BLUE = { Notes = "" },
+ E_BASE_COLOR_BROWN = { Notes = "" },
+ E_BASE_COLOR_DARK_BROWN = { Notes = "" },
+ E_BASE_COLOR_DARK_GRAY = { Notes = "" },
+ E_BASE_COLOR_DARK_GREEN = { Notes = "" },
+ E_BASE_COLOR_GRAY_1 = { Notes = "" },
+ E_BASE_COLOR_GRAY_2 = { Notes = "" },
+ E_BASE_COLOR_LIGHT_BROWN = { Notes = "" },
+ E_BASE_COLOR_LIGHT_GRAY = { Notes = "" },
+ E_BASE_COLOR_LIGHT_GREEN = { Notes = "" },
+ E_BASE_COLOR_PALE_BLUE = { Notes = "" },
+ E_BASE_COLOR_RED = { Notes = "" },
+ E_BASE_COLOR_TRANSPARENT = { Notes = "" },
+ E_BASE_COLOR_WHITE = { Notes = "" },
+ },
+ }, -- cMap
+
cMonster =
{
Desc = [[
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index ef61f55f0..dd45a2aab 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -73,6 +73,7 @@ $cfile "../CraftingRecipes.h"
$cfile "../UI/Window.h"
$cfile "../Mobs/Monster.h"
$cfile "../CompositeChat.h"
+$cfile "../Map.h"
diff --git a/src/Map.cpp b/src/Map.cpp
index 87fe9555f..e89fad8b0 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -323,7 +323,7 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
ASSERT(m_World != NULL);
m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb);
- m_Data[a_Z + (a_X * m_Height)] = CalculatePixelCb.GetPixelData();
+ SetPixel(a_X, a_Z, CalculatePixelCb.GetPixelData());
return true;
}
@@ -516,11 +516,6 @@ void cMap::Resize(unsigned int a_Width, unsigned int a_Height)
void cMap::SetPosition(int a_CenterX, int a_CenterZ)
{
- if ((m_CenterX == a_CenterX) && (m_CenterZ == a_CenterZ))
- {
- return;
- }
-
m_CenterX = a_CenterX;
m_CenterZ = a_CenterZ;
}
@@ -548,6 +543,40 @@ void cMap::SetScale(unsigned int a_Scale)
+bool cMap::SetPixel(unsigned int a_X, unsigned int a_Z, cMap::ColorID a_Data)
+{
+ if ((a_X < m_Width) && (a_Z < m_Height))
+ {
+ m_Data[a_Z + (a_X * m_Height)] = a_Data;
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+
+
+
+cMap::ColorID cMap::GetPixel(unsigned int a_X, unsigned int a_Z)
+{
+ if ((a_X < m_Width) && (a_Z < m_Height))
+ {
+ return m_Data[a_Z + (a_X * m_Height)];
+ }
+ else
+ {
+ return E_BASE_COLOR_TRANSPARENT;
+ }
+}
+
+
+
+
+
void cMap::SendTo(cClientHandle & a_Client)
{
a_Client.SendMapInfo(m_ID, m_Scale);
@@ -575,6 +604,14 @@ unsigned int cMap::GetNumPixels(void) const
+unsigned int cMap::GetNumDecorators(void) const
+{
+ return m_Decorators.size();
+}
+
+
+
+
unsigned int cMap::GetPixelWidth(void) const
{
return pow(2, m_Scale);
diff --git a/src/Map.h b/src/Map.h
index a86de3dd3..fc754e6eb 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -155,6 +155,10 @@ public:
void SetScale(unsigned int a_Scale);
+ bool SetPixel(unsigned int a_X, unsigned int a_Z, ColorID a_Data);
+
+ ColorID GetPixel(unsigned int a_X, unsigned int a_Z);
+
unsigned int GetWidth (void) const { return m_Width; }
unsigned int GetHeight(void) const { return m_Height; }
@@ -171,14 +175,16 @@ public:
eDimension GetDimension(void) const;
- const cColorList & GetData(void) const { return m_Data; }
-
unsigned int GetNumPixels(void) const;
unsigned int GetPixelWidth(void) const;
// tolua_end
+ unsigned int GetNumDecorators(void) const;
+
+ const cColorList & GetData(void) const { return m_Data; }
+
protected:
@@ -247,7 +253,7 @@ private:
friend class cMapSerializer;
-};
+}; // tolua_export
--
cgit v1.2.3
From 9fa4fa1cc737a0cf9a078956def206c31a4ebd02 Mon Sep 17 00:00:00 2001
From: andrew
Date: Sun, 23 Feb 2014 12:55:55 +0200
Subject: Documented and exported cMapManager
---
MCServer/Plugins/APIDump/APIDesc.lua | 14 ++++++++++++++
src/Bindings/AllToLua.pkg | 1 +
src/MapManager.h | 8 +++++---
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 296a60640..8265b4e19 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -1534,6 +1534,19 @@ a_Player:OpenWindow(Window);
},
}, -- cMap
+ cMapManager =
+ {
+ Desc = [[
+ This class is associated with a single {{cWorld}} instance and manages a list of maps.
+ ]],
+ Functions =
+ {
+ DoWithMap = { Params = "ID, Callback", Return = "bool", Notes = "Calls the callback for the map with the specified ID. Returns true if the map was found and the callback called, false if map not found." },
+ GetNumMaps = { Params = "", Return = "number", Notes = "Returns the number of registered maps." },
+ },
+
+ }, -- cMapManager
+
cMonster =
{
Desc = [[
@@ -2289,6 +2302,7 @@ World:ForEachEntity(
]],
},
}, -- AdditionalInfo
+ Inherits = "cMapManager"
}, -- cWorld
HTTPFormData =
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index dd45a2aab..4fd5a68b8 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -74,6 +74,7 @@ $cfile "../UI/Window.h"
$cfile "../Mobs/Monster.h"
$cfile "../CompositeChat.h"
$cfile "../Map.h"
+$cfile "../MapManager.h"
diff --git a/src/MapManager.h b/src/MapManager.h
index 05673c694..5da8be035 100644
--- a/src/MapManager.h
+++ b/src/MapManager.h
@@ -21,11 +21,13 @@ typedef cItemCallback cMapCallback;
+// tolua_begin
/** Manages the in-game maps of a single world - Thread safe. */
class cMapManager
{
public:
+ // tolua_end
cMapManager(cWorld * a_World);
@@ -43,7 +45,7 @@ public:
* Returns true if the map was found and the callback called, false if map not found.
* Callback return ignored.
*/
- bool DoWithMap(unsigned int a_ID, cMapCallback & a_Callback);
+ bool DoWithMap(unsigned int a_ID, cMapCallback & a_Callback); // tolua_export
/** Calls the callback for each map.
*
@@ -51,7 +53,7 @@ public:
*/
bool ForEachMap(cMapCallback & a_Callback);
- unsigned int GetNumMaps(void) const;
+ unsigned int GetNumMaps(void) const; // tolua_export
/** Loads the map data from the disk */
void LoadMapData(void);
@@ -70,7 +72,7 @@ private:
cWorld * m_World;
-};
+}; // tolua_export
--
cgit v1.2.3
From 30b22e9f59e0873be84e80c83d274dbe5353b835 Mon Sep 17 00:00:00 2001
From: andrew
Date: Sun, 23 Feb 2014 13:25:02 +0200
Subject: Manually exported DoWithMap
---
MCServer/Plugins/APIDump/APIDesc.lua | 2 +-
src/Bindings/ManualBindings.cpp | 4 ++++
src/Map.h | 5 +++++
src/MapManager.cpp | 2 +-
src/MapManager.h | 2 +-
5 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 8265b4e19..c8811df66 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -1541,7 +1541,7 @@ a_Player:OpenWindow(Window);
]],
Functions =
{
- DoWithMap = { Params = "ID, Callback", Return = "bool", Notes = "Calls the callback for the map with the specified ID. Returns true if the map was found and the callback called, false if map not found." },
+ DoWithMap = { Params = "ID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If a map with the specified ID exists, calls the CallbackFunction for that map. The CallbackFunction has the following signature: function Callback({{cMap|Map}}, [CallbackData])
Returns true if the map was found and the callback called, false if map not found." },
GetNumMaps = { Params = "", Return = "number", Notes = "Returns the number of registered maps." },
},
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index c220e5e0a..f2d21a682 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -2511,6 +2511,10 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines);
tolua_endmodule(tolua_S);
+ tolua_beginmodule(tolua_S, "cMapManager");
+ tolua_function(tolua_S, "DoWithMap", tolua_DoWithID);
+ tolua_endmodule(tolua_S);
+
tolua_beginmodule(tolua_S, "cPlugin");
tolua_function(tolua_S, "Call", tolua_cPlugin_Call);
tolua_endmodule(tolua_S);
diff --git a/src/Map.h b/src/Map.h
index fc754e6eb..a6df7e5f2 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -185,6 +185,11 @@ public:
const cColorList & GetData(void) const { return m_Data; }
+ static const char * GetClassStatic(void) // Needed for ManualBindings's DoWith templates
+ {
+ return "cMap";
+ }
+
protected:
diff --git a/src/MapManager.cpp b/src/MapManager.cpp
index 2fc44ccc8..9d02eafb4 100644
--- a/src/MapManager.cpp
+++ b/src/MapManager.cpp
@@ -22,7 +22,7 @@ cMapManager::cMapManager(cWorld * a_World)
-bool cMapManager::DoWithMap(unsigned int a_ID, cMapCallback & a_Callback)
+bool cMapManager::DoWithMap(int a_ID, cMapCallback & a_Callback)
{
cCSLock Lock(m_CS);
cMap * Map = GetMapData(a_ID);
diff --git a/src/MapManager.h b/src/MapManager.h
index 5da8be035..80e6d16d1 100644
--- a/src/MapManager.h
+++ b/src/MapManager.h
@@ -45,7 +45,7 @@ public:
* Returns true if the map was found and the callback called, false if map not found.
* Callback return ignored.
*/
- bool DoWithMap(unsigned int a_ID, cMapCallback & a_Callback); // tolua_export
+ bool DoWithMap(int a_ID, cMapCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for each map.
*
--
cgit v1.2.3
From f47187394572027cbfa07884cba2f54eaa6972ec Mon Sep 17 00:00:00 2001
From: andrew
Date: Sun, 23 Feb 2014 15:03:40 +0200
Subject: Maps: Improvements
---
MCServer/Plugins/APIDump/APIDesc.lua | 4 ++--
src/Items/ItemEmptyMap.h | 2 +-
src/Items/ItemMap.h | 2 +-
src/Map.cpp | 12 +++++++++---
src/Map.h | 2 +-
src/World.cpp | 6 +++---
src/World.h | 9 ++++++---
src/WorldStorage/MapSerializer.h | 6 +++++-
8 files changed, 28 insertions(+), 15 deletions(-)
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index c8811df66..8e9d239fa 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -2165,7 +2165,8 @@ end
GetGeneratorQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks that are queued in the chunk generator." },
GetHeight = { Params = "BlockX, BlockZ", Return = "number", Notes = "Returns the maximum height of the particula block column in the world. If the chunk is not loaded, it waits for it to load / generate. WARNING: Do not use, Use TryGetHeight() instead for a non-waiting version, otherwise you run the risk of a deadlock!" },
GetIniFileName = { Params = "", Return = "string", Notes = "Returns the name of the world.ini file that the world uses to store the information." },
- GetLightingQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks in the lighting thread's queue." },
+ GetLightingQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks in the lighting thread's queue." },
+ GetMapManager = { Params = "", Return = "{{cMapManager}}", Notes = "Returns the {{cMapManager|MapManager}} object used by this world." },
GetMaxCactusHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which cacti will grow naturally." },
GetMaxSugarcaneHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which sugarcane will grow naturally." },
GetName = { Params = "", Return = "string", Notes = "Returns the name of the world, as specified in the settings.ini file." },
@@ -2302,7 +2303,6 @@ World:ForEachEntity(
]],
},
}, -- AdditionalInfo
- Inherits = "cMapManager"
}, -- cWorld
HTTPFormData =
diff --git a/src/Items/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h
index b06cf9d13..db28511f3 100644
--- a/src/Items/ItemEmptyMap.h
+++ b/src/Items/ItemEmptyMap.h
@@ -41,7 +41,7 @@ public:
int CenterX = round(a_Player->GetPosX() / (float) RegionWidth) * RegionWidth;
int CenterZ = round(a_Player->GetPosZ() / (float) RegionWidth) * RegionWidth;
- cMap * NewMap = a_World->CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
+ cMap * NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
// Remove empty map from inventory
if (!a_Player->GetInventory().RemoveOneEquippedItem())
diff --git a/src/Items/ItemMap.h b/src/Items/ItemMap.h
index 9bb16b189..e8ff9da88 100644
--- a/src/Items/ItemMap.h
+++ b/src/Items/ItemMap.h
@@ -29,7 +29,7 @@ public:
virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item)
{
- cMap * Map = a_World->GetMapData(a_Item.m_ItemDamage);
+ cMap * Map = a_World->GetMapManager().GetMapData(a_Item.m_ItemDamage);
if (Map == NULL)
{
diff --git a/src/Map.cpp b/src/Map.cpp
index e89fad8b0..2b8c4c74c 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -344,13 +344,19 @@ void cMap::UpdateDecorators(void)
-void cMap::AddPlayer(cPlayer * a_Player, cClientHandle * a_Handle, Int64 a_WorldAge)
+void cMap::AddPlayer(cPlayer * a_Player, Int64 a_WorldAge)
{
+ cClientHandle * Handle = a_Player->GetClientHandle();
+ if (Handle == NULL)
+ {
+ return;
+ }
+
cMapClient MapClient;
MapClient.m_LastUpdate = a_WorldAge;
MapClient.m_SendInfo = true;
- MapClient.m_Handle = a_Handle;
+ MapClient.m_Handle = Handle;
m_Clients.push_back(MapClient);
@@ -470,7 +476,7 @@ void cMap::UpdateClient(cPlayer * a_Player)
}
// New player, construct a new client state
- AddPlayer(a_Player, Handle, WorldAge);
+ AddPlayer(a_Player, WorldAge);
}
diff --git a/src/Map.h b/src/Map.h
index a6df7e5f2..a313d5431 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -226,7 +226,7 @@ private:
bool UpdatePixel(unsigned int a_X, unsigned int a_Z);
/** Add a new map client. */
- void AddPlayer(cPlayer * a_Player, cClientHandle * a_Handle, Int64 a_WorldAge);
+ void AddPlayer(cPlayer * a_Player, Int64 a_WorldAge);
/** Remove inactive or invalid clients. */
void RemoveInactiveClients(Int64 a_WorldAge);
diff --git a/src/World.cpp b/src/World.cpp
index 01fdae697..4870e7d6e 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -233,7 +233,6 @@ void cWorld::cTickThread::Execute(void)
// cWorld:
cWorld::cWorld(const AString & a_WorldName) :
- cMapManager(this),
m_WorldName(a_WorldName),
m_IniFileName(m_WorldName + "/world.ini"),
m_StorageSchema("Default"),
@@ -254,6 +253,7 @@ cWorld::cWorld(const AString & a_WorldName) :
m_bCommandBlocksEnabled(false),
m_bUseChatPrefixes(true),
m_Scoreboard(this),
+ m_MapManager(this),
m_GeneratorCallbacks(*this),
m_TickThread(*this)
{
@@ -265,7 +265,7 @@ cWorld::cWorld(const AString & a_WorldName) :
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
Serializer.Load();
- LoadMapData();
+ m_MapManager.LoadMapData();
}
@@ -289,7 +289,7 @@ cWorld::~cWorld()
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
Serializer.Save();
- SaveMapData();
+ m_MapManager.SaveMapData();
delete m_ChunkMap;
}
diff --git a/src/World.h b/src/World.h
index f05ea9b2a..4b74f7aba 100644
--- a/src/World.h
+++ b/src/World.h
@@ -71,8 +71,7 @@ typedef cItemCallback cMobHeadBlockCallback;
class cWorld :
public cForEachChunkProvider,
public cWorldInterface,
- public cBroadcastInterface,
- public cMapManager
+ public cBroadcastInterface
{
public:
@@ -582,9 +581,12 @@ public:
/** Returns the name of the world.ini file used by this world */
const AString & GetIniFileName(void) const {return m_IniFileName; }
- /** Returns the associated scoreboard instance */
+ /** Returns the associated scoreboard instance. */
cScoreboard & GetScoreBoard(void) { return m_Scoreboard; }
+ /** Returns the associated map manager instance. */
+ cMapManager & GetMapManager(void) { return m_MapManager; }
+
bool AreCommandBlocksEnabled(void) const { return m_bCommandBlocksEnabled; }
void SetCommandBlocksEnabled(bool a_Flag) { m_bCommandBlocksEnabled = a_Flag; }
@@ -850,6 +852,7 @@ private:
cChunkGenerator m_Generator;
cScoreboard m_Scoreboard;
+ cMapManager m_MapManager;
/** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
cChunkGeneratorCallbacks m_GeneratorCallbacks;
diff --git a/src/WorldStorage/MapSerializer.h b/src/WorldStorage/MapSerializer.h
index 85fe917f5..eb7678a08 100644
--- a/src/WorldStorage/MapSerializer.h
+++ b/src/WorldStorage/MapSerializer.h
@@ -51,7 +51,11 @@ private:
-/** Utility class used to serialize item ID counts. */
+/** Utility class used to serialize item ID counts.
+ *
+ * In order to perform bounds checking (while loading),
+ * the last registered ID of each item is serialized to an NBT file.
+ */
class cIDCountSerializer
{
public:
--
cgit v1.2.3