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 /src/server/game/Handlers/MovementHandler.cpp | |
| parent | 2f6f1c708960bfb23a0d69ce967b67b38e72b3fa (diff) | |
Core/Movement: Add time synchronisation (#18189)
(cherry picked from commit 975f1e364a6a68be2beca261a64ea8aecc16f6f6)
Diffstat (limited to 'src/server/game/Handlers/MovementHandler.cpp')
| -rw-r--r-- | src/server/game/Handlers/MovementHandler.cpp | 88 |
1 files changed, 76 insertions, 12 deletions
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; + } +} |
