diff options
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 10 | ||||
-rw-r--r-- | src/server/game/Handlers/MovementHandler.cpp | 44 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Server/Packets/AuthenticationPackets.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Server/Packets/AuthenticationPackets.h | 10 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 7 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 13 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 2 |
10 files changed, 75 insertions, 24 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 1f068a0ef96..d117f3739e7 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1426,9 +1426,6 @@ bool Player::TeleportTo(TeleportLocation const& teleportLocation, TeleportToOpti } SendDirectMessage(transferPending.Write()); - - RemovePlayerLocalFlag(PLAYER_LOCAL_FLAG_OVERRIDE_TRANSPORT_SERVER_TIME); - SetTransportServerTime(0); } // remove from old map now diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 9c9d751f3c1..013584e9793 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -64,6 +64,7 @@ #include "SystemPackets.h" #include "Util.h" #include "World.h" +#include <boost/circular_buffer.hpp> #include <sstream> class LoginQueryHolder : public CharacterDatabaseQueryHolder @@ -964,6 +965,9 @@ void WorldSession::HandleContinuePlayerLogin() SendPacket(WorldPackets::Auth::ResumeComms(CONNECTION_TYPE_INSTANCE).Write()); + // client will respond to SMSG_RESUME_COMMS with CMSG_QUEUED_MESSAGES_END + RegisterTimeSync(SPECIAL_RESUME_COMMS_TIME_SYNC_COUNTER); + AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& holder) { HandlePlayerLogin(static_cast<LoginQueryHolder const&>(holder)); @@ -1005,6 +1009,12 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder const& holder) return; } + if (!_timeSyncClockDeltaQueue->empty()) + { + pCurrChar->SetPlayerLocalFlag(PLAYER_LOCAL_FLAG_OVERRIDE_TRANSPORT_SERVER_TIME); + pCurrChar->SetTransportServerTime(_timeSyncClockDelta); + } + pCurrChar->SetVirtualPlayerRealm(GetVirtualRealmAddress()); SendAccountDataTimes(ObjectGuid::Empty, GLOBAL_CACHE_MASK); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 5f2ab41c856..3ec02d2ad20 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -15,6 +15,7 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "AuthenticationPackets.h" #include "WorldSession.h" #include "Battleground.h" #include "Corpse.h" @@ -783,20 +784,18 @@ void WorldSession::HandleMoveTimeSkippedOpcode(WorldPackets::Movement::MoveTimeS mover->SendMessageToSet(moveSkipTime.Write(), _player); } -void WorldSession::HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse& timeSyncResponse) +void WorldSession::HandleTimeSync(uint32 counter, int64 clientTime, TimePoint responseReceiveTime) { - if (_pendingTimeSyncRequests.count(timeSyncResponse.SequenceIndex) == 0) + auto serverTimeAtSent = _pendingTimeSyncRequests.extract(counter); + if (!serverTimeAtSent) 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; + uint32 roundTripDuration = getMSTimeDiff(serverTimeAtSent.mapped(), responseReceiveTime); + int64 lagDelay = roundTripDuration / 2; /* clockDelta = serverTime - clientTime @@ -808,11 +807,28 @@ void WorldSession::HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse& using the following relation: serverTime = clockDelta + clientTime */ - int64 clockDelta = (int64)serverTimeAtSent + (int64)lagDelay - (int64)timeSyncResponse.ClientTime; + int64 clockDelta = serverTimeAtSent.mapped() + lagDelay - clientTime; _timeSyncClockDeltaQueue->push_back(std::pair<int64, uint32>(clockDelta, roundTripDuration)); ComputeNewClockDelta(); } +void WorldSession::HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse const& timeSyncResponse) +{ + HandleTimeSync(timeSyncResponse.SequenceIndex, timeSyncResponse.ClientTime, timeSyncResponse.GetReceivedTime()); +} + +void WorldSession::HandleQueuedMessagesEnd(WorldPackets::Auth::QueuedMessagesEnd const& queuedMessagesEnd) +{ + HandleTimeSync(SPECIAL_RESUME_COMMS_TIME_SYNC_COUNTER, queuedMessagesEnd.Timestamp, queuedMessagesEnd.GetRawPacket()->GetReceivedTime()); +} + +void WorldSession::HandleMoveInitActiveMoverComplete(WorldPackets::Movement::MoveInitActiveMoverComplete const& moveInitActiveMoverComplete) +{ + HandleTimeSync(SPECIAL_INIT_ACTIVE_MOVER_TIME_SYNC_COUNTER, moveInitActiveMoverComplete.Ticks, moveInitActiveMoverComplete.GetRawPacket()->GetReceivedTime()); + + _player->UpdateObjectVisibility(false); +} + void WorldSession::ComputeNewClockDelta() { // implementation of the technique described here: https://web.archive.org/web/20180430214420/http://www.mine-control.com/zack/timesync/timesync.html @@ -846,12 +862,10 @@ void WorldSession::ComputeNewClockDelta() } else if (_timeSyncClockDelta == 0) _timeSyncClockDelta = _timeSyncClockDeltaQueue->back().first; -} -void WorldSession::HandleMoveInitActiveMoverComplete(WorldPackets::Movement::MoveInitActiveMoverComplete& moveInitActiveMoverComplete) -{ - _player->SetPlayerLocalFlag(PLAYER_LOCAL_FLAG_OVERRIDE_TRANSPORT_SERVER_TIME); - _player->SetTransportServerTime(GameTime::GetGameTimeMS() - moveInitActiveMoverComplete.Ticks); - - _player->UpdateObjectVisibility(false); + if (_player) + { + _player->SetPlayerLocalFlag(PLAYER_LOCAL_FLAG_OVERRIDE_TRANSPORT_SERVER_TIME); + _player->SetTransportServerTime(int32(_timeSyncClockDelta)); + } } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index a30111070a5..242a18ac88b 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -1853,6 +1853,9 @@ void Map::SendInitSelf(Player* player) WorldPacket packet; data.BuildPacket(&packet); player->SendDirectMessage(&packet); + + // client will respond to SMSG_UPDATE_OBJECT that contains ThisIsYou = true with CMSG_MOVE_INIT_ACTIVE_MOVER_COMPLETE + player->GetSession()->RegisterTimeSync(WorldSession::SPECIAL_INIT_ACTIVE_MOVER_TIME_SYNC_COUNTER); } void Map::SendInitTransports(Player* player) diff --git a/src/server/game/Server/Packets/AuthenticationPackets.cpp b/src/server/game/Server/Packets/AuthenticationPackets.cpp index c0bda4a873b..8854232466f 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.cpp +++ b/src/server/game/Server/Packets/AuthenticationPackets.cpp @@ -367,3 +367,8 @@ WorldPacket const* WorldPackets::Auth::EnterEncryptedMode::Write() return &_worldPacket; } + +void WorldPackets::Auth::QueuedMessagesEnd::Read() +{ + _worldPacket >> Timestamp; +} diff --git a/src/server/game/Server/Packets/AuthenticationPackets.h b/src/server/game/Server/Packets/AuthenticationPackets.h index 35007251366..bb838b972f8 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.h +++ b/src/server/game/Server/Packets/AuthenticationPackets.h @@ -310,6 +310,16 @@ namespace WorldPackets std::array<uint8, 32> const& EncryptionKey; bool Enabled = false; }; + + class QueuedMessagesEnd final : public ClientPacket + { + public: + QueuedMessagesEnd(WorldPacket&& packet) : ClientPacket(CMSG_QUEUED_MESSAGES_END, std::move(packet)) { } + + void Read() override; + + uint32 Timestamp = 0; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 7828e297085..e1a1213359f 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -652,7 +652,7 @@ void OpcodeTable::InitializeClientOpcodes() DEFINE_HANDLER(CMSG_QUEST_LOG_REMOVE_QUEST, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleQuestLogRemoveQuest); DEFINE_HANDLER(CMSG_QUEST_POI_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleQuestPOIQuery); DEFINE_HANDLER(CMSG_QUEST_PUSH_RESULT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestPushResult); - DEFINE_HANDLER(CMSG_QUEUED_MESSAGES_END, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_QUEUED_MESSAGES_END, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleQueuedMessagesEnd); DEFINE_HANDLER(CMSG_QUICK_JOIN_AUTO_ACCEPT_REQUESTS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_QUICK_JOIN_REQUEST_INVITE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_QUICK_JOIN_RESPOND_TO_INVITE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index dedb76379ed..aa44170eac5 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -1566,13 +1566,18 @@ void WorldSession::SendTimeSync() timeSyncRequest.SequenceIndex = _timeSyncNextCounter; SendPacket(timeSyncRequest.Write()); - _pendingTimeSyncRequests[_timeSyncNextCounter] = getMSTime(); + RegisterTimeSync(_timeSyncNextCounter); // Schedule next sync in 10 sec (except for the 2 first packets, which are spaced by only 5s) _timeSyncTimer = _timeSyncNextCounter == 0 ? 5000 : 10000; _timeSyncNextCounter++; } +void WorldSession::RegisterTimeSync(uint32 counter) +{ + _pendingTimeSyncRequests[counter] = getMSTime(); +} + uint32 WorldSession::AdjustClientMovementTime(uint32 time) const { int64 movementTime = int64(time) + _timeSyncClockDelta; diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 9f2815750eb..750bdb7a9cf 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -141,6 +141,7 @@ namespace WorldPackets namespace Auth { enum class ConnectToSerial : uint32; + class QueuedMessagesEnd; } namespace Bank @@ -1105,8 +1106,12 @@ class TC_GAME_API WorldSession // Time Synchronisation void ResetTimeSync(); void SendTimeSync(); + void RegisterTimeSync(uint32 counter); uint32 AdjustClientMovementTime(uint32 time) const; + static constexpr uint32 SPECIAL_INIT_ACTIVE_MOVER_TIME_SYNC_COUNTER = 0xFFFFFFFF; + static constexpr uint32 SPECIAL_RESUME_COMMS_TIME_SYNC_COUNTER = 0xFFFFFFFE; + // Packets cooldown time_t GetCalendarEventCreationCooldown() const { return _calendarEventCreationCooldown; } void SetCalendarEventCreationCooldown(time_t cooldown) { _calendarEventCreationCooldown = cooldown; } @@ -1265,7 +1270,7 @@ class TC_GAME_API WorldSession void HandleMoveSetVehicleRecAck(WorldPackets::Vehicle::MoveSetVehicleRecIdAck& setVehicleRecIdAck); void HandleMoveTimeSkippedOpcode(WorldPackets::Movement::MoveTimeSkipped& moveTimeSkipped); void HandleMovementAckMessage(WorldPackets::Movement::MovementAckMessage& movementAck); - void HandleMoveInitActiveMoverComplete(WorldPackets::Movement::MoveInitActiveMoverComplete& moveInitActiveMoverComplete); + void HandleMoveInitActiveMoverComplete(WorldPackets::Movement::MoveInitActiveMoverComplete const& moveInitActiveMoverComplete); void HandleRequestRaidInfoOpcode(WorldPackets::Party::RequestRaidInfo& packet); @@ -1544,7 +1549,9 @@ 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& timeSyncResponse); + void HandleTimeSync(uint32 counter, int64 clientTime, TimePoint responseReceiveTime); + void HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse const& timeSyncResponse); + void HandleQueuedMessagesEnd(WorldPackets::Auth::QueuedMessagesEnd const& queuedMessagesEnd); void HandleWhoIsOpcode(WorldPackets::Who::WhoIsRequest& packet); void HandleResetInstancesOpcode(WorldPackets::Instance::ResetInstances& packet); void HandleInstanceLockResponse(WorldPackets::Instance::InstanceLockResponse& packet); @@ -1847,7 +1854,7 @@ class TC_GAME_API WorldSession int64 _timeSyncClockDelta; void ComputeNewClockDelta(); - std::map<uint32, uint32> _pendingTimeSyncRequests; // key: counter. value: server time when packet with that counter was sent. + std::map<uint32, int64> _pendingTimeSyncRequests; // key: counter. value: server time when packet with that counter was sent. uint32 _timeSyncNextCounter; uint32 _timeSyncTimer; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 2b868ff3884..7f2bd595776 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -478,7 +478,7 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() [[fallthrough]]; default: { - if (opcode == CMSG_TIME_SYNC_RESPONSE) + if (opcode == CMSG_TIME_SYNC_RESPONSE || opcode == CMSG_MOVE_INIT_ACTIVE_MOVER_COMPLETE || opcode == CMSG_QUEUED_MESSAGES_END) packet.SetReceiveTime(std::chrono::steady_clock::now()); sessionGuard.lock(); |