mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-16 02:20:27 +00:00
feat(Core/Movement): time synchronisation to better interpret client timestamps (#5300)
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include "GameGraveyard.h"
|
||||
#include "InstanceSaveMgr.h"
|
||||
#include "Log.h"
|
||||
#include "MathUtil.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
@@ -419,11 +420,6 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
|
||||
if (mover->GetGUID() != _player->GetGUID())
|
||||
movementInfo.flags &= ~MOVEMENTFLAG_WALKING;
|
||||
|
||||
uint32 mstime = World::GetGameTimeMS();
|
||||
/*----------------------*/
|
||||
if(m_clientTimeDelay == 0)
|
||||
m_clientTimeDelay = mstime > movementInfo.time ? std::min(mstime - movementInfo.time, (uint32)100) : 0;
|
||||
|
||||
// Xinef: do not allow to move with UNIT_FLAG_DISABLE_MOVE
|
||||
if (mover->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
|
||||
{
|
||||
@@ -442,8 +438,16 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
|
||||
|
||||
/* process position-change */
|
||||
WorldPacket data(opcode, recvData.size());
|
||||
//movementInfo.time = movementInfo.time + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY;
|
||||
movementInfo.time = mstime; // pussywizard: set to time of relocation (server time), constant addition may smoothen movement clientside, but client sees target on different position than the real serverside position
|
||||
int64 movementTime = (int64)movementInfo.time + _timeSyncClockDelta;
|
||||
if (_timeSyncClockDelta == 0 || movementTime < 0 || movementTime > 0xFFFFFFFF)
|
||||
{
|
||||
LOG_INFO("misc", "The computed movement time using clockDelta is erronous. Using fallback instead");
|
||||
movementInfo.time = getMSTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
movementInfo.time = (uint32) movementTime;
|
||||
}
|
||||
|
||||
movementInfo.guid = mover->GetGUID();
|
||||
WriteMovementInfo(&data, &movementInfo);
|
||||
@@ -796,3 +800,76 @@ void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recvData)
|
||||
data << timeSkipped;
|
||||
GetPlayer()->SendMessageToSet(&data, false);
|
||||
}
|
||||
|
||||
void WorldSession::HandleTimeSyncResp(WorldPacket& recvData)
|
||||
{
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
LOG_DEBUG("network", "CMSG_TIME_SYNC_RESP");
|
||||
#endif
|
||||
|
||||
uint32 counter, clientTimestamp;
|
||||
recvData >> counter >> clientTimestamp;
|
||||
|
||||
if (_pendingTimeSyncRequests.count(counter) == 0)
|
||||
return;
|
||||
|
||||
uint32 serverTimeAtSent = _pendingTimeSyncRequests.at(counter);
|
||||
_pendingTimeSyncRequests.erase(counter);
|
||||
|
||||
// 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, recvData.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 + (int64)lagDelay - (int64)clientTimestamp;
|
||||
_timeSyncClockDeltaQueue.put(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.
|
||||
|
||||
std::vector<uint32> latencies;
|
||||
std::vector<int64> clockDeltasAfterFiltering;
|
||||
|
||||
for (auto pair : _timeSyncClockDeltaQueue.content())
|
||||
latencies.push_back(pair.second);
|
||||
|
||||
uint32 latencyMedian = median(latencies);
|
||||
uint32 latencyStandardDeviation = standard_deviation(latencies);
|
||||
|
||||
uint32 sampleSizeAfterFiltering = 0;
|
||||
for (auto pair : _timeSyncClockDeltaQueue.content())
|
||||
{
|
||||
if (pair.second <= latencyMedian + latencyStandardDeviation) {
|
||||
clockDeltasAfterFiltering.push_back(pair.first);
|
||||
sampleSizeAfterFiltering++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sampleSizeAfterFiltering != 0)
|
||||
{
|
||||
int64 meanClockDelta = static_cast<int64>(mean(clockDeltasAfterFiltering));
|
||||
if (std::abs(meanClockDelta - _timeSyncClockDelta) > 25)
|
||||
_timeSyncClockDelta = meanClockDelta;
|
||||
}
|
||||
else if (_timeSyncClockDelta == 0)
|
||||
{
|
||||
std::pair<int64, uint32> back = _timeSyncClockDeltaQueue.peak_back();
|
||||
_timeSyncClockDelta = back.first;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user