From f201f4f176fc908e9ddebfed86d4c8ef5582556c Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 20 Feb 2014 16:38:37 +0200 Subject: [PATCH] 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: