diff options
Diffstat (limited to 'src')
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 |