diff --git a/src/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/game/AuctionHouseBot/AuctionHouseBot.cpp index 7d504085..11fd2e70 100644 --- a/src/game/AuctionHouseBot/AuctionHouseBot.cpp +++ b/src/game/AuctionHouseBot/AuctionHouseBot.cpp @@ -1812,14 +1812,14 @@ void AuctionBotSeller::SetPricesOfItem(AHB_Seller_Config& config, uint32& buyp, double randrange = temp_buyp * 0.4; uint32 buypMin = (uint32)temp_buyp - (uint32)randrange; - uint32 buypMax = ((uint32)temp_buyp + (uint32)randrange) < temp_buyp ? ACE_Numeric_Limits::max() : temp_buyp + randrange; + uint32 buypMax = ((uint32)temp_buyp + (uint32)randrange) < temp_buyp ? std::numeric_limits::max() : temp_buyp + randrange; buyp = (urand(buypMin, buypMax) / 100) + 1; double urandrange = buyp * 40; double temp_bidp = buyp * 50; uint32 bidPmin = (uint32)temp_bidp - (uint32)urandrange; - uint32 bidPmax = ((uint32)temp_bidp + (uint32)urandrange) < temp_bidp ? ACE_Numeric_Limits::max() : temp_bidp + urandrange; + uint32 bidPmax = ((uint32)temp_bidp + (uint32)urandrange) < temp_bidp ? std::numeric_limits::max() : temp_bidp + urandrange; bidp = (urand(bidPmin, bidPmax) / 100) + 1; } diff --git a/src/game/BattleGround/BattleGroundHandler.cpp b/src/game/BattleGround/BattleGroundHandler.cpp index c4b37fb7..5228f1b7 100644 --- a/src/game/BattleGround/BattleGroundHandler.cpp +++ b/src/game/BattleGround/BattleGroundHandler.cpp @@ -38,6 +38,7 @@ #include "ScriptMgr.h" #include "World.h" #include "DisableMgr.h" +#include "GameTime.h" void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket& recv_data) { @@ -539,7 +540,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recv_data*/) { continue; } - uint32 remainingTime = WorldTimer::getMSTimeDiff(WorldTimer::getMSTime(), ginfo.RemoveInviteTime); + uint32 remainingTime = getMSTimeDiff(GameTime::GetGameTimeMS(), ginfo.RemoveInviteTime); // send status invited to BattleGround sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0); SendPacket(&data); @@ -554,7 +555,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recv_data*/) uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, _player->GetBattleGroundBracketIdFromLevel(bgTypeId)); // send status in BattleGround Queue - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, WorldTimer::getMSTimeDiff(ginfo.JoinTime, WorldTimer::getMSTime())); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, GameTime::GetGameTimeMS())); SendPacket(&data); } } diff --git a/src/game/BattleGround/BattleGroundMgr.cpp b/src/game/BattleGround/BattleGroundMgr.cpp index 02224f63..49e0a140 100644 --- a/src/game/BattleGround/BattleGroundMgr.cpp +++ b/src/game/BattleGround/BattleGroundMgr.cpp @@ -39,6 +39,7 @@ #include "Language.h" #include "GameEventMgr.h" #include "DisableMgr.h" +#include "GameTime.h" #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ @@ -163,7 +164,7 @@ GroupQueueInfo* BattleGroundQueue::AddGroup(Player* leader, Group* grp, BattleGr GroupQueueInfo* ginfo = new GroupQueueInfo; ginfo->BgTypeId = BgTypeId; ginfo->IsInvitedToBGInstanceGUID = 0; - ginfo->JoinTime = WorldTimer::getMSTime(); + ginfo->JoinTime = GameTime::GetGameTimeMS(); ginfo->RemoveInviteTime = 0; ginfo->GroupTeam = leader->GetTeam(); @@ -183,7 +184,7 @@ GroupQueueInfo* BattleGroundQueue::AddGroup(Player* leader, Group* grp, BattleGr DEBUG_LOG("Adding Group to BattleGroundQueue bgTypeId : %u, bracket_id : %u, index : %u", BgTypeId, bracketId, index); - uint32 lastOnlineTime = WorldTimer::getMSTime(); + uint32 lastOnlineTime = GameTime::GetGameTimeMS(); // add players from group to ginfo { @@ -259,7 +260,7 @@ GroupQueueInfo* BattleGroundQueue::AddGroup(Player* leader, Group* grp, BattleGr void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BattleGroundBracketId bracket_id) { - uint32 timeInQueue = WorldTimer::getMSTimeDiff(ginfo->JoinTime, WorldTimer::getMSTime()); + uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, GameTime::GetGameTimeMS()); uint8 team_index = TEAM_INDEX_ALLIANCE; // default set to BG_TEAM_ALLIANCE - or non rated arenas! if (ginfo->GroupTeam == HORDE) @@ -422,7 +423,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo* ginfo, BattleGround* bg, BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId); BattleGroundBracketId bracket_id = bg->GetBracketId(); - ginfo->RemoveInviteTime = WorldTimer::getMSTime() + INVITE_ACCEPT_WAIT_TIME; + ginfo->RemoveInviteTime = GameTime::GetGameTimeMS() + INVITE_ACCEPT_WAIT_TIME; // loop through the players for (GroupQueueInfoPlayers::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr) @@ -610,7 +611,7 @@ bool BattleGroundQueue::CheckPremadeMatch(BattleGroundBracketId bracket_id, uint // this could be 2 cycles but i'm checking only first team in queue - it can cause problem - // if first is invited to BG and seconds timer expired, but we can ignore it, because players have only 80 seconds to click to enter bg // and when they click or after 80 seconds the queue info is removed from queue - uint32 time_before = WorldTimer::getMSTime() - sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH); + uint32 time_before = GameTime::GetGameTimeMS() - sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH); for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i) { if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty()) diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index da22505e..be7849f5 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -57,6 +57,10 @@ source_group("References" FILES ${SRC_GRP_REFERENCES}) file(GLOB SRC_GRP_SERVER Server/*.cpp Server/*.h) source_group("Server" FILES ${SRC_GRP_SERVER}) +#Time group +file(GLOB SRC_GRP_TIME Time/*.cpp Time/*.h) +source_group("Time" FILES ${SRC_GRP_TIME}) + #Tools group file(GLOB SRC_GRP_TOOL Tools/*.cpp Tools/*.h) source_group("Tool" FILES ${SRC_GRP_TOOL}) @@ -219,6 +223,7 @@ add_library(game STATIC ${SRC_GRP_OUTDOOR_PVP} ${SRC_GRP_REFERENCES} ${SRC_GRP_SERVER} + ${SRC_GRP_TIME} ${SRC_GRP_TOOL} ${SRC_GRP_VMAPS} ${SRC_GRP_WARDEN} @@ -244,6 +249,7 @@ target_include_directories(game OutdoorPvP References Server + Time Tools vmap Warden diff --git a/src/game/ChatCommands/MMapCommands.cpp b/src/game/ChatCommands/MMapCommands.cpp index d39ea6ab..d7aa1eb0 100644 --- a/src/game/ChatCommands/MMapCommands.cpp +++ b/src/game/ChatCommands/MMapCommands.cpp @@ -31,6 +31,7 @@ #include "GridNotifiersImpl.h" // for mmap manager #include "CellImpl.h" #include "movement/MoveSplineInit.h" +#include "GameTime.h" #include #include #include @@ -320,7 +321,7 @@ bool ChatHandler::HandleMmapTestArea(char* args) PSendSysMessage("Found " SIZEFMTD " Creatures.", creatureList.size()); uint32 paths = 0; - uint32 uStartTime = WorldTimer::getMSTime(); + uint32 uStartTime = GameTime::GetGameTimeMS(); float gx, gy, gz; m_session->GetPlayer()->GetPosition(gx, gy, gz); @@ -331,7 +332,7 @@ bool ChatHandler::HandleMmapTestArea(char* args) ++paths; } - uint32 uPathLoadTime = WorldTimer::getMSTimeDiff(uStartTime, WorldTimer::getMSTime()); + uint32 uPathLoadTime = getMSTimeDiff(uStartTime, GameTime::GetGameTimeMS()); PSendSysMessage("Generated %i paths in %i ms", paths, uPathLoadTime); } else @@ -389,7 +390,7 @@ bool ChatHandler::HandleMmapTestHeight(char* args) summoned->CastSpell(summoned, 8599, false); uint32 tries = 1; uint32 successes = 0; - uint32 startTime = WorldTimer::getMSTime(); + uint32 startTime = GameTime::GetGameTimeMS(); for (; tries < 500; ++tries) { unit->GetPosition(gx, gy, gz); @@ -403,7 +404,7 @@ bool ChatHandler::HandleMmapTestHeight(char* args) } } } - uint32 genTime = WorldTimer::getMSTimeDiff(startTime, WorldTimer::getMSTime()); + uint32 genTime = getMSTimeDiff(startTime, GameTime::GetGameTimeMS()); PSendSysMessage("Generated %u valid points for %u try in %ums.", successes, tries, genTime); return true; } diff --git a/src/game/ChatCommands/ServerCommands.cpp b/src/game/ChatCommands/ServerCommands.cpp index 34ea7124..df85f4b6 100644 --- a/src/game/ChatCommands/ServerCommands.cpp +++ b/src/game/ChatCommands/ServerCommands.cpp @@ -27,6 +27,7 @@ #include "World.h" #include "Config.h" #include "SystemConfig.h" +#include "UpdateTime.h" #include "revision.h" /********************************************************************** @@ -41,6 +42,7 @@ bool ChatHandler::HandleServerInfoCommand(char* /*args*/) uint32 maxActiveClientsNum = sWorld.GetMaxActiveSessionCount(); uint32 maxQueuedClientsNum = sWorld.GetMaxQueuedSessionCount(); std::string str = secsToTimeString(sWorld.GetUptime()); + uint32 updateTime = sWorldUpdateTime.GetLastUpdateTime(); char const* full; full = REVISION_NR; @@ -66,6 +68,7 @@ bool ChatHandler::HandleServerInfoCommand(char* /*args*/) PSendSysMessage(LANG_USING_WORLD_DB, sWorld.GetDBVersion()); PSendSysMessage(LANG_CONNECTED_USERS, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum); PSendSysMessage(LANG_UPTIME, str.c_str()); + PSendSysMessage("World Delay: %u", updateTime); // ToDo: move to language string return true; } diff --git a/src/game/MotionGenerators/RandomMovementGenerator.cpp b/src/game/MotionGenerators/RandomMovementGenerator.cpp index 7d311571..ac6f8e34 100644 --- a/src/game/MotionGenerators/RandomMovementGenerator.cpp +++ b/src/game/MotionGenerators/RandomMovementGenerator.cpp @@ -45,7 +45,7 @@ RandomMovementGenerator::RandomMovementGenerator(const Creature& creat { float respX, respY, respZ, respO, wander_distance; creature.GetRespawnCoord(respX, respY, respZ, &respO, &wander_distance); - i_nextMoveTime = ShortTimeTracker(0); + i_nextMoveTime = TimeTracker(0); i_x = respX; i_y = respY; i_z = respZ; diff --git a/src/game/MotionGenerators/RandomMovementGenerator.h b/src/game/MotionGenerators/RandomMovementGenerator.h index 5be0a673..66326e08 100644 --- a/src/game/MotionGenerators/RandomMovementGenerator.h +++ b/src/game/MotionGenerators/RandomMovementGenerator.h @@ -46,7 +46,7 @@ class RandomMovementGenerator bool Update(T&, const uint32&); MovementGeneratorType GetMovementGeneratorType() const override { return RANDOM_MOTION_TYPE; } private: - ShortTimeTracker i_nextMoveTime; + TimeTracker i_nextMoveTime; float i_x, i_y, i_z; float i_radius; float i_verticalZ; diff --git a/src/game/MotionGenerators/TargetedMovementGenerator.h b/src/game/MotionGenerators/TargetedMovementGenerator.h index 3f593f20..fb0a97ee 100644 --- a/src/game/MotionGenerators/TargetedMovementGenerator.h +++ b/src/game/MotionGenerators/TargetedMovementGenerator.h @@ -69,7 +69,7 @@ class TargetedMovementGeneratorMedium bool RequiresNewPosition(T& owner, float x, float y, float z) const; virtual float GetDynamicTargetDistance(T& /*owner*/, bool /*forRangeCheck*/) const { return i_offset; } - ShortTimeTracker i_recheckDistance; + TimeTracker i_recheckDistance; float i_offset; float i_angle; G3D::Vector3 m_prevTargetPos; diff --git a/src/game/MotionGenerators/WaypointMovementGenerator.cpp b/src/game/MotionGenerators/WaypointMovementGenerator.cpp index 50487bdc..ddd58ae9 100644 --- a/src/game/MotionGenerators/WaypointMovementGenerator.cpp +++ b/src/game/MotionGenerators/WaypointMovementGenerator.cpp @@ -390,11 +390,11 @@ void WaypointMovementGenerator::GetPathInformation(std::ostringstream& void WaypointMovementGenerator::AddToWaypointPauseTime(int32 waitTimeDiff) { - if (!i_nextMoveTime.Passed()) + i_nextMoveTime.Update(waitTimeDiff); + if (i_nextMoveTime.Passed()) { - // Prevent <= 0, the code in Update requires to catch the change from moving to not moving - int32 newWaitTime = i_nextMoveTime.GetExpiry() + waitTimeDiff; - i_nextMoveTime.Reset(newWaitTime > 0 ? newWaitTime : 1); + i_nextMoveTime.Reset(0); + return; } } diff --git a/src/game/MotionGenerators/WaypointMovementGenerator.h b/src/game/MotionGenerators/WaypointMovementGenerator.h index 7da1a504..0a9c79cc 100644 --- a/src/game/MotionGenerators/WaypointMovementGenerator.h +++ b/src/game/MotionGenerators/WaypointMovementGenerator.h @@ -99,7 +99,7 @@ class WaypointMovementGenerator void OnArrived(Creature&); void StartMove(Creature&); - ShortTimeTracker i_nextMoveTime; + TimeTracker i_nextMoveTime; bool m_isArrivalDone; uint32 m_lastReachedWaypoint; diff --git a/src/game/Object/Object.cpp b/src/game/Object/Object.cpp index e6ea9030..caf86750 100644 --- a/src/game/Object/Object.cpp +++ b/src/game/Object/Object.cpp @@ -44,6 +44,7 @@ #include "movement/packet_builder.h" #include "CreatureLinkingMgr.h" #include "Chat.h" +#include "GameTime.h" #ifdef ENABLE_ELUNA #include "LuaEngine.h" #include "ElunaEventMgr.h" @@ -322,7 +323,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint8 updateFlags) const // 0x2 if (updateFlags & UPDATEFLAG_TRANSPORT) { - *data << uint32(WorldTimer::getMSTime()); // ms time + *data << uint32(GameTime::GetGameTimeMS()); // ms time } } diff --git a/src/game/Object/Object.h b/src/game/Object/Object.h index c3086cfd..d0d47fdb 100644 --- a/src/game/Object/Object.h +++ b/src/game/Object/Object.h @@ -31,6 +31,7 @@ #include "UpdateData.h" #include "ObjectGuid.h" #include "Camera.h" +#include "GameTime.h" #include @@ -114,13 +115,13 @@ class WorldUpdateCounter { if (!m_tmStart) { - m_tmStart = WorldTimer::tickPrevTime(); + m_tmStart = GameTime::GetGameTimeMS(); } - return WorldTimer::getMSTimeDiff(m_tmStart, WorldTimer::tickTime()); + return getMSTimeDiff(m_tmStart, GameTime::GetGameTimeMS()); } - void Reset() { m_tmStart = WorldTimer::tickTime(); } + void Reset() { m_tmStart = GameTime::GetGameTimeMS(); } private: uint32 m_tmStart; diff --git a/src/game/Object/Unit.cpp b/src/game/Object/Unit.cpp index 09787604..5a169a94 100644 --- a/src/game/Object/Unit.cpp +++ b/src/game/Object/Unit.cpp @@ -52,6 +52,7 @@ #include "movement/MoveSplineInit.h" #include "movement/MoveSpline.h" #include "CreatureLinkingMgr.h" +#include "GameTime.h" #ifdef ENABLE_ELUNA #include "LuaEngine.h" #include "ElunaEventMgr.h" @@ -59,17 +60,6 @@ #include -#ifdef WIN32 -inline uint32 getMSTime() { return GetTickCount(); } -#else -inline uint32 getMSTime() -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); -} -#endif - float baseMoveSpeed[MAX_MOVE_TYPE] = { 2.5f, // MOVE_WALK @@ -170,12 +160,12 @@ void MovementInfo::Write(ByteBuffer& data) const bool GlobalCooldownMgr::HasGlobalCooldown(SpellEntry const* spellInfo) const { GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory); - return itr != m_GlobalCooldowns.end() && itr->second.duration && WorldTimer::getMSTimeDiff(itr->second.cast_time, WorldTimer::getMSTime()) < itr->second.duration; + return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, GameTime::GetGameTimeMS()) < itr->second.duration; } void GlobalCooldownMgr::AddGlobalCooldown(SpellEntry const* spellInfo, uint32 gcd) { - m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, WorldTimer::getMSTime()); + m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, GameTime::GetGameTimeMS()); } void GlobalCooldownMgr::CancelGlobalCooldown(SpellEntry const* spellInfo) @@ -485,7 +475,7 @@ bool Unit::haveOffhandWeapon() const void Unit::SendHeartBeat() { - m_movementInfo.UpdateTime(WorldTimer::getMSTime()); + m_movementInfo.UpdateTime(GameTime::GetGameTimeMS()); WorldPacket data(MSG_MOVE_HEARTBEAT, 31); data << GetPackGUID(); data << m_movementInfo; @@ -8825,7 +8815,7 @@ DiminishingLevels Unit::GetDiminishing(DiminishingGroup group) } // If last spell was casted more than 15 seconds ago - reset the count. - if (i->stack == 0 && WorldTimer::getMSTimeDiff(i->hitTime, WorldTimer::getMSTime()) > 15 * IN_MILLISECONDS) + if (i->stack == 0 && getMSTimeDiff(i->hitTime, GameTime::GetGameTimeMS()) > 15 * IN_MILLISECONDS) { i->hitCount = DIMINISHING_LEVEL_1; return DIMINISHING_LEVEL_1; @@ -8854,7 +8844,7 @@ void Unit::IncrDiminishing(DiminishingGroup group) } return; } - m_Diminishing.push_back(DiminishingReturn(group, WorldTimer::getMSTime(), DIMINISHING_LEVEL_2)); + m_Diminishing.push_back(DiminishingReturn(group, GameTime::GetGameTimeMS(), DIMINISHING_LEVEL_2)); } void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32& duration, Unit* caster, DiminishingLevels Level, bool isReflected) @@ -8903,7 +8893,7 @@ void Unit::ApplyDiminishingAura(DiminishingGroup group, bool apply) // Remember time after last aura from group removed if (i->stack == 0) { - i->hitTime = WorldTimer::getMSTime(); + i->hitTime = GameTime::GetGameTimeMS(); } } break; diff --git a/src/game/Object/Unit.h b/src/game/Object/Unit.h index b7d80c89..cd9bd654 100644 --- a/src/game/Object/Unit.h +++ b/src/game/Object/Unit.h @@ -3850,7 +3850,7 @@ protected: UnitVisibility m_Visibility; Position m_last_notified_position; bool m_AINotifyScheduled; - ShortTimeTracker m_movesplineTimer; + TimeTracker m_movesplineTimer; Diminishing m_Diminishing; // Manage all Units threatening us diff --git a/src/game/OutdoorPvP/OutdoorPvPMgr.h b/src/game/OutdoorPvP/OutdoorPvPMgr.h index 6f19a330..b3d6b0f7 100644 --- a/src/game/OutdoorPvP/OutdoorPvPMgr.h +++ b/src/game/OutdoorPvP/OutdoorPvPMgr.h @@ -163,7 +163,7 @@ class OutdoorPvPMgr */ CapturePointSliderMap m_capturePointSlider; - ShortIntervalTimer m_updateTimer; /**< update interval */ + IntervalTimer m_updateTimer; /**< update interval */ }; #define sOutdoorPvPMgr MaNGOS::Singleton::Instance() diff --git a/src/game/Time/GameTime.cpp b/src/game/Time/GameTime.cpp new file mode 100644 index 00000000..f98c0bbd --- /dev/null +++ b/src/game/Time/GameTime.cpp @@ -0,0 +1,75 @@ +/** + * MaNGOS is a full featured server for World of Warcraft, supporting + * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 + * + * Copyright (C) 2005-2021 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * World of Warcraft, and all World of Warcraft or Warcraft art, images, + * and lore are copyrighted by Blizzard Entertainment, Inc. + */ + +#include "GameTime.h" +#include "Timer.h" + +namespace GameTime +{ + time_t const StartTime = time(nullptr); + + time_t GameTime = 0; + uint32 GameMSTime = 0; + + std::chrono::system_clock::time_point GameTimeSystemPoint = std::chrono::system_clock::time_point::min(); + std::chrono::steady_clock::time_point GameTimeSteadyPoint = std::chrono::steady_clock::time_point::min(); + + time_t GetStartTime() + { + return StartTime; + } + + time_t GetGameTime() + { + return GameTime; + } + + uint32 GetGameTimeMS() + { + return GameMSTime; + } + + std::chrono::system_clock::time_point GetGameTimeSystemPoint() + { + return GameTimeSystemPoint; + } + + std::chrono::steady_clock::time_point GetGameTimeSteadyPoint() + { + return GameTimeSteadyPoint; + } + + uint32 GetUptime() + { + return uint32(GameTime - StartTime); + } + + void UpdateGameTimers() + { + GameTime = time(nullptr); + GameMSTime = getMSTime(); + GameTimeSystemPoint = std::chrono::system_clock::now(); + GameTimeSteadyPoint = std::chrono::steady_clock::now(); + } +} diff --git a/src/game/Time/GameTime.h b/src/game/Time/GameTime.h new file mode 100644 index 00000000..da3ff121 --- /dev/null +++ b/src/game/Time/GameTime.h @@ -0,0 +1,55 @@ +/** + * MaNGOS is a full featured server for World of Warcraft, supporting + * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 + * + * Copyright (C) 2005-2021 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * World of Warcraft, and all World of Warcraft or Warcraft art, images, + * and lore are copyrighted by Blizzard Entertainment, Inc. + */ + +#ifndef GAMETIME_H +#define GAMETIME_H + +#include "Define.h" + +#include + +namespace GameTime +{ + // Server Start Time + time_t GetStartTime(); + + // Current Server Time (unix) in seconds + time_t GetGameTime(); + + // Milliseconds since Server Start + uint32 GetGameTimeMS(); + + // Current chrono system_clock time point + std::chrono::system_clock::time_point GetGameTimeSystemPoint(); + + // Current chrono steady_clock time point + std::chrono::steady_clock::time_point GetGameTimeSteadyPoint(); + + // Uptime (in seconds) + uint32 GetUptime(); + + void UpdateGameTimers(); +} + +#endif diff --git a/src/game/Time/UpdateTime.cpp b/src/game/Time/UpdateTime.cpp new file mode 100644 index 00000000..445ecf77 --- /dev/null +++ b/src/game/Time/UpdateTime.cpp @@ -0,0 +1,146 @@ +/** + * MaNGOS is a full featured server for World of Warcraft, supporting + * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 + * + * Copyright (C) 2005-2021 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * World of Warcraft, and all World of Warcraft or Warcraft art, images, + * and lore are copyrighted by Blizzard Entertainment, Inc. + */ + + +#include "UpdateTime.h" + +#include "Timer.h" +#include "Config.h" +#include "Log.h" + +WorldUpdateTime sWorldUpdateTime; + +UpdateTime::UpdateTime() : _averageUpdateTime(0), _totalUpdateTime(0), _updateTimeTableIndex(0), _maxUpdateTime(0), + _maxUpdateTimeOfLastTable(0), _maxUpdateTimeOfCurrentTable(0), _updateTimeDataTable() { } + +uint32 UpdateTime::GetAverageUpdateTime() const +{ + return _averageUpdateTime; +} + +uint32 UpdateTime::GetTimeWeightedAverageUpdateTime() const +{ + uint32 sum = 0, weightsum = 0; + for (uint32 diff : _updateTimeDataTable) + { + sum += diff * diff; + weightsum += diff; + } + + return sum / weightsum; +} + +uint32 UpdateTime::GetMaxUpdateTime() const +{ + return _maxUpdateTime; +} + +uint32 UpdateTime::GetMaxUpdatTimeOfCurrentTable() const +{ + return std::max(_maxUpdateTimeOfCurrentTable, _maxUpdateTimeOfLastTable); +} + +uint32 UpdateTime::GetLastUpdateTime() const +{ + return _updateTimeDataTable[_updateTimeTableIndex != 0 ? _updateTimeTableIndex - 1 : _updateTimeDataTable.size() - 1]; +} + +void UpdateTime::UpdateWithDiff(uint32 diff) +{ + _totalUpdateTime = _totalUpdateTime - _updateTimeDataTable[_updateTimeTableIndex] + diff; + _updateTimeDataTable[_updateTimeTableIndex] = diff; + + if (diff > _maxUpdateTime) + { + _maxUpdateTime = diff; + } + + if (diff > _maxUpdateTimeOfCurrentTable) + { + _maxUpdateTimeOfCurrentTable = diff; + } + + if (++_updateTimeTableIndex >= _updateTimeDataTable.size()) + { + _updateTimeTableIndex = 0; + _maxUpdateTimeOfLastTable = _maxUpdateTimeOfCurrentTable; + _maxUpdateTimeOfCurrentTable = 0; + } + + if (_updateTimeDataTable[_updateTimeDataTable.size() - 1]) + { + _averageUpdateTime = _totalUpdateTime / _updateTimeDataTable.size(); + } + else if (_updateTimeTableIndex) + { + _averageUpdateTime = _totalUpdateTime / _updateTimeTableIndex; + } +} + +void UpdateTime::RecordUpdateTimeReset() +{ + _recordedTime = getMSTime(); +} + +void UpdateTime::_RecordUpdateTimeDuration(std::string const& text, uint32 minUpdateTime) +{ + uint32 thisTime = getMSTime(); + uint32 diff = getMSTimeDiff(_recordedTime, thisTime); + + if (diff > minUpdateTime) + { + sLog.outError("Record Update Time of %s: %u", text.c_str(), diff); + } + + _recordedTime = thisTime; +} + +void WorldUpdateTime::LoadFromConfig() +{ + // ToDo: move to configuration + _recordUpdateTimeInverval = 60000; + _recordUpdateTimeMin = 100; +} + +void WorldUpdateTime::SetRecordUpdateTimeInterval(uint32 t) +{ + _recordUpdateTimeInverval = t; +} + +void WorldUpdateTime::RecordUpdateTime(uint32 gameTimeMs, uint32 diff, uint32 sessionCount) +{ + if (_recordUpdateTimeInverval > 0 && diff > _recordUpdateTimeMin) + { + if (getMSTimeDiff(_lastRecordTime, gameTimeMs) > _recordUpdateTimeInverval) + { + sLog.outString("Update time diff: %u. Players online: %u", GetAverageUpdateTime(), sessionCount); + _lastRecordTime = gameTimeMs; + } + } +} + +void WorldUpdateTime::RecordUpdateTimeDuration(std::string const& text) +{ + _RecordUpdateTimeDuration(text, _recordUpdateTimeMin); +} diff --git a/src/game/Time/UpdateTime.h b/src/game/Time/UpdateTime.h new file mode 100644 index 00000000..49f5e4a0 --- /dev/null +++ b/src/game/Time/UpdateTime.h @@ -0,0 +1,85 @@ +/** + * MaNGOS is a full featured server for World of Warcraft, supporting + * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 + * + * Copyright (C) 2005-2021 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * World of Warcraft, and all World of Warcraft or Warcraft art, images, + * and lore are copyrighted by Blizzard Entertainment, Inc. + */ + +#ifndef UPDATETIME_H +#define UPDATETIME_H + +#include "Common.h" +#include "Timer.h" + +#include +#include + +#define AVG_DIFF_COUNT 500 + +class UpdateTime +{ + using DiffTableArray = std::array; + +public: + uint32 GetAverageUpdateTime() const; + uint32 GetTimeWeightedAverageUpdateTime() const; + uint32 GetMaxUpdateTime() const; + uint32 GetMaxUpdatTimeOfCurrentTable() const; + uint32 GetLastUpdateTime() const; + + void UpdateWithDiff(uint32 diff); + + void RecordUpdateTimeReset(); + +protected: + UpdateTime(); + + void _RecordUpdateTimeDuration(std::string const& text, uint32 minUpdateTime); + +private: + DiffTableArray _updateTimeDataTable; + uint32 _averageUpdateTime; + uint32 _totalUpdateTime; + uint32 _updateTimeTableIndex; + uint32 _maxUpdateTime; + uint32 _maxUpdateTimeOfLastTable; + uint32 _maxUpdateTimeOfCurrentTable; + + uint32 _recordedTime; +}; + +class WorldUpdateTime : public UpdateTime +{ +public: + WorldUpdateTime() : UpdateTime(), _recordUpdateTimeInverval(0), _recordUpdateTimeMin(0), _lastRecordTime(0) { } + void LoadFromConfig(); + void SetRecordUpdateTimeInterval(uint32 t); + void RecordUpdateTime(uint32 gameTimeMs, uint32 diff, uint32 sessionCount); + void RecordUpdateTimeDuration(std::string const& text); + +private: + uint32 _recordUpdateTimeInverval; + uint32 _recordUpdateTimeMin; + uint32 _lastRecordTime; +}; + +extern WorldUpdateTime sWorldUpdateTime; + +#endif diff --git a/src/game/Warden/Warden.cpp b/src/game/Warden/Warden.cpp index 7649bf94..136ed626 100644 --- a/src/game/Warden/Warden.cpp +++ b/src/game/Warden/Warden.cpp @@ -35,6 +35,7 @@ #include "Util.h" #include "Warden.h" #include "AccountMgr.h" +#include "GameTime.h" Warden::Warden() : _session(NULL), _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0), _module(NULL), _state(WardenState::STATE_INITIAL) @@ -42,7 +43,7 @@ Warden::Warden() : _session(NULL), _inputCrypto(16), _outputCrypto(16), _checkTi memset(_inputKey, 0, sizeof(_inputKey)); memset(_outputKey, 0, sizeof(_outputKey)); memset(_seed, 0, sizeof(_seed)); - _previousTimestamp = WorldTimer::getMSTime(); + _previousTimestamp = GameTime::GetGameTimeMS(); } Warden::~Warden() @@ -128,7 +129,7 @@ void Warden::RequestModule() void Warden::Update() { - uint32 currentTimestamp = WorldTimer::getMSTime(); + uint32 currentTimestamp = GameTime::GetGameTimeMS(); uint32 diff = currentTimestamp - _previousTimestamp; _previousTimestamp = currentTimestamp; diff --git a/src/game/Warden/WardenMac.cpp b/src/game/Warden/WardenMac.cpp index 1a0f41bf..ff582cff 100644 --- a/src/game/Warden/WardenMac.cpp +++ b/src/game/Warden/WardenMac.cpp @@ -36,6 +36,7 @@ #include "Util.h" #include "WardenMac.h" #include "WardenModuleMac.h" +#include "GameTime.h" WardenMac::WardenMac() : Warden() { } @@ -177,7 +178,7 @@ void WardenMac::HandleHashResult(ByteBuffer &buff) _inputCrypto.Init(_inputKey); _outputCrypto.Init(_outputKey); - _previousTimestamp = WorldTimer::getMSTime(); + _previousTimestamp = GameTime::GetGameTimeMS(); } void WardenMac::RequestData() diff --git a/src/game/Warden/WardenWin.cpp b/src/game/Warden/WardenWin.cpp index f22bbe93..2b73b280 100644 --- a/src/game/Warden/WardenWin.cpp +++ b/src/game/Warden/WardenWin.cpp @@ -39,6 +39,7 @@ #include "WardenWin.h" #include "WardenModuleWin.h" #include "WardenCheckMgr.h" +#include "GameTime.h" WardenWin::WardenWin() : Warden(), _serverTicks(0) {} @@ -156,7 +157,7 @@ void WardenWin::HandleHashResult(ByteBuffer &buff) _inputCrypto.Init(_inputKey); _outputCrypto.Init(_outputKey); - _previousTimestamp = WorldTimer::getMSTime(); + _previousTimestamp = GameTime::GetGameTimeMS(); } void WardenWin::RequestData() @@ -179,7 +180,7 @@ void WardenWin::RequestData() sWardenCheckMgr->GetWardenCheckIds(false, build, _otherChecksTodo); } - _serverTicks = WorldTimer::getMSTime(); + _serverTicks = GameTime::GetGameTimeMS(); _currentChecks.clear(); @@ -355,7 +356,7 @@ void WardenWin::HandleData(ByteBuffer &buff) uint32 newClientTicks; buff >> newClientTicks; - uint32 ticksNow = WorldTimer::getMSTime(); + uint32 ticksNow = GameTime::GetGameTimeMS(); uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks); sLog.outWarden("ServerTicks %u, RequestTicks %u, ClientTicks %u", ticksNow, _serverTicks, newClientTicks); // Now, At request, At response diff --git a/src/game/WorldHandlers/CharacterHandler.cpp b/src/game/WorldHandlers/CharacterHandler.cpp index 6fd9851c..9a4d2cc1 100644 --- a/src/game/WorldHandlers/CharacterHandler.cpp +++ b/src/game/WorldHandlers/CharacterHandler.cpp @@ -45,6 +45,7 @@ #include "Language.h" #include "Chat.h" #include "SpellMgr.h" +#include "GameTime.h" #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ @@ -799,7 +800,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) #endif /* Sync player's in-game time with server time */ - pCurrChar->SetInGameTime(WorldTimer::getMSTime()); + pCurrChar->SetInGameTime(GameTime::GetGameTimeMS()); /* Send logon notification to player's group * This is sent after player is added to the world so that player receives it too */ diff --git a/src/game/WorldHandlers/GridMap.h b/src/game/WorldHandlers/GridMap.h index 462d3932..f14ac202 100644 --- a/src/game/WorldHandlers/GridMap.h +++ b/src/game/WorldHandlers/GridMap.h @@ -275,7 +275,7 @@ class TerrainInfo : public Referencable int16 m_GridRef[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; // global garbage collection timer - ShortIntervalTimer i_timer; + IntervalTimer i_timer; typedef ACE_Thread_Mutex LOCK_TYPE; LOCK_TYPE m_mutex; diff --git a/src/game/WorldHandlers/MovementHandler.cpp b/src/game/WorldHandlers/MovementHandler.cpp index 3ba35f92..60ec86f6 100644 --- a/src/game/WorldHandlers/MovementHandler.cpp +++ b/src/game/WorldHandlers/MovementHandler.cpp @@ -575,7 +575,7 @@ bool WorldSession::VerifyMovementInfo(MovementInfo const& movementInfo) const void WorldSession::HandleMoverRelocation(MovementInfo& movementInfo) { - //uint32 mstime = WorldTimer::getMSTime(); + //uint32 mstime = GameTime::GetGameTimeMS(); //if (m_clientTimeDelay == 0) // m_clientTimeDelay = mstime - movementInfo.GetTime(); diff --git a/src/game/WorldHandlers/Transports.cpp b/src/game/WorldHandlers/Transports.cpp index ffd4a511..9a335d1f 100644 --- a/src/game/WorldHandlers/Transports.cpp +++ b/src/game/WorldHandlers/Transports.cpp @@ -30,6 +30,7 @@ #include "ObjectMgr.h" #include "ObjectGuid.h" #include "Path.h" +#include "GameTime.h" #include "WorldPacket.h" #include "DBCStores.h" @@ -655,7 +656,7 @@ void GlobalTransport::Update(uint32 /*update_diff*/, uint32 /*p_time*/) return; } - m_timer = WorldTimer::getMSTime() % m_period; + m_timer = GameTime::GetGameTimeMS() % m_period; while (((m_timer - m_curr->first) % m_pathTime) > ((m_next->first - m_curr->first) % m_pathTime)) { MoveToNextWayPoint(); diff --git a/src/game/WorldHandlers/Weather.h b/src/game/WorldHandlers/Weather.h index fa418f7b..f05c5ebd 100644 --- a/src/game/WorldHandlers/Weather.h +++ b/src/game/WorldHandlers/Weather.h @@ -100,7 +100,7 @@ class Weather uint32 m_zone; WeatherType m_type; float m_grade; - ShortIntervalTimer m_timer; + IntervalTimer m_timer; WeatherZoneChances const* m_weatherChances; bool m_isPermanentWeather; }; diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index 27ae6d6e..4be91bf0 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -74,6 +74,8 @@ #include "Language.h" #include "CommandMgr.h" #include "revision.h" +#include "UpdateTime.h" +#include "GameTime.h" #ifdef ENABLE_ELUNA #include "LuaEngine.h" @@ -962,7 +964,7 @@ void World::SetInitialWorldSettings() srand((unsigned int)time(NULL)); ///- Time server startup - uint32 uStartTime = WorldTimer::getMSTime(); + uint32 startupBegin = GameTime::GetGameTimeMS(); ///- Initialize detour memory management dtAllocSetCustom(dtCustomAlloc, dtCustomFree); @@ -1500,8 +1502,8 @@ void World::SetInitialWorldSettings() showFooter(); - uint32 uStartInterval = WorldTimer::getMSTimeDiff(uStartTime, WorldTimer::getMSTime()); - sLog.outString("SERVER STARTUP TIME: %i minutes %i seconds", uStartInterval / 60000, (uStartInterval % 60000) / 1000); + uint32 startupDuration = GetMSTimeDiffToNow(startupBegin); + sLog.outString("SERVER STARTUP TIME: %i minutes %i seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000)); sLog.outString(); } @@ -1676,6 +1678,8 @@ void World::Update(uint32 diff) ///- Update the game time and check for shutdown time _UpdateGameTime(); + sWorldUpdateTime.UpdateWithDiff(diff); + ///-Update mass mailer tasks if any sMassMailMgr.Update(); diff --git a/src/game/vmap/DynamicTree.cpp b/src/game/vmap/DynamicTree.cpp index 6e98847d..9c6313c9 100644 --- a/src/game/vmap/DynamicTree.cpp +++ b/src/game/vmap/DynamicTree.cpp @@ -98,7 +98,7 @@ struct DynTreeImpl : public ParentTree/*, public Intersectable*/ } } - ShortTimeTracker rebalance_timer; + TimeTracker rebalance_timer; int unbalanced_times; }; diff --git a/src/mangosd/AFThread.cpp b/src/mangosd/AFThread.cpp index 714d8e27..87d1d5f7 100644 --- a/src/mangosd/AFThread.cpp +++ b/src/mangosd/AFThread.cpp @@ -27,7 +27,6 @@ #include "World.h" #include "Log.h" - AntiFreezeThread::AntiFreezeThread(uint32 delay) : delaytime_(delay) { m_loops = 0; @@ -49,12 +48,12 @@ int AntiFreezeThread::svc(void) return 0; } - sLog.outString("AntiFreeze Thread started (%u seconds max stuck time)", delaytime_/1000); + sLog.outString("AntiFreeze Thread started (%u seconds max stuck time)", delaytime_ / 1000); while (!World::IsStopped()) { ACE_OS::sleep(1); - uint32 curtime = WorldTimer::getMSTime(); + uint32 curtime = getMSTime(); // normal work if (w_loops != World::m_worldLoopCounter.value()) @@ -63,12 +62,13 @@ int AntiFreezeThread::svc(void) w_loops = World::m_worldLoopCounter.value(); } // possible freeze - else if (WorldTimer::getMSTimeDiff(w_lastchange, curtime) > delaytime_) + else if (getMSTimeDiff(w_lastchange, curtime) > delaytime_) { sLog.outError("World Thread hangs, kicking out server!"); *((uint32 volatile*)NULL) = 0; // bang crash } } + sLog.outString("AntiFreeze Thread stopped."); return 0; } diff --git a/src/mangosd/WorldThread.cpp b/src/mangosd/WorldThread.cpp index ce6a219b..83f2d0b9 100644 --- a/src/mangosd/WorldThread.cpp +++ b/src/mangosd/WorldThread.cpp @@ -36,6 +36,9 @@ #include "MapManager.h" #include "Database/DatabaseEnv.h" +#include +#include + #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ @@ -71,38 +74,35 @@ int WorldThread::open(void* unused) /// Heartbeat for the World int WorldThread::svc() { - uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST + uint32 realCurrTime = 0; + uint32 realPrevTime = getMSTime(); sLog.outString("World Updater Thread started (%dms min update interval)", WORLD_SLEEP_CONST); ///- While we have not World::m_stopEvent, update the world while (!World::IsStopped()) { ++World::m_worldLoopCounter; + realCurrTime = getMSTime(); - uint32 diff = WorldTimer::tick(); + uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime); sWorld.Update(diff); + realPrevTime = realCurrTime; - // diff (D0) include time of previous sleep (d0) + tick time (t0) - // we want that next d1 + t1 == WORLD_SLEEP_CONST - // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement - // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0 - if (diff <= WORLD_SLEEP_CONST + prevSleepTime) + uint32 executionTimeDiff = getMSTimeDiff(realCurrTime, getMSTime()); + + // we know exactly how long it took to update the world, if the update took less than WORLD_SLEEP_CONST, sleep for WORLD_SLEEP_CONST - world update time + if (executionTimeDiff < WORLD_SLEEP_CONST) { - prevSleepTime = WORLD_SLEEP_CONST + prevSleepTime - diff; - ACE_Based::Thread::Sleep(prevSleepTime); - } - else - { - prevSleepTime = 0; + std::this_thread::sleep_for(std::chrono::milliseconds(WORLD_SLEEP_CONST - executionTimeDiff)); } #ifdef _WIN32 - if (m_ServiceStatus == 0) //service stopped + if (m_ServiceStatus == 0) // service stopped { World::StopNow(SHUTDOWN_EXIT_CODE); } - while (m_ServiceStatus == 2) //service paused + while (m_ServiceStatus == 2) // service paused Sleep(1000); #endif } diff --git a/src/shared/Database/DatabaseMysql.cpp b/src/shared/Database/DatabaseMysql.cpp index 89c7ca7a..fd465529 100644 --- a/src/shared/Database/DatabaseMysql.cpp +++ b/src/shared/Database/DatabaseMysql.cpp @@ -207,7 +207,7 @@ bool MySQLConnection::_Query(const char* sql, MYSQL_RES** pResult, MYSQL_FIELD** return 0; } - uint32 _s = WorldTimer::getMSTime(); + uint32 _s = getMSTime(); if (mysql_query(mMysql, sql)) { @@ -217,7 +217,7 @@ bool MySQLConnection::_Query(const char* sql, MYSQL_RES** pResult, MYSQL_FIELD** } else { - DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "[%u ms] SQL: %s", WorldTimer::getMSTimeDiff(_s, WorldTimer::getMSTime()), sql); + DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql); } *pResult = mysql_store_result(mMysql); @@ -289,7 +289,7 @@ bool MySQLConnection::Execute(const char* sql) } { - uint32 _s = WorldTimer::getMSTime(); + uint32 _s = getMSTime(); if (mysql_query(mMysql, sql)) { @@ -299,7 +299,7 @@ bool MySQLConnection::Execute(const char* sql) } else { - DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "[%u ms] SQL: %s", WorldTimer::getMSTimeDiff(_s, WorldTimer::getMSTime()), sql); + DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql); } // end guarded block } diff --git a/src/shared/Log/Log.cpp b/src/shared/Log/Log.cpp index 715c61fa..ddaafebc 100644 --- a/src/shared/Log/Log.cpp +++ b/src/shared/Log/Log.cpp @@ -357,34 +357,37 @@ FILE* Log::openGmlogPerAccount(uint32 account) void Log::outTimestamp(FILE* file) { - time_t t = time(NULL); - tm* aTm = localtime(&t); + time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + std::tm aTm = localtime_r(tt); + // YYYY year // MM month (2 digits 01-12) // DD day (2 digits 01-31) // HH hour (2 digits 00-23) // MM minutes (2 digits 00-59) // SS seconds (2 digits 00-59) - fprintf(file, "%-4d-%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); + fprintf(file, "%-4d-%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); } void Log::outTime() { - time_t t = time(NULL); - tm* aTm = localtime(&t); + time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + std::tm aTm = localtime_r(tt); + // YYYY year // MM month (2 digits 01-12) // DD day (2 digits 01-31) // HH hour (2 digits 00-23) // MM minutes (2 digits 00-59) // SS seconds (2 digits 00-59) - printf("%02d:%02d:%02d ", aTm->tm_hour, aTm->tm_min, aTm->tm_sec); + printf("%02d:%02d:%02d ", aTm.tm_hour, aTm.tm_min, aTm.tm_sec); } std::string Log::GetTimestampStr() { - time_t t = time(NULL); - tm* aTm = localtime(&t); + time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + std::tm aTm = localtime_r(tt); + // YYYY year // MM month (2 digits 01-12) // DD day (2 digits 01-31) @@ -392,7 +395,7 @@ std::string Log::GetTimestampStr() // 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); + 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); } diff --git a/src/shared/Utilities/Duration.h b/src/shared/Utilities/Duration.h new file mode 100644 index 00000000..3eab22ff --- /dev/null +++ b/src/shared/Utilities/Duration.h @@ -0,0 +1,51 @@ +/** + * MaNGOS is a full featured server for World of Warcraft, supporting + * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 + * + * Copyright (C) 2005-2021 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * World of Warcraft, and all World of Warcraft or Warcraft art, images, + * and lore are copyrighted by Blizzard Entertainment, Inc. + */ + +#ifndef DURATION_H +#define DURATION_H + +#include + + /// 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; + +/// time_point shorthand typedefs +typedef std::chrono::steady_clock::time_point TimePoint; +typedef std::chrono::system_clock::time_point SystemTimePoint; + +constexpr std::chrono::hours operator""_days(unsigned long long days) +{ + return std::chrono::hours(days * Hours(24)); +} + +#endif diff --git a/src/shared/Utilities/Timer.h b/src/shared/Utilities/Timer.h index 32df8722..52c59a76 100644 --- a/src/shared/Utilities/Timer.h +++ b/src/shared/Utilities/Timer.h @@ -25,315 +25,177 @@ #ifndef MANGOS_TIMER_H #define MANGOS_TIMER_H -#include "Common/Common.h" -#include +#include "Common.h" +#include "Duration.h" -/** - * @brief - * - */ -class WorldTimer +// New Method +inline std::chrono::steady_clock::time_point GetApplicationStartTime() { - public: + using namespace std::chrono; - /** - * @brief get current server time - * - * @return uint32 - */ - static uint32 getMSTime(); + static const steady_clock::time_point ApplicationStartTime = steady_clock::now(); - /** - * @brief get time difference between two timestamps - * - * @param oldMSTime - * @param newMSTime - * @return uint32 - */ - static inline uint32 getMSTimeDiff(const uint32& oldMSTime, const uint32& newMSTime) - { - if (oldMSTime > newMSTime) - { - const uint32 diff_1 = (uint32(0xFFFFFFFF) - oldMSTime) + newMSTime; - const uint32 diff_2 = oldMSTime - newMSTime; + return ApplicationStartTime; +} - return std::min(diff_1, diff_2); - } +inline uint32 getMSTime() +{ + using namespace std::chrono; - return newMSTime - oldMSTime; - } + return uint32(duration_cast(steady_clock::now() - GetApplicationStartTime()).count()); +} - /** - * @brief get last world tick time - * - * @return uint32 - */ - static uint32 tickTime(); - /** - * @brief get previous world tick time - * - * @return uint32 - */ - static uint32 tickPrevTime(); - /** - * @brief tick world timer - * - * @return uint32 - */ - static uint32 tick(); +inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime) +{ + // getMSTime() have limited data range and this is case when it overflow in this tick + if (oldMSTime > newMSTime) + { + return (0xFFFFFFFF - oldMSTime) + newMSTime; + } + else + { + return newMSTime - oldMSTime; + } +} - private: - /** - * @brief - * - */ - WorldTimer(); - /** - * @brief - * - * @param - */ - WorldTimer(const WorldTimer&); +inline uint32 getMSTimeDiff(uint32 oldMSTime, std::chrono::steady_clock::time_point newTime) +{ + using namespace std::chrono; - /** - * @brief analogue to getMSTime() but it persists m_SystemTickTime - * - * @param savetime - * @return uint32 - */ - static uint32 getMSTime_internal(); + uint32 newMSTime = uint32(duration_cast(newTime - GetApplicationStartTime()).count()); + + return getMSTimeDiff(oldMSTime, newMSTime); +} - static uint32 m_iTime; /**< TODO */ - static uint32 m_iPrevTime; /**< TODO */ +inline uint32 GetMSTimeDiffToNow(uint32 oldMSTime) +{ + return getMSTimeDiff(oldMSTime, getMSTime()); +} + +struct IntervalTimer +{ +public: + IntervalTimer() : _interval(0), _current(0) { } + + void Update(time_t diff) + { + _current += diff; + if (_current < 0) + { + _current = 0; + } + } + + bool Passed() + { + return _current >= _interval; + } + + void Reset() + { + if (_current >= _interval) + { + _current %= _interval; + } + } + + void SetCurrent(time_t current) + { + _current = current; + } + + void SetInterval(time_t interval) + { + _interval = interval; + } + + time_t GetInterval() const + { + return _interval; + } + + time_t GetCurrent() const + { + return _current; + } + +private: + + time_t _interval; + time_t _current; }; -/** - * @brief - * - */ -class IntervalTimer -{ - public: - /** - * @brief - * - */ - IntervalTimer() : _interval(0), _current(0) {} - - /** - * @brief - * - * @param diff - */ - void Update(time_t diff) - { - _current += diff; - if (_current < 0) - { - _current = 0; - } - } - /** - * @brief - * - * @return bool - */ - bool Passed() const { return _current >= _interval; } - /** - * @brief - * - */ - void Reset() - { - if (_current >= _interval) - { - _current -= _interval; - } - } - - /** - * @brief - * - * @param current - */ - void SetCurrent(time_t current) { _current = current; } - /** - * @brief - * - * @param interval - */ - void SetInterval(time_t interval) { _interval = interval; } - /** - * @brief - * - * @return time_t - */ - time_t GetInterval() const { return _interval; } - /** - * @brief - * - * @return time_t - */ - time_t GetCurrent() const { return _current; } - - private: - time_t _interval; /**< TODO */ - time_t _current; /**< TODO */ -}; - -/** - * @brief - * - */ -class ShortIntervalTimer -{ - public: - /** - * @brief - * - */ - ShortIntervalTimer() : _interval(0), _current(0) {} - - /** - * @brief - * - * @param diff - */ - void Update(uint32 diff) - { - _current += diff; - } - - /** - * @brief - * - * @return bool - */ - bool Passed() const { return _current >= _interval; } - /** - * @brief - * - */ - void Reset() - { - if (_current >= _interval) - { - _current -= _interval; - } - } - - /** - * @brief - * - * @param current - */ - void SetCurrent(uint32 current) { _current = current; } - /** - * @brief - * - * @param interval - */ - void SetInterval(uint32 interval) { _interval = interval; } - /** - * @brief - * - * @return uint32 - */ - uint32 GetInterval() const { return _interval; } - /** - * @brief - * - * @return uint32 - */ - uint32 GetCurrent() const { return _current; } - - private: - uint32 _interval; /**< TODO */ - uint32 _current; /**< TODO */ -}; - -/** - * @brief - * - */ struct TimeTracker { - public: - /** - * @brief - * - * @param expiry - */ - TimeTracker(time_t expiry) : i_expiryTime(expiry) {} - /** - * @brief - * - * @param diff - */ - void Update(time_t diff) { i_expiryTime -= diff; } - /** - * @brief - * - * @return bool - */ - bool Passed() const { return (i_expiryTime <= 0); } - /** - * @brief - * - * @param interval - */ - void Reset(time_t interval) { i_expiryTime = interval; } - /** - * @brief - * - * @return time_t - */ - time_t GetExpiry() const { return i_expiryTime; } +public: + TimeTracker(int32 expiry = 0) : _expiryTime(expiry) { } + TimeTracker(Milliseconds expiry) : _expiryTime(expiry) { } - private: - time_t i_expiryTime; /**< TODO */ + void Update(int32 diff) + { + Update(Milliseconds(diff)); + } + + void Update(Milliseconds diff) + { + _expiryTime -= diff; + } + + bool Passed() const + { + return _expiryTime <= Seconds(0); + } + + void Reset(int32 expiry) + { + Reset(Milliseconds(expiry)); + } + + void Reset(Milliseconds expiry) + { + _expiryTime = expiry; + } + + Milliseconds GetExpiry() const + { + return _expiryTime; + } + +private: + Milliseconds _expiryTime; }; -/** - * @brief - * - */ -struct ShortTimeTracker +struct PeriodicTimer { - public: - /** - * @brief - * - * @param expiry - */ - ShortTimeTracker(int32 expiry = 0) : i_expiryTime(expiry) {} - /** - * @brief - * - * @param diff - */ - void Update(int32 diff) { i_expiryTime -= diff; } - /** - * @brief - * - * @return bool - */ - bool Passed() const { return (i_expiryTime <= 0); } - /** - * @brief - * - * @param interval - */ - void Reset(int32 interval) { i_expiryTime = interval; } - /** - * @brief - * - * @return int32 - */ - int32 GetExpiry() const { return i_expiryTime; } +public: + PeriodicTimer(int32 period, int32 start_time) : + i_period(period), i_expireTime(start_time) { } - private: - int32 i_expiryTime; /**< TODO */ + bool Update(const uint32 diff) + { + if ((i_expireTime -= diff) > 0) + { + return false; + } + + i_expireTime += i_period > int32(diff) ? i_period : diff; + return true; + } + + void SetPeriodic(int32 period, int32 start_time) + { + i_expireTime = start_time; + i_period = period; + } + + // Tracker interface + void TUpdate(int32 diff) { i_expireTime -= diff; } + bool TPassed() const { return i_expireTime <= 0; } + void TReset(int32 diff, int32 period) { i_expireTime += period > diff ? period : diff; } + +private: + int32 i_period; + int32 i_expireTime; }; #endif diff --git a/src/shared/Utilities/Util.cpp b/src/shared/Utilities/Util.cpp index 2d3c697d..a8750bc2 100644 --- a/src/shared/Utilities/Util.cpp +++ b/src/shared/Utilities/Util.cpp @@ -27,50 +27,8 @@ #include "utf8.h" #include "RNGen.h" -#include -#include #include "Log/Log.h" -static ACE_Time_Value g_SystemTickTime = ACE_OS::gettimeofday(); - -uint32 WorldTimer::m_iTime = 0; -uint32 WorldTimer::m_iPrevTime = 0; - -uint32 WorldTimer::tickTime() { return m_iTime; } -uint32 WorldTimer::tickPrevTime() { return m_iPrevTime; } - -uint32 WorldTimer::tick() -{ - // save previous world tick time - m_iPrevTime = m_iTime; - - // get the new one and don't forget to persist current system time in m_SystemTickTime - m_iTime = WorldTimer::getMSTime_internal(); - - // return tick diff - return getMSTimeDiff(m_iPrevTime, m_iTime); -} - -uint32 WorldTimer::getMSTime() -{ - return getMSTime_internal(); -} - -uint32 WorldTimer::getMSTime_internal() -{ - // get current time - const ACE_Time_Value currTime = ACE_OS::gettimeofday(); - // calculate time diff between two world ticks - // special case: curr_time < old_time - we suppose that our time has not ticked at all - // this should be constant value otherwise it is possible that our time can start ticking backwards until next world tick!!! - uint64 diff = 0; - (currTime - g_SystemTickTime).msec(diff); - - // lets calculate current world time - uint32 iRes = uint32(diff % UI64LIT(0x00000000FFFFFFFF)); - return iRes; -} - ////////////////////////////////////////////////////////////////////////// int32 irand(int32 min, int32 max) { @@ -194,6 +152,17 @@ void stripLineInvisibleChars(std::string& str) } } +std::tm localtime_r(const time_t& time) +{ + std::tm tm_snapshot; +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) + localtime_s(&tm_snapshot, &time); +#else + localtime_r(&time, &tm_snapshot); // POSIX +#endif + return tm_snapshot; +} + std::string secsToTimeString(time_t timeInSecs, bool shortText, bool hoursOnly) { time_t secs = timeInSecs % MINUTE; @@ -259,7 +228,7 @@ uint32 TimeStringToSecs(const std::string& timestring) std::string TimeToTimestampStr(time_t t) { - tm* aTm = localtime(&t); + tm aTm = localtime_r(t); // YYYY year // MM month (2 digits 01-12) // DD day (2 digits 01-31) @@ -267,7 +236,7 @@ std::string TimeToTimestampStr(time_t t) // 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); + 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); } diff --git a/src/shared/Utilities/Util.h b/src/shared/Utilities/Util.h index a4f3ec55..f74792ea 100644 --- a/src/shared/Utilities/Util.h +++ b/src/shared/Utilities/Util.h @@ -26,7 +26,6 @@ #define MANGOS_H_UTIL #include "Common/Common.h" -#include #include #include @@ -72,6 +71,13 @@ float GetFloatValueFromArray(Tokens const& data, uint16 index); */ void stripLineInvisibleChars(std::string& src); +/** + * @brief + * + * @param localtime + */ +std::tm localtime_r(const time_t& time); + /** * @brief *