diff options
author | Chaouki Dhib <chaodhib@gmail.com> | 2019-04-15 23:31:25 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-11-30 22:11:36 +0100 |
commit | c19a4db1c12b8864d6c486ee8e2f0e058fb4155a (patch) | |
tree | 1976d6734054eb05eb03322be9d76da9a0c1840c | |
parent | 2f6f1c708960bfb23a0d69ce967b67b38e72b3fa (diff) |
Core/Movement: Add time synchronisation (#18189)
(cherry picked from commit 975f1e364a6a68be2beca261a64ea8aecc16f6f6)
-rw-r--r-- | src/common/Utilities/Timer.h | 19 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 40 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 8 | ||||
-rw-r--r-- | src/server/game/Handlers/MiscHandler.cpp | 23 | ||||
-rw-r--r-- | src/server/game/Handlers/MovementHandler.cpp | 88 | ||||
-rw-r--r-- | src/server/game/Server/Packets/MiscPackets.h | 2 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldPacket.h | 7 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 50 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 27 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 6 |
11 files changed, 177 insertions, 95 deletions
diff --git a/src/common/Utilities/Timer.h b/src/common/Utilities/Timer.h index 0996c7e9dae..4abd6cc8ca1 100644 --- a/src/common/Utilities/Timer.h +++ b/src/common/Utilities/Timer.h @@ -21,13 +21,20 @@ #include "Define.h" #include <chrono> -inline uint32 getMSTime() +inline std::chrono::steady_clock::time_point GetApplicationStartTime() { using namespace std::chrono; static const steady_clock::time_point ApplicationStartTime = steady_clock::now(); - return uint32(duration_cast<milliseconds>(steady_clock::now() - ApplicationStartTime).count()); + return ApplicationStartTime; +} + +inline uint32 getMSTime() +{ + using namespace std::chrono; + + return uint32(duration_cast<milliseconds>(steady_clock::now() - GetApplicationStartTime()).count()); } inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime) @@ -39,6 +46,14 @@ inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime) return newMSTime - oldMSTime; } +inline uint32 getMSTimeDiff(uint32 oldMSTime, std::chrono::steady_clock::time_point newTime) +{ + using namespace std::chrono; + + uint32 newMSTime = uint32(duration_cast<milliseconds>(newTime - GetApplicationStartTime()).count()); + return getMSTimeDiff(oldMSTime, newMSTime); +} + inline uint32 GetMSTimeDiffToNow(uint32 oldMSTime) { return getMSTimeDiff(oldMSTime, getMSTime()); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e633754a955..f24f12540e4 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -322,10 +322,6 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this) m_ChampioningFaction = 0; - m_timeSyncTimer = 0; - m_timeSyncClient = 0; - m_timeSyncServer = GameTime::GetGameTimeMS(); - for (uint8 i = 0; i < MAX_POWERS_PER_CLASS; ++i) m_powerFraction[i] = 0; @@ -1132,14 +1128,6 @@ void Player::Update(uint32 p_time) m_zoneUpdateTimer -= p_time; } - if (m_timeSyncTimer > 0 && !IsBeingTeleportedFar()) - { - if (p_time >= m_timeSyncTimer) - SendTimeSync(); - else - m_timeSyncTimer -= p_time; - } - if (IsAlive()) { m_regenTimer += p_time; @@ -24295,10 +24283,10 @@ void Player::SendInitialPacketsBeforeAddToMap() if (!(m_teleport_options & TELE_TO_SEAMLESS)) { m_movementCounter = 0; - ResetTimeSync(); + GetSession()->ResetTimeSync(); } - SendTimeSync(); + GetSession()->SendTimeSync(); /// Pass 'this' as argument because we're not stored in ObjectAccessor yet GetSocial()->SendSocialList(this, SOCIAL_FLAG_ALL); @@ -27802,30 +27790,6 @@ void Player::LoadActions(PreparedQueryResult result) SendActionButtons(1); } -void Player::ResetTimeSync() -{ - m_timeSyncTimer = 0; - m_timeSyncClient = 0; - m_timeSyncServer = GameTime::GetGameTimeMS(); -} - -void Player::SendTimeSync() -{ - m_timeSyncQueue.push(m_movementCounter++); - - WorldPackets::Misc::TimeSyncRequest packet; - packet.SequenceIndex = m_timeSyncQueue.back(); - SendDirectMessage(packet.Write()); - - // Schedule next sync in 10 sec - m_timeSyncTimer = 10000; - m_timeSyncServer = GameTime::GetGameTimeMS(); - - if (m_timeSyncQueue.size() > 3) - TC_LOG_ERROR("network", "Player::SendTimeSync: Did not receive CMSG_TIME_SYNC_RESP for over 30 seconds from '%s' (%s), possible cheater", - GetName().c_str(), GetGUID().ToString().c_str()); -} - void Player::SetReputation(uint32 factionentry, int32 value) { GetReputationMgr().SetReputation(sFactionStore.LookupEntry(factionentry), value); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 9774f6a9b69..53507fd4182 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2933,9 +2933,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> ItemDurationList m_itemDuration; GuidUnorderedSet m_itemSoulboundTradeable; - void ResetTimeSync(); - void SendTimeSync(); - std::unique_ptr<ResurrectionData> _resurrectionData; WorldSession* m_session; @@ -3063,11 +3060,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> uint32 m_ChampioningFaction; - std::queue<uint32> m_timeSyncQueue; - uint32 m_timeSyncTimer; - uint32 m_timeSyncClient; - uint32 m_timeSyncServer; - InstanceTimeMap _instanceResetTimes; uint32 _pendingBindId; uint32 _pendingBindTimer; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 9c49cfa17bf..5ca99c36248 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -857,29 +857,6 @@ void WorldSession::HandleSetTitleOpcode(WorldPackets::Character::SetTitle& packe GetPlayer()->SetChosenTitle(packet.TitleID); } -void WorldSession::HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse& packet) -{ - // Prevent crashing server if queue is empty - if (_player->m_timeSyncQueue.empty()) - { - TC_LOG_ERROR("network", "Received CMSG_TIME_SYNC_RESPONSE from player %s without requesting it (hacker?)", _player->GetName().c_str()); - return; - } - - if (packet.SequenceIndex != _player->m_timeSyncQueue.front()) - TC_LOG_ERROR("network", "Wrong time sync counter from player %s (cheater?)", _player->GetName().c_str()); - - TC_LOG_DEBUG("network", "Time sync received: counter %u, client ticks %u, time since last sync %u", packet.SequenceIndex, packet.ClientTime, packet.ClientTime - _player->m_timeSyncClient); - - uint32 ourTicks = packet.ClientTime + (GameTime::GetGameTimeMS() - _player->m_timeSyncServer); - - // diff should be small - TC_LOG_DEBUG("network", "Our ticks: %u, diff %u, latency %u", ourTicks, ourTicks - packet.ClientTime, GetLatency()); - - _player->m_timeSyncClient = packet.ClientTime; - _player->m_timeSyncQueue.pop(); -} - void WorldSession::HandleResetInstancesOpcode(WorldPackets::Instance::ResetInstances& /*packet*/) { if (Group* group = _player->GetGroup()) diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 7273b896c97..4cc1b5b1977 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -27,6 +27,7 @@ #include "InstanceSaveMgr.h" #include "Log.h" #include "MapManager.h" +#include "MiscPackets.h" #include "MovementPackets.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -37,8 +38,9 @@ #include "Transport.h" #include "Vehicle.h" #include "SpellMgr.h" - -#define MOVEMENT_PACKET_TIME_DELAY 0 +#include <boost/accumulators/statistics/variance.hpp> +#include <boost/accumulators/accumulators.hpp> +#include <boost/accumulators/statistics.hpp> void WorldSession::HandleMoveWorldportAckOpcode(WorldPackets::Movement::WorldPortResponse& /*packet*/) { @@ -382,15 +384,9 @@ void WorldSession::HandleMovementOpcode(OpcodeClient opcode, MovementInfo& movem if (opcode == CMSG_MOVE_FALL_LAND || opcode == CMSG_MOVE_START_SWIM || opcode == CMSG_MOVE_SET_FLY) mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::LandingOrFlight); // Parachutes - uint32 mstime = GameTime::GetGameTimeMS(); - /*----------------------*/ - if (m_clientTimeDelay == 0) - m_clientTimeDelay = mstime - movementInfo.time; - /* process position-change */ - movementInfo.time = movementInfo.time + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY; - movementInfo.guid = mover->GetGUID(); + movementInfo.time = AdjustClientMovementTime(movementInfo.time); mover->m_movementInfo = movementInfo; // Some vehicles allow the passenger to turn by himself @@ -579,7 +575,7 @@ void WorldSession::HandleMoveApplyMovementForceAck(WorldPackets::Movement::MoveA return; } - moveApplyMovementForceAck.Ack.Status.time += m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY; + moveApplyMovementForceAck.Ack.Status.time = AdjustClientMovementTime(moveApplyMovementForceAck.Ack.Status.time); WorldPackets::Movement::MoveUpdateApplyMovementForce updateApplyMovementForce; updateApplyMovementForce.Status = &moveApplyMovementForceAck.Ack.Status; @@ -601,7 +597,7 @@ void WorldSession::HandleMoveRemoveMovementForceAck(WorldPackets::Movement::Move return; } - moveRemoveMovementForceAck.Ack.Status.time += m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY; + moveRemoveMovementForceAck.Ack.Status.time = AdjustClientMovementTime(moveRemoveMovementForceAck.Ack.Status.time); WorldPackets::Movement::MoveUpdateRemoveMovementForce updateRemoveMovementForce; updateRemoveMovementForce.Status = &moveRemoveMovementForceAck.Ack.Status; @@ -643,7 +639,7 @@ void WorldSession::HandleMoveSetModMovementForceMagnitudeAck(WorldPackets::Movem } } - setModMovementForceMagnitudeAck.Ack.Status.time += m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY; + setModMovementForceMagnitudeAck.Ack.Status.time = AdjustClientMovementTime(setModMovementForceMagnitudeAck.Ack.Status.time); WorldPackets::Movement::MoveUpdateSpeed updateModMovementForceMagnitude(SMSG_MOVE_UPDATE_MOD_MOVEMENT_FORCE_MAGNITUDE); updateModMovementForceMagnitude.Status = &setModMovementForceMagnitudeAck.Ack.Status; @@ -716,3 +712,71 @@ void WorldSession::HandleMoveTimeSkippedOpcode(WorldPackets::Movement::MoveTimeS moveSkipTime.TimeSkipped = moveTimeSkipped.TimeSkipped; mover->SendMessageToSet(moveSkipTime.Write(), _player); } + +void WorldSession::HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse& timeSyncResponse) +{ + if (_pendingTimeSyncRequests.count(timeSyncResponse.SequenceIndex) == 0) + return; + + uint32 serverTimeAtSent = _pendingTimeSyncRequests.at(timeSyncResponse.SequenceIndex); + _pendingTimeSyncRequests.erase(timeSyncResponse.SequenceIndex); + + // time it took for the request to travel to the client, for the client to process it and reply and for response to travel back to the server. + // we are going to make 2 assumptions: + // 1) we assume that the request processing time equals 0. + // 2) we assume that the packet took as much time to travel from server to client than it took to travel from client to server. + uint32 roundTripDuration = getMSTimeDiff(serverTimeAtSent, timeSyncResponse.GetReceivedTime()); + uint32 lagDelay = roundTripDuration / 2; + + /* + clockDelta = serverTime - clientTime + where + serverTime: time that was displayed on the clock of the SERVER at the moment when the client processed the SMSG_TIME_SYNC_REQUEST packet. + clientTime: time that was displayed on the clock of the CLIENT at the moment when the client processed the SMSG_TIME_SYNC_REQUEST packet. + + Once clockDelta has been computed, we can compute the time of an event on server clock when we know the time of that same event on the client clock, + using the following relation: + serverTime = clockDelta + clientTime + */ + int64 clockDelta = (int64)(serverTimeAtSent + lagDelay) - (int64)timeSyncResponse.ClientTime; + _timeSyncClockDeltaQueue.push_back(std::pair<int64, uint32>(clockDelta, roundTripDuration)); + ComputeNewClockDelta(); +} + +void WorldSession::ComputeNewClockDelta() +{ + // implementation of the technique described here: https://web.archive.org/web/20180430214420/http://www.mine-control.com/zack/timesync/timesync.html + // to reduce the skew induced by dropped TCP packets that get resent. + + using namespace boost::accumulators; + + accumulator_set<uint32, features<tag::mean, tag::median, tag::variance(lazy)> > latencyAccumulator; + + for (auto pair : _timeSyncClockDeltaQueue) + latencyAccumulator(pair.second); + + uint32 latencyMedian = static_cast<uint32>(std::round(median(latencyAccumulator))); + uint32 latencyStandardDeviation = static_cast<uint32>(std::round(sqrt(variance(latencyAccumulator)))); + + accumulator_set<int64, features<tag::mean> > clockDeltasAfterFiltering; + uint32 sampleSizeAfterFiltering = 0; + for (auto pair : _timeSyncClockDeltaQueue) + { + if (pair.second < latencyStandardDeviation + latencyMedian) { + clockDeltasAfterFiltering(pair.first); + sampleSizeAfterFiltering++; + } + } + + if (sampleSizeAfterFiltering != 0) + { + int64 meanClockDelta = static_cast<int64>(std::round(mean(clockDeltasAfterFiltering))); + if (std::abs(meanClockDelta - _timeSyncClockDelta) > 25) + _timeSyncClockDelta = meanClockDelta; + } + else if (_timeSyncClockDelta == 0) + { + std::pair<int64, uint32> back = _timeSyncClockDeltaQueue.back(); + _timeSyncClockDelta = back.first; + } +} diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index 75119e91e89..2e107094c2d 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -183,6 +183,8 @@ namespace WorldPackets void Read() override; + std::chrono::steady_clock::time_point GetReceivedTime() const { return _worldPacket.GetReceivedTime(); } + uint32 ClientTime = 0; // Client ticks in ms uint32 SequenceIndex = 0; // Same index as in request }; diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 43fb5bbbf01..f0a7262d2e2 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -863,7 +863,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_TAXI_QUERY_AVAILABLE_NODES, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodesOpcode); DEFINE_HANDLER(CMSG_TAXI_REQUEST_EARLY_LANDING, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTaxiRequestEarlyLanding); DEFINE_HANDLER(CMSG_TIME_ADJUSTMENT_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_TIME_SYNC_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleTimeSyncResponse); + DEFINE_HANDLER(CMSG_TIME_SYNC_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTimeSyncResponse); DEFINE_HANDLER(CMSG_TIME_SYNC_RESPONSE_DROPPED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TIME_SYNC_RESPONSE_FAILED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TOGGLE_DIFFICULTY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); diff --git a/src/server/game/Server/WorldPacket.h b/src/server/game/Server/WorldPacket.h index 99e06b2b1cd..cb9565b1fd3 100644 --- a/src/server/game/Server/WorldPacket.h +++ b/src/server/game/Server/WorldPacket.h @@ -20,6 +20,7 @@ #include "ByteBuffer.h" #include "Opcodes.h" +#include <chrono> class WorldPacket : public ByteBuffer { @@ -40,7 +41,7 @@ class WorldPacket : public ByteBuffer WorldPacket(uint32 opcode, size_t res, ConnectionType connection = CONNECTION_TYPE_DEFAULT) : WorldPacket(opcode, res, Reserve{}, connection) { } - WorldPacket(WorldPacket&& packet) noexcept : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode), _connection(packet._connection) + WorldPacket(WorldPacket&& packet) noexcept : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode), _connection(packet._connection), m_receivedTime(packet.m_receivedTime) { } @@ -85,9 +86,13 @@ class WorldPacket : public ByteBuffer ConnectionType GetConnection() const { return _connection; } + std::chrono::steady_clock::time_point GetReceivedTime() const { return m_receivedTime; } + void SetReceiveTime(std::chrono::steady_clock::time_point receivedTime) { m_receivedTime = receivedTime; } + protected: uint32 m_opcode; ConnectionType _connection; + std::chrono::steady_clock::time_point m_receivedTime; // only set for a specific set of opcodes, for performance reasons. }; #endif diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 1f34512a9b6..a1416d18410 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -128,7 +128,6 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun m_sessionDbcLocale(sWorld->GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(locale), m_latency(0), - m_clientTimeDelay(0), _tutorialsChanged(TUTORIALS_FLAG_NONE), _filterAddonMessages(false), recruiterId(recruiter), @@ -137,11 +136,17 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun expireTime(60000), // 1 min after socket loss, session is deleted forceExit(false), m_currentBankerGUID(), + _timeSyncClockDeltaQueue(6), + _timeSyncClockDelta(0), + _pendingTimeSyncRequests(), _battlePetMgr(std::make_unique<BattlePetMgr>(this)), _collectionMgr(std::make_unique<CollectionMgr>(this)) { memset(_tutorials, 0, sizeof(_tutorials)); + _timeSyncNextCounter = 0; + _timeSyncTimer = 0; + if (sock) { m_Address = sock->GetRemoteIpAddress().to_string(); @@ -453,6 +458,18 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (m_Socket[CONNECTION_TYPE_REALM] && m_Socket[CONNECTION_TYPE_REALM]->IsOpen() && _warden) _warden->Update(); + if (!updater.ProcessUnsafe()) // <=> updater is of type MapSessionFilter + { + // Send time sync packet every 10s. + if (_timeSyncTimer > 0) + { + if (diff >= _timeSyncTimer) + SendTimeSync(); + else + _timeSyncTimer -= diff; + } + } + ProcessQueryCallbacks(); //check if we are safe to proceed with logout @@ -1457,3 +1474,34 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co WorldSession::DosProtection::DosProtection(WorldSession* s) : Session(s), _policy((Policy)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_POLICY)) { } + +void WorldSession::ResetTimeSync() +{ + _timeSyncNextCounter = 0; + _pendingTimeSyncRequests.clear(); +} + +void WorldSession::SendTimeSync() +{ + WorldPackets::Misc::TimeSyncRequest timeSyncRequest; + timeSyncRequest.SequenceIndex = _timeSyncNextCounter; + SendPacket(timeSyncRequest.Write()); + + _pendingTimeSyncRequests[_timeSyncNextCounter] = getMSTime(); + + // Schedule next sync in 10 sec (except for the 2 first packets, which are spaced by only 5s) + _timeSyncTimer = _timeSyncNextCounter == 0 ? 5000 : 10000; + _timeSyncNextCounter++; +} + +uint32 WorldSession::AdjustClientMovementTime(uint32 time) const +{ + int64 movementTime = int64(time) + _timeSyncClockDelta; + if (_timeSyncClockDelta == 0 || movementTime < 0 || movementTime > 0xFFFFFFFF) + { + TC_LOG_WARN("misc", "The computed movement time using clockDelta is erronous. Using fallback instead"); + return GameTime::GetGameTimeMS(); + } + else + return uint32(movementTime); +} diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index f2f4fb03159..24354eccd30 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -34,7 +34,9 @@ #include "Packet.h" #include "RaceMask.h" #include "SharedDefines.h" +#include <boost/circular_buffer.hpp> #include <array> +#include <map> #include <unordered_map> #include <unordered_set> @@ -894,8 +896,8 @@ public: explicit PacketFilter(WorldSession* pSession) : m_pSession(pSession) { } virtual ~PacketFilter() { } - virtual bool Process(WorldPacket* /*packet*/) = 0; - virtual bool ProcessUnsafe() const { return false; } + virtual bool Process(WorldPacket* /*packet*/) { return true; } + virtual bool ProcessUnsafe() const { return true; } protected: WorldSession* const m_pSession; @@ -912,7 +914,9 @@ public: explicit MapSessionFilter(WorldSession* pSession) : PacketFilter(pSession) { } ~MapSessionFilter() { } - bool Process(WorldPacket* packet) override; + virtual bool Process(WorldPacket* packet) override; + //in Map::Update() we do not process player logout! + virtual bool ProcessUnsafe() const override { return false; } }; //class used to filer only thread-unsafe packets from queue @@ -1122,7 +1126,6 @@ class TC_GAME_API WorldSession uint32 GetLatency() const { return m_latency; } void SetLatency(uint32 latency) { m_latency = latency; } - void ResetClientTimeDelay() { m_clientTimeDelay = 0; } std::atomic<time_t> m_timeOutTime; @@ -1134,6 +1137,11 @@ class TC_GAME_API WorldSession uint32 GetRecruiterId() const { return recruiterId; } bool IsARecruiter() const { return isRecruiter; } + // Time Synchronisation + void ResetTimeSync(); + void SendTimeSync(); + uint32 AdjustClientMovementTime(uint32 time) const; + // Battle Pets BattlePetMgr* GetBattlePetMgr() const { return _battlePetMgr.get(); } @@ -1587,7 +1595,7 @@ class TC_GAME_API WorldSession void HandleSetDungeonDifficultyOpcode(WorldPackets::Misc::SetDungeonDifficulty& setDungeonDifficulty); void HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDifficulty& setRaidDifficulty); void HandleSetTitleOpcode(WorldPackets::Character::SetTitle& packet); - void HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse& packet); + void HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse& timeSyncResponse); void HandleWhoIsOpcode(WorldPackets::Who::WhoIsRequest& packet); void HandleResetInstancesOpcode(WorldPackets::Instance::ResetInstances& packet); void HandleInstanceLockResponse(WorldPackets::Instance::InstanceLockResponse& packet); @@ -1900,7 +1908,6 @@ class TC_GAME_API WorldSession LocaleConstant m_sessionDbcLocale; LocaleConstant m_sessionDbLocaleIndex; std::atomic<uint32> m_latency; - std::atomic<uint32> m_clientTimeDelay; AccountData _accountData[NUM_ACCOUNT_DATA_TYPES]; uint32 _tutorials[MAX_ACCOUNT_TUTORIAL_VALUES]; uint8 _tutorialsChanged; @@ -1914,6 +1921,14 @@ class TC_GAME_API WorldSession bool forceExit; ObjectGuid m_currentBankerGUID; + boost::circular_buffer<std::pair<int64, uint32>> _timeSyncClockDeltaQueue; // first member: clockDelta. Second member: latency of the packet exchange that was used to compute that clockDelta. + int64 _timeSyncClockDelta; + void ComputeNewClockDelta(); + + std::map<uint32, uint32> _pendingTimeSyncRequests; // key: counter. value: server time when packet with that counter was sent. + uint32 _timeSyncNextCounter; + uint32 _timeSyncTimer; + std::unique_ptr<BattlePetMgr> _battlePetMgr; std::unique_ptr<CollectionMgr> _collectionMgr; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 72519fbd15f..5df8e8853cb 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -468,6 +468,9 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() /* fallthrough */ default: { + if (opcode == CMSG_TIME_SYNC_RESPONSE) + packet.SetReceiveTime(std::chrono::steady_clock::now()); + sessionGuard.lock(); LogOpcodeText(opcode, sessionGuard); @@ -1035,10 +1038,7 @@ bool WorldSocket::HandlePing(WorldPackets::Auth::Ping& ping) std::lock_guard<std::mutex> sessionGuard(_worldSessionLock); if (_worldSession) - { _worldSession->SetLatency(ping.Latency); - _worldSession->ResetClientTimeDelay(); - } else { TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s", GetRemoteIpAddress().to_string().c_str()); |