aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Handlers/MovementHandler.cpp
diff options
context:
space:
mode:
authorChaouki Dhib <chaodhib@gmail.com>2019-04-15 23:31:25 +0200
committerShauren <shauren.trinity@gmail.com>2021-11-30 22:11:36 +0100
commitc19a4db1c12b8864d6c486ee8e2f0e058fb4155a (patch)
tree1976d6734054eb05eb03322be9d76da9a0c1840c /src/server/game/Handlers/MovementHandler.cpp
parent2f6f1c708960bfb23a0d69ce967b67b38e72b3fa (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.cpp88
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;
+ }
+}