mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Core/Movement: Add time synchronisation (#18189)
(cherry picked from commit 975f1e364a)
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user