aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/collision/Management/MMapManager.cpp65
-rw-r--r--src/server/collision/Management/MMapManager.h5
-rw-r--r--src/server/collision/Management/VMapFactory.cpp2
-rw-r--r--src/server/collision/Management/VMapManager2.cpp49
-rw-r--r--src/server/collision/Management/VMapManager2.h4
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp6
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp2
-rw-r--r--src/server/game/Battlegrounds/Battleground.h1
-rw-r--r--src/server/game/Chat/Chat.h12
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp28
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp13
-rw-r--r--src/server/game/Maps/Map.cpp20
-rw-r--r--src/server/game/Server/WorldSocket.cpp2
-rw-r--r--src/server/game/Spells/SpellMgr.cpp5
-rw-r--r--src/server/game/World/World.cpp11
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp1
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_erekem.cpp2
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp4
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp2
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_moragg.cpp2
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp4
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp2
-rw-r--r--src/server/shared/Common.h11
-rw-r--r--src/server/shared/Database/DatabaseWorkerPool.h44
-rw-r--r--src/server/shared/Database/QueryHolder.h7
-rw-r--r--src/server/shared/Database/Transaction.h7
-rw-r--r--src/server/shared/Logging/Log.cpp7
-rw-r--r--src/server/shared/Logging/Log.h19
-rw-r--r--src/server/shared/PrecompiledHeaders/sharedPCH.h1
-rw-r--r--src/server/shared/Threading/ProducerConsumerQueue.h3
-rw-r--r--src/server/shared/Utilities/Duration.h39
-rw-r--r--src/server/shared/Utilities/EventMap.cpp136
-rw-r--r--src/server/shared/Utilities/EventMap.h341
-rw-r--r--src/server/shared/Utilities/StringFormat.h22
-rw-r--r--src/server/shared/Utilities/TaskScheduler.h13
-rw-r--r--src/server/shared/Utilities/Timer.h4
-rw-r--r--src/server/shared/Utilities/Util.cpp9
-rw-r--r--src/server/shared/Utilities/Util.h342
39 files changed, 771 insertions, 477 deletions
diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp
index 847b7bbd001..b71b94e3291 100644
--- a/src/server/collision/Management/MMapManager.cpp
+++ b/src/server/collision/Management/MMapManager.cpp
@@ -32,11 +32,41 @@ namespace MMAP
// if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
}
+ void MMapManager::InitializeThreadUnsafe(const std::vector<uint32>& mapIds)
+ {
+ // the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime
+ for (const uint32& mapId : mapIds)
+ loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr));
+
+ thread_safe_environment = false;
+ }
+
+ MMapDataSet::const_iterator MMapManager::GetMMapData(uint32 mapId) const
+ {
+ // return the iterator if found or end() if not found/NULL
+ MMapDataSet::const_iterator itr = loadedMMaps.find(mapId);
+ if (itr != loadedMMaps.cend() && !itr->second)
+ itr = loadedMMaps.cend();
+
+ return itr;
+ }
+
bool MMapManager::loadMapData(uint32 mapId)
{
// we already have this map loaded?
- if (loadedMMaps.find(mapId) != loadedMMaps.end())
- return true;
+ MMapDataSet::iterator itr = loadedMMaps.find(mapId);
+ if (itr != loadedMMaps.end())
+ {
+ if (itr->second)
+ return true;
+ }
+ else
+ {
+ if (thread_safe_environment)
+ itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first;
+ else
+ ASSERT(false, "Invalid mapId %u passed to MMapManager after startup in thread unsafe environment", mapId);
+ }
// load and init dtNavMesh - read parameters from file
uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i.mmap")+1;
@@ -79,7 +109,7 @@ namespace MMAP
MMapData* mmap_data = new MMapData(mesh);
mmap_data->mmapLoadedTiles.clear();
- loadedMMaps.insert(std::pair<uint32, MMapData*>(mapId, mmap_data));
+ itr->second = mmap_data;
return true;
}
@@ -165,21 +195,20 @@ namespace MMAP
dtFree(data);
return false;
}
-
- return false;
}
bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y)
{
// check if we have this map loaded
- if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ MMapDataSet::const_iterator itr = GetMMapData(mapId);
+ if (itr == loadedMMaps.end())
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y);
return false;
}
- MMapData* mmap = loadedMMaps[mapId];
+ MMapData* mmap = itr->second;
// check if we have this tile loaded
uint32 packedGridPos = packTileID(x, y);
@@ -214,7 +243,8 @@ namespace MMAP
bool MMapManager::unloadMap(uint32 mapId)
{
- if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ MMapDataSet::iterator itr = loadedMMaps.find(mapId);
+ if (itr == loadedMMaps.end() || !itr->second)
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId);
@@ -222,7 +252,7 @@ namespace MMAP
}
// unload all tiles from given map
- MMapData* mmap = loadedMMaps[mapId];
+ MMapData* mmap = itr->second;
for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i)
{
uint32 x = (i->first >> 16);
@@ -237,7 +267,7 @@ namespace MMAP
}
delete mmap;
- loadedMMaps.erase(mapId);
+ itr->second = nullptr;
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId);
return true;
@@ -246,14 +276,15 @@ namespace MMAP
bool MMapManager::unloadMapInstance(uint32 mapId, uint32 instanceId)
{
// check if we have this map loaded
- if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ MMapDataSet::const_iterator itr = GetMMapData(mapId);
+ if (itr == loadedMMaps.end())
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId);
return false;
}
- MMapData* mmap = loadedMMaps[mapId];
+ MMapData* mmap = itr->second;
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
{
TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId);
@@ -271,18 +302,20 @@ namespace MMAP
dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId)
{
- if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ MMapDataSet::const_iterator itr = GetMMapData(mapId);
+ if (itr == loadedMMaps.end())
return NULL;
- return loadedMMaps[mapId]->navMesh;
+ return itr->second->navMesh;
}
dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId)
{
- if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ MMapDataSet::const_iterator itr = GetMMapData(mapId);
+ if (itr == loadedMMaps.end())
return NULL;
- MMapData* mmap = loadedMMaps[mapId];
+ MMapData* mmap = itr->second;
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
{
// allocate mesh query
diff --git a/src/server/collision/Management/MMapManager.h b/src/server/collision/Management/MMapManager.h
index ac01a3c5693..f51f6ecd981 100644
--- a/src/server/collision/Management/MMapManager.h
+++ b/src/server/collision/Management/MMapManager.h
@@ -60,9 +60,10 @@ namespace MMAP
class MMapManager
{
public:
- MMapManager() : loadedTiles(0) { }
+ MMapManager() : loadedTiles(0), thread_safe_environment(true) {}
~MMapManager();
+ void InitializeThreadUnsafe(const std::vector<uint32>& mapIds);
bool loadMap(const std::string& basePath, uint32 mapId, int32 x, int32 y);
bool unloadMap(uint32 mapId, int32 x, int32 y);
bool unloadMap(uint32 mapId);
@@ -78,8 +79,10 @@ namespace MMAP
bool loadMapData(uint32 mapId);
uint32 packTileID(int32 x, int32 y);
+ MMapDataSet::const_iterator GetMMapData(uint32 mapId) const;
MMapDataSet loadedMMaps;
uint32 loadedTiles;
+ bool thread_safe_environment;
};
}
diff --git a/src/server/collision/Management/VMapFactory.cpp b/src/server/collision/Management/VMapFactory.cpp
index e3e211268e0..4c2750a9e5c 100644
--- a/src/server/collision/Management/VMapFactory.cpp
+++ b/src/server/collision/Management/VMapFactory.cpp
@@ -27,7 +27,7 @@ namespace VMAP
// just return the instance
IVMapManager* VMapFactory::createOrGetVMapManager()
{
- if (gVMapManager == 0)
+ if (gVMapManager == nullptr)
gVMapManager= new VMapManager2(); // should be taken from config ... Please change if you like :-)
return gVMapManager;
}
diff --git a/src/server/collision/Management/VMapManager2.cpp b/src/server/collision/Management/VMapManager2.cpp
index f9fcff96ad2..a1cdb5502a9 100644
--- a/src/server/collision/Management/VMapManager2.cpp
+++ b/src/server/collision/Management/VMapManager2.cpp
@@ -37,6 +37,7 @@ namespace VMAP
{
GetLiquidFlagsPtr = &GetLiquidFlagsDummy;
IsVMAPDisabledForPtr = &IsVMAPDisabledForDummy;
+ thread_safe_environment = true;
}
VMapManager2::~VMapManager2(void)
@@ -51,6 +52,15 @@ namespace VMAP
}
}
+ void VMapManager2::InitializeThreadUnsafe(const std::vector<uint32>& mapIds)
+ {
+ // the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime
+ for (const uint32& mapId : mapIds)
+ iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, nullptr));
+
+ thread_safe_environment = false;
+ }
+
Vector3 VMapManager2::convertPositionToInternalRep(float x, float y, float z) const
{
Vector3 pos;
@@ -86,12 +96,31 @@ namespace VMAP
return result;
}
+ InstanceTreeMap::const_iterator VMapManager2::GetMapTree(uint32 mapId) const
+ {
+ // return the iterator if found or end() if not found/NULL
+ InstanceTreeMap::const_iterator itr = iInstanceMapTrees.find(mapId);
+ if (itr != iInstanceMapTrees.cend() && !itr->second)
+ itr = iInstanceMapTrees.cend();
+
+ return itr;
+ }
+
// load one tile (internal use only)
bool VMapManager2::_loadMap(unsigned int mapId, const std::string& basePath, uint32 tileX, uint32 tileY)
{
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
if (instanceTree == iInstanceMapTrees.end())
{
+ if (thread_safe_environment)
+ instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, nullptr)).first;
+ else
+ ASSERT(false, "Invalid mapId %u tile [%u, %u] passed to VMapManager2 after startup in thread unsafe environment",
+ mapId, tileX, tileY);
+ }
+
+ if (!instanceTree->second)
+ {
std::string mapFileName = getMapFileName(mapId);
StaticMapTree* newTree = new StaticMapTree(mapId, basePath);
if (!newTree->InitMap(mapFileName, this))
@@ -99,7 +128,7 @@ namespace VMAP
delete newTree;
return false;
}
- instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, newTree)).first;
+ instanceTree->second = newTree;
}
return instanceTree->second->LoadMapTile(tileX, tileY, this);
@@ -108,13 +137,13 @@ namespace VMAP
void VMapManager2::unloadMap(unsigned int mapId)
{
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
- if (instanceTree != iInstanceMapTrees.end())
+ if (instanceTree != iInstanceMapTrees.end() && instanceTree->second)
{
instanceTree->second->UnloadMap(this);
if (instanceTree->second->numLoadedTiles() == 0)
{
delete instanceTree->second;
- iInstanceMapTrees.erase(mapId);
+ instanceTree->second = nullptr;
}
}
}
@@ -122,13 +151,13 @@ namespace VMAP
void VMapManager2::unloadMap(unsigned int mapId, int x, int y)
{
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
- if (instanceTree != iInstanceMapTrees.end())
+ if (instanceTree != iInstanceMapTrees.end() && instanceTree->second)
{
instanceTree->second->UnloadMapTile(x, y, this);
if (instanceTree->second->numLoadedTiles() == 0)
{
delete instanceTree->second;
- iInstanceMapTrees.erase(mapId);
+ instanceTree->second = nullptr;
}
}
}
@@ -138,7 +167,7 @@ namespace VMAP
if (!isLineOfSightCalcEnabled() || IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS))
return true;
- InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
+ InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
if (instanceTree != iInstanceMapTrees.end())
{
Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1);
@@ -160,7 +189,7 @@ namespace VMAP
{
if (isLineOfSightCalcEnabled() && !IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS))
{
- InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
+ InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
if (instanceTree != iInstanceMapTrees.end())
{
Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1);
@@ -190,7 +219,7 @@ namespace VMAP
{
if (isHeightCalcEnabled() && !IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_HEIGHT))
{
- InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
+ InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
if (instanceTree != iInstanceMapTrees.end())
{
Vector3 pos = convertPositionToInternalRep(x, y, z);
@@ -209,7 +238,7 @@ namespace VMAP
{
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG))
{
- InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(mapId);
+ InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
if (instanceTree != iInstanceMapTrees.end())
{
Vector3 pos = convertPositionToInternalRep(x, y, z);
@@ -227,7 +256,7 @@ namespace VMAP
{
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS))
{
- InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(mapId);
+ InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
if (instanceTree != iInstanceMapTrees.end())
{
LocationInfo info;
diff --git a/src/server/collision/Management/VMapManager2.h b/src/server/collision/Management/VMapManager2.h
index e13d5ab952b..af04fa0d970 100644
--- a/src/server/collision/Management/VMapManager2.h
+++ b/src/server/collision/Management/VMapManager2.h
@@ -80,6 +80,7 @@ namespace VMAP
// Tree to check collision
ModelFileMap iLoadedModelFiles;
InstanceTreeMap iInstanceMapTrees;
+ bool thread_safe_environment;
// Mutex for iLoadedModelFiles
std::mutex LoadedModelFilesLock;
@@ -89,6 +90,8 @@ namespace VMAP
static uint32 GetLiquidFlagsDummy(uint32) { return 0; }
static bool IsVMAPDisabledForDummy(uint32 /*entry*/, uint8 /*flags*/) { return false; }
+ InstanceTreeMap::const_iterator GetMapTree(uint32 mapId) const;
+
public:
// public for debug
G3D::Vector3 convertPositionToInternalRep(float x, float y, float z) const;
@@ -97,6 +100,7 @@ namespace VMAP
VMapManager2();
~VMapManager2(void);
+ void InitializeThreadUnsafe(const std::vector<uint32>& mapIds);
int loadMap(const char* pBasePath, unsigned int mapId, int x, int y) override;
void unloadMap(unsigned int mapId, int x, int y) override;
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index efe55830b1b..1939c96dac9 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -22,6 +22,7 @@
#include "Define.h"
#include "Unit.h"
#include "Containers.h"
+#include "EventMap.h"
#include <list>
class Player;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 37187d9b04c..013acd2e314 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -1228,11 +1228,11 @@ bool SmartAIMgr::IsTextValid(SmartScriptHolder const& e, uint32 id)
default:
if (e.entryOrGuid < 0)
{
- entry = uint32(std::abs(e.entryOrGuid));
- CreatureData const* data = sObjectMgr->GetCreatureData(entry);
+ ObjectGuid::LowType guid = ObjectGuid::LowType(-e.entryOrGuid);
+ CreatureData const* data = sObjectMgr->GetCreatureData(guid);
if (!data)
{
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u using non-existent Creature guid %d, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u using non-existent Creature guid %d, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), guid);
return false;
}
else
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index 16d5f4b6959..4b48f1f341b 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -293,7 +293,7 @@ void AuctionHouseMgr::LoadAuctionItems()
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
if (!proto)
{
- TC_LOG_ERROR("misc", "AuctionHouseMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped.", item_guid, itemEntry);
+ TC_LOG_ERROR("misc", "AuctionHouseMgr::LoadAuctionItems: Unknown item (GUID: %u item entry: #%u) in auction, skipped.", item_guid, itemEntry);
continue;
}
diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h
index 562a20b340f..08134298569 100644
--- a/src/server/game/Battlegrounds/Battleground.h
+++ b/src/server/game/Battlegrounds/Battleground.h
@@ -26,6 +26,7 @@
#include "WorldPacket.h"
#include "Object.h"
#include "GameObject.h"
+#include "EventMap.h"
class Creature;
class GameObject;
diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h
index ba59245cdaa..1b095534ad0 100644
--- a/src/server/game/Chat/Chat.h
+++ b/src/server/game/Chat/Chat.h
@@ -71,21 +71,21 @@ class ChatHandler
void SendSysMessage(uint32 entry);
template<typename... Args>
- void PSendSysMessage(const char* fmt, Args const&... args)
+ void PSendSysMessage(const char* fmt, Args&&... args)
{
- SendSysMessage(Trinity::StringFormat(fmt, args...).c_str());
+ SendSysMessage(Trinity::StringFormat(fmt, std::forward<Args>(args)...).c_str());
}
template<typename... Args>
- void PSendSysMessage(uint32 entry, Args const&... args)
+ void PSendSysMessage(uint32 entry, Args&&... args)
{
- SendSysMessage(PGetParseString(entry, args...).c_str());
+ SendSysMessage(PGetParseString(entry, std::forward<Args>(args)...).c_str());
}
template<typename... Args>
- std::string PGetParseString(uint32 entry, Args const&... args) const
+ std::string PGetParseString(uint32 entry, Args&&... args) const
{
- return Trinity::StringFormat(GetTrinityString(entry), args...);
+ return Trinity::StringFormat(GetTrinityString(entry), std::forward<Args>(args)...);
}
bool ParseCommands(const char* text);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index acf7dcb79e9..c65e52c8de7 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -6527,13 +6527,10 @@ void ObjectMgr::LoadGameObjectLocales()
{
uint32 oldMSTime = getMSTime();
- _gameObjectLocaleStore.clear(); // need for reload case
-
- QueryResult result = WorldDatabase.Query("SELECT entry, "
- "name_loc1, name_loc2, name_loc3, name_loc4, name_loc5, name_loc6, name_loc7, name_loc8, "
- "castbarcaption_loc1, castbarcaption_loc2, castbarcaption_loc3, castbarcaption_loc4, "
- "castbarcaption_loc5, castbarcaption_loc6, castbarcaption_loc7, castbarcaption_loc8 FROM locales_gameobject");
+ _gameObjectLocaleStore.clear(); // need for reload case
+ // 0 1 2 3
+ QueryResult result = WorldDatabase.Query("SELECT entry, locale, name, castBarCaption FROM gameobject_template_locale");
if (!result)
return;
@@ -6541,18 +6538,21 @@ void ObjectMgr::LoadGameObjectLocales()
{
Field* fields = result->Fetch();
- uint32 entry = fields[0].GetUInt32();
+ uint32 id = fields[0].GetUInt32();
+ std::string localeName = fields[1].GetString();
- GameObjectLocale& data = _gameObjectLocaleStore[entry];
+ std::string name = fields[2].GetString();
+ std::string castBarCaption = fields[3].GetString();
+
+ GameObjectLocale& data = _gameObjectLocaleStore[id];
+ LocaleConstant locale = GetLocaleByName(localeName);
+
+ AddLocaleString(name, locale, data.Name);
+ AddLocaleString(castBarCaption, locale, data.CastBarCaption);
- for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i)
- {
- AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.Name);
- AddLocaleString(fields[i + (TOTAL_LOCALES - 1)].GetString(), LocaleConstant(i), data.CastBarCaption);
- }
} while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u gameobject locale strings in %u ms", uint32(_gameObjectLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded %u gameobject_template_locale strings in %u ms", uint32(_gameObjectLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime));
}
inline void CheckGOLockId(GameObjectTemplate const* goInfo, uint32 dataN, uint32 N)
diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp
index 03782481ef7..fda3551bf2b 100644
--- a/src/server/game/Handlers/QueryHandler.cpp
+++ b/src/server/game/Handlers/QueryHandler.cpp
@@ -174,15 +174,14 @@ void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recvData)
IconName = info->IconName;
CastBarCaption = info->castBarCaption;
- int loc_idx = GetSessionDbLocaleIndex();
- if (loc_idx >= 0)
- {
- if (GameObjectLocale const* gl = sObjectMgr->GetGameObjectLocale(entry))
+ LocaleConstant localeConstant = GetSessionDbLocaleIndex();
+ if (localeConstant >= LOCALE_enUS)
+ if (GameObjectLocale const* gameObjectLocale = sObjectMgr->GetGameObjectLocale(entry))
{
- ObjectMgr::GetLocaleString(gl->Name, loc_idx, Name);
- ObjectMgr::GetLocaleString(gl->CastBarCaption, loc_idx, CastBarCaption);
+ ObjectMgr::GetLocaleString(gameObjectLocale->Name, localeConstant, Name);
+ ObjectMgr::GetLocaleString(gameObjectLocale->CastBarCaption, localeConstant, CastBarCaption);
}
- }
+
TC_LOG_DEBUG("network", "WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name.c_str(), entry);
WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 150);
data << uint32(entry);
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 585533fa21b..354bbe4e269 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -317,7 +317,15 @@ void Map::SwitchGridContainers(Creature* obj, bool on)
if (!IsGridLoaded(GridCoord(cell.data.Part.grid_x, cell.data.Part.grid_y)))
return;
- TC_LOG_DEBUG("maps", "Switch object %s from grid[%u, %u] %u", obj->GetGUID().ToString().c_str(), cell.data.Part.grid_x, cell.data.Part.grid_y, on);
+ if (sLog->ShouldLog("maps", LOG_LEVEL_DEBUG))
+ {
+ // Extract bitfield values
+ uint32 const grid_x = cell.data.Part.grid_x;
+ uint32 const grid_y = cell.data.Part.grid_y;
+
+ TC_LOG_DEBUG("maps", "Switch object %s from grid[%u, %u] %u", obj->GetGUID().ToString().c_str(), grid_x, grid_y, on);
+ }
+
NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY());
ASSERT(ngrid != NULL);
@@ -354,7 +362,15 @@ void Map::SwitchGridContainers(GameObject* obj, bool on)
if (!IsGridLoaded(GridCoord(cell.data.Part.grid_x, cell.data.Part.grid_y)))
return;
- TC_LOG_DEBUG("maps", "Switch object %s from grid[%u, %u] %u", obj->GetGUID().ToString().c_str(), cell.data.Part.grid_x, cell.data.Part.grid_y, on);
+ if (sLog->ShouldLog("maps", LOG_LEVEL_DEBUG))
+ {
+ // Extract bitfield values
+ uint32 const grid_x = cell.data.Part.grid_x;
+ uint32 const grid_y = cell.data.Part.grid_y;
+
+ TC_LOG_DEBUG("maps", "Switch object %s from grid[%u, %u] %u", obj->GetGUID().ToString().c_str(), grid_x, grid_y, on);
+ }
+
NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY());
ASSERT(ngrid != NULL);
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index cff423c71c6..be70d67b4de 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -509,6 +509,8 @@ void WorldSocket::SendAuthResponseError(uint8 code)
bool WorldSocket::HandlePing(WorldPacket& recvPacket)
{
+ using namespace std::chrono;
+
uint32 ping;
uint32 latency;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index b63f0571ac5..54262d8f2e4 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3158,6 +3158,11 @@ void SpellMgr::LoadSpellInfoCorrections()
// add corruption to affected spells
spellInfo->Effects[EFFECT_1].SpellClassMask[0] |= 2;
break;
+ case 57470: // Renewed Hope (Rank 1)
+ case 57472: // Renewed Hope (Rank 2)
+ // should also affect Flash Heal
+ spellInfo->Effects[EFFECT_0].SpellClassMask[0] |= 0x800;
+ break;
case 51852: // The Eye of Acherus (no spawn in phase 2 in db)
spellInfo->Effects[EFFECT_0].MiscValue |= 1;
break;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 7cddfc3f61e..fc79f351a54 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1375,6 +1375,17 @@ void World::SetInitialWorldSettings()
LoadDBCStores(m_dataPath);
DetectDBCLang();
+ std::vector<uint32> mapIds;
+ for (uint32 mapId = 0; mapId < sMapStore.GetNumRows(); mapId++)
+ if (sMapStore.LookupEntry(mapId))
+ mapIds.push_back(mapId);
+
+ if (VMAP::VMapManager2* vmmgr2 = dynamic_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager()))
+ vmmgr2->InitializeThreadUnsafe(mapIds);
+
+ MMAP::MMapManager* mmmgr = MMAP::MMapFactory::createOrGetMMapManager();
+ mmmgr->InitializeThreadUnsafe(mapIds);
+
TC_LOG_INFO("server.loading", "Loading SpellInfo store...");
sSpellMgr->LoadSpellInfoStore();
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
index 326360428d2..b37d505d766 100644
--- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
@@ -152,6 +152,7 @@ public:
if (id == 1)
{
wait_timer = 5000;
+ me->LoadEquipment(1);
me->CastSpell(me, SPELL_DK_INITIATE_VISUAL, true);
if (Player* starter = ObjectAccessor::GetPlayer(*me, playerGUID))
diff --git a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
index 1f9fc6d7981..2baa5d60221 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
@@ -254,7 +254,7 @@ public:
else
breakBondsCd -= diff;
- switch (uint32 eventId = events.ExecuteEvent())
+ switch (events.ExecuteEvent())
{
case EVENT_EARTH_SHIELD:
if (Unit* ally = DoSelectLowestHpFriendly(30.0f))
diff --git a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
index cfdacb10896..25f063e451a 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
@@ -345,7 +345,7 @@ public:
events.Update(diff);
- switch (uint32 eventId = events.ExecuteEvent())
+ switch (events.ExecuteEvent())
{
case EVENT_WATER_BLAST:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
@@ -398,7 +398,7 @@ public:
events.Update(diff);
- switch (uint32 eventId = events.ExecuteEvent())
+ switch (events.ExecuteEvent())
{
case EVENT_WATER_BLAST:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
diff --git a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
index 8dc0e32fb31..8b77b512ca4 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
@@ -106,7 +106,7 @@ public:
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- switch (uint32 eventId = events.ExecuteEvent())
+ switch (events.ExecuteEvent())
{
case EVENT_FIREBOLT:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
diff --git a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
index f9e223d3bab..8662e7f6669 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
@@ -108,7 +108,7 @@ public:
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- switch (uint32 eventId = events.ExecuteEvent())
+ switch (events.ExecuteEvent())
{
case EVENT_OPTIC_LINK:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
diff --git a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
index 4fb7646558d..548c87efc22 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
@@ -196,7 +196,7 @@ public:
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- switch (uint32 eventId = events.ExecuteEvent())
+ switch (events.ExecuteEvent())
{
case EVENT_ARCANE_BARRAGE:
DoCast(SPELL_ARCANE_BARRAGE_VOLLEY);
@@ -286,7 +286,7 @@ public:
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- switch (uint32 eventId = events.ExecuteEvent())
+ switch (events.ExecuteEvent())
{
case EVENT_RANGE_CHECK:
if (Creature* xevozz = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_XEVOZZ)))
diff --git a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
index 02e479a22f4..5b3f06c9e40 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
@@ -180,7 +180,7 @@ public:
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- switch (uint32 eventId = events.ExecuteEvent())
+ switch (events.ExecuteEvent())
{
case EVENT_SUMMON_VOID:
DoCast(SPELL_SUMMON_VOID_SENTRY);
diff --git a/src/server/shared/Common.h b/src/server/shared/Common.h
index dc4a4d231b1..09d64acc795 100644
--- a/src/server/shared/Common.h
+++ b/src/server/shared/Common.h
@@ -38,6 +38,7 @@
#include <queue>
#include <sstream>
#include <algorithm>
+#include <memory>
#include "Debugging/Errors.h"
@@ -144,4 +145,14 @@ typedef std::vector<std::string> StringVector;
#define MAX_QUERY_LEN 32*1024
+namespace Trinity
+{
+ //! std::make_unique implementation (TODO: remove this once C++14 is supported)
+ template<typename T, typename ...Args>
+ std::unique_ptr<T> make_unique(Args&& ...args)
+ {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+ }
+}
+
#endif
diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h
index 6bc204fbf76..6fb58cf414e 100644
--- a/src/server/shared/Database/DatabaseWorkerPool.h
+++ b/src/server/shared/Database/DatabaseWorkerPool.h
@@ -162,7 +162,7 @@ class DatabaseWorkerPool
//! This method should only be used for queries that are only executed once, e.g during startup.
void Execute(const char* sql)
{
- if (!sql)
+ if (Trinity::IsFormatEmptyOrNull(sql))
return;
BasicStatementTask* task = new BasicStatementTask(sql);
@@ -171,13 +171,13 @@ class DatabaseWorkerPool
//! Enqueues a one-way SQL operation in string format -with variable args- that will be executed asynchronously.
//! This method should only be used for queries that are only executed once, e.g during startup.
- template<typename... Args>
- void PExecute(const char* sql, Args const&... args)
+ template<typename Format, typename... Args>
+ void PExecute(Format&& sql, Args&&... args)
{
- if (!sql)
+ if (Trinity::IsFormatEmptyOrNull(sql))
return;
- Execute(Trinity::StringFormat(sql, args...).c_str());
+ Execute(Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str());
}
//! Enqueues a one-way SQL operation in prepared statement format that will be executed asynchronously.
@@ -206,13 +206,13 @@ class DatabaseWorkerPool
//! Directly executes a one-way SQL operation in string format -with variable args-, that will block the calling thread until finished.
//! This method should only be used for queries that are only executed once, e.g during startup.
- template<typename... Args>
- void DirectPExecute(const char* sql, Args const&... args)
+ template<typename Format, typename... Args>
+ void DirectPExecute(Format&& sql, Args&&... args)
{
- if (!sql)
+ if (Trinity::IsFormatEmptyOrNull(sql))
return;
- DirectExecute(Trinity::StringFormat(sql, args...).c_str());
+ DirectExecute(Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str());
}
//! Directly executes a one-way SQL operation in prepared statement format, that will block the calling thread until finished.
@@ -233,7 +233,7 @@ class DatabaseWorkerPool
//! Directly executes an SQL query in string format that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
- QueryResult Query(const char* sql, T* conn = NULL)
+ QueryResult Query(const char* sql, T* conn = nullptr)
{
if (!conn)
conn = GetFreeConnection();
@@ -251,24 +251,24 @@ class DatabaseWorkerPool
//! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
- template<typename... Args>
- QueryResult PQuery(const char* sql, T* conn, Args const&... args)
+ template<typename Format, typename... Args>
+ QueryResult PQuery(Format&& sql, T* conn, Args&&... args)
{
- if (!sql)
- return QueryResult(NULL);
+ if (Trinity::IsFormatEmptyOrNull(sql))
+ return QueryResult(nullptr);
- return Query(Trinity::StringFormat(sql, args...).c_str(), conn);
+ return Query(Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str(), conn);
}
//! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
- template<typename... Args>
- QueryResult PQuery(const char* sql, Args const&... args)
+ template<typename Format, typename... Args>
+ QueryResult PQuery(Format&& sql, Args&&... args)
{
if (!sql)
- return QueryResult(NULL);
+ return QueryResult(nullptr);
- return Query(Trinity::StringFormat(sql, args...).c_str());
+ return Query(Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str());
}
//! Directly executes an SQL query in prepared format that will block the calling thread until finished.
@@ -309,10 +309,10 @@ class DatabaseWorkerPool
//! Enqueues a query in string format -with variable args- that will set the value of the QueryResultFuture return object as soon as the query is executed.
//! The return value is then processed in ProcessQueryCallback methods.
- template<typename... Args>
- QueryResultFuture AsyncPQuery(const char* sql, Args const&... args)
+ template<typename Format, typename... Args>
+ QueryResultFuture AsyncPQuery(Format&& sql, Args&&... args)
{
- return AsyncQuery(Trinity::StringFormat(sql, args...).c_str());
+ return AsyncQuery(Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str());
}
//! Enqueues a query in prepared format that will set the value of the PreparedQueryResultFuture return object as soon as the query is executed.
diff --git a/src/server/shared/Database/QueryHolder.h b/src/server/shared/Database/QueryHolder.h
index 4102bba1223..b64da948a16 100644
--- a/src/server/shared/Database/QueryHolder.h
+++ b/src/server/shared/Database/QueryHolder.h
@@ -30,8 +30,11 @@ class SQLQueryHolder
SQLQueryHolder() { }
~SQLQueryHolder();
bool SetQuery(size_t index, const char* sql);
- template<typename... Args>
- bool SetPQuery(size_t index, const char* sql, Args const&... args) { return SetQuery(index, Trinity::StringFormat(sql, args...).c_str()); }
+ template<typename Format, typename... Args>
+ bool SetPQuery(size_t index, Format&& sql, Args&&... args)
+ {
+ return SetQuery(index, Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str());
+ }
bool SetPreparedQuery(size_t index, PreparedStatement* stmt);
void SetSize(size_t size);
QueryResult GetResult(size_t index);
diff --git a/src/server/shared/Database/Transaction.h b/src/server/shared/Database/Transaction.h
index a51c96ea93b..4fbbe1ed45b 100644
--- a/src/server/shared/Database/Transaction.h
+++ b/src/server/shared/Database/Transaction.h
@@ -39,8 +39,11 @@ class Transaction
void Append(PreparedStatement* statement);
void Append(const char* sql);
- template<typename... Args>
- void PAppend(const char* sql, Args const&... args) { Append(Trinity::StringFormat(sql, args...).c_str()); }
+ template<typename Format, typename... Args>
+ void PAppend(Format&& sql, Args&&... args)
+ {
+ Append(Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str());
+ }
size_t GetSize() const { return m_queries.size(); }
diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp
index a2150733c6b..6c2580b3168 100644
--- a/src/server/shared/Logging/Log.cpp
+++ b/src/server/shared/Logging/Log.cpp
@@ -269,7 +269,7 @@ void Log::write(std::unique_ptr<LogMessage>&& msg) const
if (_ioService)
{
- auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, std::forward<std::unique_ptr<LogMessage>>(msg)));
+ auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, std::move(msg)));
_ioService->post(_strand->wrap([logOperation](){ logOperation->call(); }));
}
@@ -290,9 +290,8 @@ std::string Log::GetTimestampStr()
// HH hour (2 digits 00-23)
// MM minutes (2 digits 00-59)
// SS seconds (2 digits 00-59)
- char buf[20];
- snprintf(buf, 20, "%04d-%02d-%02d_%02d-%02d-%02d", aTm.tm_year+1900, aTm.tm_mon+1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
- return std::string(buf);
+ return Trinity::StringFormat("%04d-%02d-%02d_%02d-%02d-%02d",
+ aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
}
bool Log::SetLogLevel(std::string const& name, const char* newLevelc, bool isLogger /* = true */)
diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h
index e22a06e635e..ab7b2169ed2 100644
--- a/src/server/shared/Logging/Log.h
+++ b/src/server/shared/Logging/Log.h
@@ -23,6 +23,7 @@
#include "Appender.h"
#include "Logger.h"
#include "StringFormat.h"
+#include "Common.h"
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
@@ -61,19 +62,22 @@ class Log
bool ShouldLog(std::string const& type, LogLevel level) const;
bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true);
- template<typename... Args>
- inline void outMessage(std::string const& filter, LogLevel const level, const char* fmt, Args const&... args)
+ template<typename Format, typename... Args>
+ inline void outMessage(std::string const& filter, LogLevel const level, Format&& fmt, Args&&... args)
{
- write(std::unique_ptr<LogMessage>(new LogMessage(level, filter, Trinity::StringFormat(fmt, args...))));
+ write(Trinity::make_unique<LogMessage>(level, filter,
+ Trinity::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...)));
}
- template<typename... Args>
- void outCommand(uint32 account, const char* fmt, Args const&... args)
+ template<typename Format, typename... Args>
+ void outCommand(uint32 account, Format&& fmt, Args&&... args)
{
if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
return;
- std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "commands.gm", std::move(Trinity::StringFormat(fmt, args...))));
+ std::unique_ptr<LogMessage> msg =
+ Trinity::make_unique<LogMessage>(LOG_LEVEL_INFO, "commands.gm",
+ Trinity::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
msg->param1 = std::to_string(account);
@@ -159,7 +163,8 @@ inline bool Log::ShouldLog(std::string const& type, LogLevel level) const
}
#if PLATFORM != PLATFORM_WINDOWS
-void check_args(const char* format, ...) ATTR_PRINTF(1, 2);
+void check_args(const char*, ...) ATTR_PRINTF(1, 2);
+void check_args(std::string const&, ...);
// This will catch format errors on build time
#define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \
diff --git a/src/server/shared/PrecompiledHeaders/sharedPCH.h b/src/server/shared/PrecompiledHeaders/sharedPCH.h
index 87af9f44eb7..d99476bc7a8 100644
--- a/src/server/shared/PrecompiledHeaders/sharedPCH.h
+++ b/src/server/shared/PrecompiledHeaders/sharedPCH.h
@@ -7,3 +7,4 @@
#include "Errors.h"
#include "TypeList.h"
#include "TaskScheduler.h"
+#include "EventMap.h"
diff --git a/src/server/shared/Threading/ProducerConsumerQueue.h b/src/server/shared/Threading/ProducerConsumerQueue.h
index e2f13e5c339..96546960393 100644
--- a/src/server/shared/Threading/ProducerConsumerQueue.h
+++ b/src/server/shared/Threading/ProducerConsumerQueue.h
@@ -70,7 +70,8 @@ public:
{
std::unique_lock<std::mutex> lock(_queueLock);
- // we could be using .wait(lock, predicate) overload here but some threading error analysis tools produce false positives
+ // we could be using .wait(lock, predicate) overload here but it is broken
+ // https://connect.microsoft.com/VisualStudio/feedback/details/1098841
while (_queue.empty() && !_shutdown)
_condition.wait(lock);
diff --git a/src/server/shared/Utilities/Duration.h b/src/server/shared/Utilities/Duration.h
new file mode 100644
index 00000000000..58a08e5842f
--- /dev/null
+++ b/src/server/shared/Utilities/Duration.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DURATION_H_
+#define _DURATION_H_
+
+#include <chrono>
+
+/// Milliseconds shorthand typedef.
+typedef std::chrono::milliseconds Milliseconds;
+
+/// Seconds shorthand typedef.
+typedef std::chrono::seconds Seconds;
+
+/// Minutes shorthand typedef.
+typedef std::chrono::minutes Minutes;
+
+/// Hours shorthand typedef.
+typedef std::chrono::hours Hours;
+
+/// Makes std::chrono_literals globally available.
+// ToDo: Enable this when TC supports C++14.
+// using namespace std::chrono_literals;
+
+#endif // _DURATION_H_
diff --git a/src/server/shared/Utilities/EventMap.cpp b/src/server/shared/Utilities/EventMap.cpp
new file mode 100644
index 00000000000..8c3f60afe82
--- /dev/null
+++ b/src/server/shared/Utilities/EventMap.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "EventMap.h"
+
+void EventMap::Reset()
+{
+ _eventMap.clear();
+ _time = 0;
+ _phase = 0;
+}
+
+void EventMap::SetPhase(uint8 phase)
+{
+ if (!phase)
+ _phase = 0;
+ else if (phase <= 8)
+ _phase = uint8(1 << (phase - 1));
+}
+
+void EventMap::ScheduleEvent(uint32 eventId, uint32 time, uint32 group /*= 0*/, uint8 phase /*= 0*/)
+{
+ if (group && group <= 8)
+ eventId |= (1 << (group + 15));
+
+ if (phase && phase <= 8)
+ eventId |= (1 << (phase + 23));
+
+ _eventMap.insert(EventStore::value_type(_time + time, eventId));
+}
+
+uint32 EventMap::ExecuteEvent()
+{
+ while (!Empty())
+ {
+ EventStore::iterator itr = _eventMap.begin();
+
+ if (itr->first > _time)
+ return 0;
+ else if (_phase && (itr->second & 0xFF000000) && !((itr->second >> 24) & _phase))
+ _eventMap.erase(itr);
+ else
+ {
+ uint32 eventId = (itr->second & 0x0000FFFF);
+ _lastEvent = itr->second; // include phase/group
+ _eventMap.erase(itr);
+ return eventId;
+ }
+ }
+
+ return 0;
+}
+
+void EventMap::DelayEvents(uint32 delay, uint32 group)
+{
+ if (!group || group > 8 || Empty())
+ return;
+
+ EventStore delayed;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (itr->second & (1 << (group + 15)))
+ {
+ delayed.insert(EventStore::value_type(itr->first + delay, itr->second));
+ _eventMap.erase(itr++);
+ }
+ else
+ ++itr;
+ }
+
+ _eventMap.insert(delayed.begin(), delayed.end());
+}
+
+void EventMap::CancelEvent(uint32 eventId)
+{
+ if (Empty())
+ return;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (eventId == (itr->second & 0x0000FFFF))
+ _eventMap.erase(itr++);
+ else
+ ++itr;
+ }
+}
+
+void EventMap::CancelEventGroup(uint32 group)
+{
+ if (!group || group > 8 || Empty())
+ return;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (itr->second & (1 << (group + 15)))
+ _eventMap.erase(itr++);
+ else
+ ++itr;
+ }
+}
+
+uint32 EventMap::GetNextEventTime(uint32 eventId) const
+{
+ if (Empty())
+ return 0;
+
+ for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
+ if (eventId == (itr->second & 0x0000FFFF))
+ return itr->first;
+
+ return 0;
+}
+
+uint32 EventMap::GetTimeUntilEvent(uint32 eventId) const
+{
+ for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
+ if (eventId == (itr->second & 0x0000FFFF))
+ return itr->first - _time;
+
+ return std::numeric_limits<uint32>::max();
+}
diff --git a/src/server/shared/Utilities/EventMap.h b/src/server/shared/Utilities/EventMap.h
new file mode 100644
index 00000000000..790a25a0b63
--- /dev/null
+++ b/src/server/shared/Utilities/EventMap.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _EVENT_MAP_H_
+#define _EVENT_MAP_H_
+
+#include "Common.h"
+#include "Duration.h"
+
+class EventMap
+{
+ /**
+ * Internal storage type.
+ * Key: Time as uint32 when the event should occur.
+ * Value: The event data as uint32.
+ *
+ * Structure of event data:
+ * - Bit 0 - 15: Event Id.
+ * - Bit 16 - 23: Group
+ * - Bit 24 - 31: Phase
+ * - Pattern: 0xPPGGEEEE
+ */
+ typedef std::multimap<uint32, uint32> EventStore;
+
+public:
+ EventMap() : _time(0), _phase(0), _lastEvent(0) { }
+
+ /**
+ * @name Reset
+ * @brief Removes all scheduled events and resets time and phase.
+ */
+ void Reset();
+
+ /**
+ * @name Update
+ * @brief Updates the timer of the event map.
+ * @param time Value in ms to be added to time.
+ */
+ void Update(uint32 time)
+ {
+ _time += time;
+ }
+
+ /**
+ * @name GetTimer
+ * @return Current timer in ms value.
+ */
+ uint32 GetTimer() const
+ {
+ return _time;
+ }
+
+ /**
+ * @name GetPhaseMask
+ * @return Active phases as mask.
+ */
+ uint8 GetPhaseMask() const
+ {
+ return _phase;
+ }
+
+ /**
+ * @name Empty
+ * @return True, if there are no events scheduled.
+ */
+ bool Empty() const
+ {
+ return _eventMap.empty();
+ }
+
+ /**
+ * @name SetPhase
+ * @brief Sets the phase of the map (absolute).
+ * @param phase Phase which should be set. Values: 1 - 8. 0 resets phase.
+ */
+ void SetPhase(uint8 phase);
+
+ /**
+ * @name AddPhase
+ * @brief Activates the given phase (bitwise).
+ * @param phase Phase which should be activated. Values: 1 - 8
+ */
+ void AddPhase(uint8 phase)
+ {
+ if (phase && phase <= 8)
+ _phase |= uint8(1 << (phase - 1));
+ }
+
+ /**
+ * @name RemovePhase
+ * @brief Deactivates the given phase (bitwise).
+ * @param phase Phase which should be deactivated. Values: 1 - 8.
+ */
+ void RemovePhase(uint8 phase)
+ {
+ if (phase && phase <= 8)
+ _phase &= uint8(~(1 << (phase - 1)));
+ }
+
+ /**
+ * @name ScheduleEvent
+ * @brief Creates new event entry in map.
+ * @param eventId The id of the new event.
+ * @param time The time in milliseconds as std::chrono::duration until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void ScheduleEvent(uint32 eventId, Milliseconds const& time, uint32 group = 0, uint8 phase = 0)
+ {
+ ScheduleEvent(eventId, time.count(), group, phase);
+ }
+
+ /**
+ * @name ScheduleEvent
+ * @brief Creates new event entry in map.
+ * @param eventId The id of the new event.
+ * @param time The time in milliseconds until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void ScheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0);
+
+ /**
+ * @name RescheduleEvent
+ * @brief Cancels the given event and reschedules it.
+ * @param eventId The id of the event.
+ * @param time The time in milliseconds as std::chrono::duration until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void RescheduleEvent(uint32 eventId, Milliseconds const& time, uint32 group = 0, uint8 phase = 0)
+ {
+ RescheduleEvent(eventId, time.count(), group, phase);
+ }
+
+ /**
+ * @name RescheduleEvent
+ * @brief Cancels the given event and reschedules it.
+ * @param eventId The id of the event.
+ * @param time The time in milliseconds until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void RescheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
+ {
+ CancelEvent(eventId);
+ ScheduleEvent(eventId, time, group, phase);
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event.
+ * @param time Time until in milliseconds as std::chrono::duration the event occurs.
+ */
+ void Repeat(Milliseconds const& time)
+ {
+ Repeat(time.count());
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event.
+ * @param time Time until the event occurs.
+ */
+ void Repeat(uint32 time)
+ {
+ _eventMap.insert(EventStore::value_type(_time + time, _lastEvent));
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event.
+ * @param minTime Minimum time as std::chrono::duration until the event occurs.
+ * @param maxTime Maximum time as std::chrono::duration until the event occurs.
+ */
+ void Repeat(Milliseconds const& minTime, Milliseconds const& maxTime)
+ {
+ Repeat(minTime.count(), maxTime.count());
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event, Equivalent to Repeat(urand(minTime, maxTime).
+ * @param minTime Minimum time until the event occurs.
+ * @param maxTime Maximum time until the event occurs.
+ */
+ void Repeat(uint32 minTime, uint32 maxTime)
+ {
+ Repeat(urand(minTime, maxTime));
+ }
+
+ /**
+ * @name ExecuteEvent
+ * @brief Returns the next event to execute and removes it from map.
+ * @return Id of the event to execute.
+ */
+ uint32 ExecuteEvent();
+
+ /**
+ * @name DelayEvents
+ * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
+ * @param delay Amount of delay in ms as std::chrono::duration.
+ */
+ void DelayEvents(Milliseconds const& delay)
+ {
+ DelayEvents(delay.count());
+ }
+
+ /**
+ * @name DelayEvents
+ * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
+ * @param delay Amount of delay.
+ */
+ void DelayEvents(uint32 delay)
+ {
+ _time = delay < _time ? _time - delay : 0;
+ }
+
+ /**
+ * @name DelayEvents
+ * @brief Delay all events of the same group.
+ * @param delay Amount of delay in ms as std::chrono::duration.
+ * @param group Group of the events.
+ */
+ void DelayEvents(Milliseconds const& delay, uint32 group)
+ {
+ DelayEvents(delay.count(), group);
+ }
+
+ /**
+ * @name DelayEvents
+ * @brief Delay all events of the same group.
+ * @param delay Amount of delay.
+ * @param group Group of the events.
+ */
+ void DelayEvents(uint32 delay, uint32 group);
+
+ /**
+ * @name CancelEvent
+ * @brief Cancels all events of the specified id.
+ * @param eventId Event id to cancel.
+ */
+ void CancelEvent(uint32 eventId);
+
+ /**
+ * @name CancelEventGroup
+ * @brief Cancel events belonging to specified group.
+ * @param group Group to cancel.
+ */
+ void CancelEventGroup(uint32 group);
+
+ /**
+ * @name GetNextEventTime
+ * @brief Returns closest occurence of specified event.
+ * @param eventId Wanted event id.
+ * @return Time of found event.
+ */
+ uint32 GetNextEventTime(uint32 eventId) const;
+
+ /**
+ * @name GetNextEventTime
+ * @return Time of next event.
+ */
+ uint32 GetNextEventTime() const
+ {
+ return Empty() ? 0 : _eventMap.begin()->first;
+ }
+
+ /**
+ * @name IsInPhase
+ * @brief Returns whether event map is in specified phase or not.
+ * @param phase Wanted phase.
+ * @return True, if phase of event map contains specified phase.
+ */
+ bool IsInPhase(uint8 phase) const
+ {
+ return phase <= 8 && (!phase || _phase & (1 << (phase - 1)));
+ }
+
+ /**
+ * @name GetTimeUntilEvent
+ * @brief Returns time in milliseconds until next event.
+ * @param eventId of the event.
+ * @return Time of next event.
+ */
+ uint32 GetTimeUntilEvent(uint32 eventId) const;
+
+private:
+ /**
+ * @name _time
+ * @brief Internal timer.
+ *
+ * This does not represent the real date/time value.
+ * It's more like a stopwatch: It can run, it can be stopped,
+ * it can be resetted and so on. Events occur when this timer
+ * has reached their time value. Its value is changed in the
+ * Update method.
+ */
+ uint32 _time;
+
+ /**
+ * @name _phase
+ * @brief Phase mask of the event map.
+ *
+ * Contains the phases the event map is in. Multiple
+ * phases from 1 to 8 can be set with SetPhase or
+ * AddPhase. RemovePhase deactives a phase.
+ */
+ uint8 _phase;
+
+ /**
+ * @name _eventMap
+ * @brief Internal event storage map. Contains the scheduled events.
+ *
+ * See typedef at the beginning of the class for more
+ * details.
+ */
+ EventStore _eventMap;
+
+ /**
+ * @name _lastEvent
+ * @brief Stores information on the most recently executed event
+ */
+ uint32 _lastEvent;
+};
+
+#endif // _EVENT_MAP_H_
diff --git a/src/server/shared/Utilities/StringFormat.h b/src/server/shared/Utilities/StringFormat.h
index 70d9aefb14d..67e0100e7c8 100644
--- a/src/server/shared/Utilities/StringFormat.h
+++ b/src/server/shared/Utilities/StringFormat.h
@@ -19,15 +19,27 @@
#ifndef TRINITYCORE_STRING_FORMAT_H
#define TRINITYCORE_STRING_FORMAT_H
-#include <format.h>
+#include "format.h"
namespace Trinity
{
- //! Default TC string format function
- template<typename... Args>
- inline std::string StringFormat(const char* fmt, Args const&... args)
+ /// Default TC string format function.
+ template<typename Format, typename... Args>
+ inline std::string StringFormat(Format&& fmt, Args&&... args)
{
- return fmt::sprintf(fmt, args...);
+ return fmt::sprintf(std::forward<Format>(fmt), std::forward<Args>(args)...);
+ }
+
+ /// Returns true if the given char pointer is null.
+ inline bool IsFormatEmptyOrNull(const char* fmt)
+ {
+ return fmt == nullptr;
+ }
+
+ /// Returns true if the given std::string is empty.
+ inline bool IsFormatEmptyOrNull(std::string const& fmt)
+ {
+ return fmt.empty();
}
}
diff --git a/src/server/shared/Utilities/TaskScheduler.h b/src/server/shared/Utilities/TaskScheduler.h
index d45835b5f17..f1fe7ea0a21 100644
--- a/src/server/shared/Utilities/TaskScheduler.h
+++ b/src/server/shared/Utilities/TaskScheduler.h
@@ -29,6 +29,7 @@
#include <boost/optional.hpp>
#include "Util.h"
+#include "Duration.h"
class TaskContext;
@@ -646,16 +647,4 @@ private:
void Invoke();
};
-/// Milliseconds shorthand typedef.
-typedef std::chrono::milliseconds Milliseconds;
-
-/// Seconds shorthand typedef.
-typedef std::chrono::seconds Seconds;
-
-/// Minutes shorthand typedef.
-typedef std::chrono::minutes Minutes;
-
-/// Hours shorthand typedef.
-typedef std::chrono::hours Hours;
-
#endif /// _TASK_SCHEDULER_H_
diff --git a/src/server/shared/Utilities/Timer.h b/src/server/shared/Utilities/Timer.h
index b7d2fa1b5ad..c54903d7be2 100644
--- a/src/server/shared/Utilities/Timer.h
+++ b/src/server/shared/Utilities/Timer.h
@@ -21,10 +21,10 @@
#include <chrono>
-using namespace std::chrono;
-
inline uint32 getMSTime()
{
+ using namespace std::chrono;
+
static const system_clock::time_point ApplicationStartTime = system_clock::now();
return uint32(duration_cast<milliseconds>(system_clock::now() - ApplicationStartTime).count());
diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp
index c4e47a6ee07..33c273fb05f 100644
--- a/src/server/shared/Utilities/Util.cpp
+++ b/src/server/shared/Utilities/Util.cpp
@@ -560,12 +560,3 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse
return ss.str();
}
-
-uint32 EventMap::GetTimeUntilEvent(uint32 eventId) const
-{
- for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
- if (eventId == (itr->second & 0x0000FFFF))
- return itr->first - _time;
-
- return std::numeric_limits<uint32>::max();
-}
diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h
index cd523511c1d..3da1c800410 100644
--- a/src/server/shared/Utilities/Util.h
+++ b/src/server/shared/Utilities/Util.h
@@ -542,346 +542,4 @@ bool CompareValues(ComparisionType type, T val1, T val2)
}
}
-class EventMap
-{
- /**
- * Internal storage type.
- * Key: Time as uint32 when the event should occur.
- * Value: The event data as uint32.
- *
- * Structure of event data:
- * - Bit 0 - 15: Event Id.
- * - Bit 16 - 23: Group
- * - Bit 24 - 31: Phase
- * - Pattern: 0xPPGGEEEE
- */
- typedef std::multimap<uint32, uint32> EventStore;
-
- public:
- EventMap() : _time(0), _phase(0), _lastEvent(0) { }
-
- /**
- * @name Reset
- * @brief Removes all scheduled events and resets time and phase.
- */
- void Reset()
- {
- _eventMap.clear();
- _time = 0;
- _phase = 0;
- }
-
- /**
- * @name Update
- * @brief Updates the timer of the event map.
- * @param time Value to be added to time.
- */
- void Update(uint32 time)
- {
- _time += time;
- }
-
- /**
- * @name GetTimer
- * @return Current timer value.
- */
- uint32 GetTimer() const
- {
- return _time;
- }
-
- /**
- * @name GetPhaseMask
- * @return Active phases as mask.
- */
- uint8 GetPhaseMask() const
- {
- return _phase;
- }
-
- /**
- * @name Empty
- * @return True, if there are no events scheduled.
- */
- bool Empty() const
- {
- return _eventMap.empty();
- }
-
- /**
- * @name SetPhase
- * @brief Sets the phase of the map (absolute).
- * @param phase Phase which should be set. Values: 1 - 8. 0 resets phase.
- */
- void SetPhase(uint8 phase)
- {
- if (!phase)
- _phase = 0;
- else if (phase <= 8)
- _phase = uint8(1 << (phase - 1));
- }
-
- /**
- * @name AddPhase
- * @brief Activates the given phase (bitwise).
- * @param phase Phase which should be activated. Values: 1 - 8
- */
- void AddPhase(uint8 phase)
- {
- if (phase && phase <= 8)
- _phase |= uint8(1 << (phase - 1));
- }
-
- /**
- * @name RemovePhase
- * @brief Deactivates the given phase (bitwise).
- * @param phase Phase which should be deactivated. Values: 1 - 8.
- */
- void RemovePhase(uint8 phase)
- {
- if (phase && phase <= 8)
- _phase &= uint8(~(1 << (phase - 1)));
- }
-
- /**
- * @name ScheduleEvent
- * @brief Creates new event entry in map.
- * @param eventId The id of the new event.
- * @param time The time in milliseconds until the event occurs.
- * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
- * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
- */
- void ScheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
- {
- if (group && group <= 8)
- eventId |= (1 << (group + 15));
-
- if (phase && phase <= 8)
- eventId |= (1 << (phase + 23));
-
- _eventMap.insert(EventStore::value_type(_time + time, eventId));
- }
-
- /**
- * @name RescheduleEvent
- * @brief Cancels the given event and reschedules it.
- * @param eventId The id of the event.
- * @param time The time in milliseconds until the event occurs.
- * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
- * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
- */
- void RescheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
- {
- CancelEvent(eventId);
- ScheduleEvent(eventId, time, group, phase);
- }
-
- /**
- * @name RepeatEvent
- * @brief Repeats the mostly recently executed event.
- * @param time Time until the event occurs.
- */
- void Repeat(uint32 time)
- {
- _eventMap.insert(EventStore::value_type(_time + time, _lastEvent));
- }
-
- /**
- * @name RepeatEvent
- * @brief Repeats the mostly recently executed event, Equivalent to Repeat(urand(minTime, maxTime).
- * @param minTime Minimum time until the event occurs.
- * @param maxTime Maximum time until the event occurs.
- */
- void Repeat(uint32 minTime, uint32 maxTime)
- {
- Repeat(urand(minTime, maxTime));
- }
-
- /**
- * @name ExecuteEvent
- * @brief Returns the next event to execute and removes it from map.
- * @return Id of the event to execute.
- */
- uint32 ExecuteEvent()
- {
- while (!Empty())
- {
- EventStore::iterator itr = _eventMap.begin();
-
- if (itr->first > _time)
- return 0;
- else if (_phase && (itr->second & 0xFF000000) && !((itr->second >> 24) & _phase))
- _eventMap.erase(itr);
- else
- {
- uint32 eventId = (itr->second & 0x0000FFFF);
- _lastEvent = itr->second; // include phase/group
- _eventMap.erase(itr);
- return eventId;
- }
- }
-
- return 0;
- }
-
- /**
- * @name DelayEvents
- * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
- * @param delay Amount of delay.
- */
- void DelayEvents(uint32 delay)
- {
- _time = delay < _time ? _time - delay : 0;
- }
-
- /**
- * @name DelayEvents
- * @brief Delay all events of the same group.
- * @param delay Amount of delay.
- * @param group Group of the events.
- */
- void DelayEvents(uint32 delay, uint32 group)
- {
- if (!group || group > 8 || Empty())
- return;
-
- EventStore delayed;
-
- for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
- {
- if (itr->second & (1 << (group + 15)))
- {
- delayed.insert(EventStore::value_type(itr->first + delay, itr->second));
- _eventMap.erase(itr++);
- }
- else
- ++itr;
- }
-
- _eventMap.insert(delayed.begin(), delayed.end());
- }
-
- /**
- * @name CancelEvent
- * @brief Cancels all events of the specified id.
- * @param eventId Event id to cancel.
- */
- void CancelEvent(uint32 eventId)
- {
- if (Empty())
- return;
-
- for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
- {
- if (eventId == (itr->second & 0x0000FFFF))
- _eventMap.erase(itr++);
- else
- ++itr;
- }
- }
-
- /**
- * @name CancelEventGroup
- * @brief Cancel events belonging to specified group.
- * @param group Group to cancel.
- */
- void CancelEventGroup(uint32 group)
- {
- if (!group || group > 8 || Empty())
- return;
-
- for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
- {
- if (itr->second & (1 << (group + 15)))
- _eventMap.erase(itr++);
- else
- ++itr;
- }
- }
-
- /**
- * @name GetNextEventTime
- * @brief Returns closest occurence of specified event.
- * @param eventId Wanted event id.
- * @return Time of found event.
- */
- uint32 GetNextEventTime(uint32 eventId) const
- {
- if (Empty())
- return 0;
-
- for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
- if (eventId == (itr->second & 0x0000FFFF))
- return itr->first;
-
- return 0;
- }
-
- /**
- * @name GetNextEventTime
- * @return Time of next event.
- */
- uint32 GetNextEventTime() const
- {
- return Empty() ? 0 : _eventMap.begin()->first;
- }
-
- /**
- * @name IsInPhase
- * @brief Returns wether event map is in specified phase or not.
- * @param phase Wanted phase.
- * @return True, if phase of event map contains specified phase.
- */
- bool IsInPhase(uint8 phase)
- {
- return phase <= 8 && (!phase || _phase & (1 << (phase - 1)));
- }
-
- /**
- * @name GetTimeUntilEvent
- * @brief Returns time in milliseconds until next event.
- * @param eventId of the event.
- * @return Time of next event.
- */
- uint32 GetTimeUntilEvent(uint32 eventId) const;
-
- private:
- /**
- * @name _time
- * @brief Internal timer.
- *
- * This does not represent the real date/time value.
- * It's more like a stopwatch: It can run, it can be stopped,
- * it can be resetted and so on. Events occur when this timer
- * has reached their time value. Its value is changed in the
- * Update method.
- */
- uint32 _time;
-
- /**
- * @name _phase
- * @brief Phase mask of the event map.
- *
- * Contains the phases the event map is in. Multiple
- * phases from 1 to 8 can be set with SetPhase or
- * AddPhase. RemovePhase deactives a phase.
- */
- uint8 _phase;
-
- /**
- * @name _eventMap
- * @brief Internal event storage map. Contains the scheduled events.
- *
- * See typedef at the beginning of the class for more
- * details.
- */
- EventStore _eventMap;
-
- /**
- * @name _lastEvent
- * @brief Stores information on the most recently executed event
- */
- uint32 _lastEvent;
-};
-
#endif