mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-22 13:16:23 +00:00
feat(Core/Movement): time synchronisation to better interpret client timestamps (#5300)
This commit is contained in:
@@ -926,7 +926,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
|
||||
/*0x38D*/ { "CMSG_MOVE_CHNG_TRANSPORT", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes },
|
||||
/*0x38E*/ { "MSG_PARTY_ASSIGNMENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePartyAssignmentOpcode },
|
||||
/*0x38F*/ { "SMSG_OFFER_PETITION_ERROR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide },
|
||||
/*0x390*/ { "SMSG_TIME_SYNC_REQ", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide },
|
||||
/*0x390*/ { "SMSG_TIME_SYNC_REQ", STATUS_NEVER, PROCESS_THREADSAFE, &WorldSession::Handle_ServerSide },
|
||||
/*0x391*/ { "CMSG_TIME_SYNC_RESP", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleTimeSyncResp },
|
||||
/*0x392*/ { "CMSG_SEND_LOCAL_EVENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL },
|
||||
/*0x393*/ { "CMSG_SEND_GENERAL_TRIGGER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL },
|
||||
|
||||
@@ -110,14 +110,16 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8
|
||||
m_sessionDbcLocale(sWorld->GetDefaultDbcLocale()),
|
||||
m_sessionDbLocaleIndex(locale),
|
||||
m_latency(0),
|
||||
m_clientTimeDelay(0),
|
||||
m_TutorialsChanged(false),
|
||||
recruiterId(recruiter),
|
||||
isRecruiter(isARecruiter),
|
||||
m_currentVendorEntry(0),
|
||||
m_currentBankerGUID(0),
|
||||
timeWhoCommandAllowed(0),
|
||||
_calendarEventCreationCooldown(0)
|
||||
_calendarEventCreationCooldown(0),
|
||||
_timeSyncClockDeltaQueue(6),
|
||||
_timeSyncClockDelta(0),
|
||||
_pendingTimeSyncRequests()
|
||||
{
|
||||
memset(m_Tutorials, 0, sizeof(m_Tutorials));
|
||||
|
||||
@@ -126,6 +128,9 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8
|
||||
_kicked = false;
|
||||
_shouldSetOfflineInDB = true;
|
||||
|
||||
_timeSyncNextCounter = 0;
|
||||
_timeSyncTimer = 0;
|
||||
|
||||
if (sock)
|
||||
{
|
||||
m_Address = sock->GetRemoteAddress();
|
||||
@@ -253,7 +258,7 @@ void WorldSession::QueuePacket(WorldPacket* new_packet)
|
||||
/// Update the WorldSession (triggered by World update)
|
||||
bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
{
|
||||
if (updater.ProcessLogout())
|
||||
if (updater.ProcessUnsafe())
|
||||
{
|
||||
UpdateTimeOutTime(diff);
|
||||
|
||||
@@ -263,7 +268,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
m_Socket->CloseSocket("Client didn't send anything for too long");
|
||||
}
|
||||
|
||||
HandleTeleportTimeout(updater.ProcessLogout());
|
||||
HandleTeleportTimeout(updater.ProcessUnsafe());
|
||||
|
||||
uint32 _startMSTime = getMSTime();
|
||||
WorldPacket* packet = nullptr;
|
||||
@@ -390,7 +395,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
if (m_Socket && !m_Socket->IsClosed())
|
||||
ProcessQueryCallbacks();
|
||||
|
||||
if (updater.ProcessLogout())
|
||||
if (updater.ProcessUnsafe())
|
||||
{
|
||||
if (m_Socket && !m_Socket->IsClosed() && _warden)
|
||||
{
|
||||
@@ -415,6 +420,22 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
}
|
||||
}
|
||||
|
||||
if (!updater.ProcessUnsafe()) // <=> updater is of type MapSessionFilter
|
||||
{
|
||||
// Send time sync packet every 10s.
|
||||
if (_timeSyncTimer > 0)
|
||||
{
|
||||
if (diff >= _timeSyncTimer)
|
||||
{
|
||||
SendTimeSync();
|
||||
}
|
||||
else
|
||||
{
|
||||
_timeSyncTimer -= diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1648,3 +1669,22 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co
|
||||
|
||||
return maxPacketCounterAllowed;
|
||||
}
|
||||
|
||||
void WorldSession::ResetTimeSync()
|
||||
{
|
||||
_timeSyncNextCounter = 0;
|
||||
_pendingTimeSyncRequests.clear();
|
||||
}
|
||||
|
||||
void WorldSession::SendTimeSync()
|
||||
{
|
||||
WorldPacket data(SMSG_TIME_SYNC_REQ, 4);
|
||||
data << uint32(_timeSyncNextCounter);
|
||||
SendPacket(&data);
|
||||
|
||||
_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++;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "AuthDefines.h"
|
||||
#include "AddonMgr.h"
|
||||
#include "BanManager.h"
|
||||
#include "CircularBuffer.h"
|
||||
#include "Common.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GossipDef.h"
|
||||
@@ -23,6 +24,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <utility>
|
||||
#include <map>
|
||||
|
||||
class Creature;
|
||||
class GameObject;
|
||||
@@ -124,7 +126,7 @@ public:
|
||||
virtual ~PacketFilter() = default;
|
||||
|
||||
virtual bool Process(WorldPacket* /*packet*/) { return true; }
|
||||
[[nodiscard]] virtual bool ProcessLogout() const { return true; }
|
||||
[[nodiscard]] virtual bool ProcessUnsafe() const { return true; }
|
||||
|
||||
protected:
|
||||
WorldSession* const m_pSession;
|
||||
@@ -138,7 +140,7 @@ public:
|
||||
|
||||
bool Process(WorldPacket* packet) override;
|
||||
//in Map::Update() we do not process player logout!
|
||||
[[nodiscard]] bool ProcessLogout() const override { return false; }
|
||||
[[nodiscard]] bool ProcessUnsafe() const override { return false; }
|
||||
};
|
||||
|
||||
//class used to filer only thread-unsafe packets from queue
|
||||
@@ -357,7 +359,6 @@ public:
|
||||
|
||||
uint32 GetLatency() const { return m_latency; }
|
||||
void SetLatency(uint32 latency) { m_latency = latency; }
|
||||
void ResetClientTimeDelay() { m_clientTimeDelay = 0; }
|
||||
|
||||
std::atomic<time_t> m_timeOutTime;
|
||||
void UpdateTimeOutTime(uint32 diff)
|
||||
@@ -387,6 +388,9 @@ public:
|
||||
time_t GetCalendarEventCreationCooldown() const { return _calendarEventCreationCooldown; }
|
||||
void SetCalendarEventCreationCooldown(time_t cooldown) { _calendarEventCreationCooldown = cooldown; }
|
||||
|
||||
// Time Synchronisation
|
||||
void ResetTimeSync();
|
||||
void SendTimeSync();
|
||||
public: // opcodes handlers
|
||||
void Handle_NULL(WorldPacket& recvPacket); // not used
|
||||
void Handle_EarlyProccess(WorldPacket& recvPacket); // just mark packets processed in WorldSocket::OnRead
|
||||
@@ -1028,7 +1032,6 @@ private:
|
||||
LocaleConstant m_sessionDbcLocale;
|
||||
LocaleConstant m_sessionDbLocaleIndex;
|
||||
uint32 m_latency;
|
||||
uint32 m_clientTimeDelay;
|
||||
AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES];
|
||||
uint32 m_Tutorials[MAX_ACCOUNT_TUTORIAL_VALUES];
|
||||
bool m_TutorialsChanged;
|
||||
@@ -1044,6 +1047,14 @@ private:
|
||||
bool _shouldSetOfflineInDB;
|
||||
// Packets cooldown
|
||||
time_t _calendarEventCreationCooldown;
|
||||
|
||||
CircularBuffer<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;
|
||||
};
|
||||
#endif
|
||||
/// @}
|
||||
|
||||
@@ -669,15 +669,13 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct)
|
||||
switch (opcode)
|
||||
{
|
||||
case CMSG_PING:
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
return HandlePing(*new_pct);
|
||||
}
|
||||
catch (ByteBufferPositionException const&) {}
|
||||
LOG_ERROR("server", "WorldSocket::ReadDataHandler(): client sent malformed CMSG_PING");
|
||||
return -1;
|
||||
return HandlePing(*new_pct);
|
||||
}
|
||||
catch (ByteBufferPositionException const&) { }
|
||||
LOG_ERROR("server", "WorldSocket::ReadDataHandler(): client sent malformed CMSG_PING");
|
||||
return -1;
|
||||
case CMSG_AUTH_SESSION:
|
||||
if (m_Session)
|
||||
{
|
||||
@@ -689,27 +687,11 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct)
|
||||
if (m_Session)
|
||||
m_Session->ResetTimeOutTime(true);
|
||||
return 0;
|
||||
case CMSG_TIME_SYNC_RESP:
|
||||
new_pct = new WorldPacket(std::move(*new_pct), std::chrono::steady_clock::now());
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_SessionLock);
|
||||
|
||||
if (m_Session != nullptr)
|
||||
{
|
||||
// Our Idle timer will reset on any non PING opcodes.
|
||||
// Catches people idling on the login screen and any lingering ingame connections.
|
||||
m_Session->ResetTimeOutTime(false);
|
||||
|
||||
// OK, give the packet to WorldSession
|
||||
aptr.release();
|
||||
m_Session->QueuePacket (new_pct);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("server", "WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (ByteBufferException const&)
|
||||
@@ -724,7 +706,25 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ACE_NOTREACHED (return 0);
|
||||
std::lock_guard<std::mutex> guard(m_SessionLock);
|
||||
|
||||
if (m_Session != nullptr)
|
||||
{
|
||||
// Our Idle timer will reset on any non PING or TIME_SYNC opcodes.
|
||||
// Catches people idling on the login screen and any lingering ingame connections.
|
||||
if (opcode != CMSG_PING && opcode != CMSG_TIME_SYNC_RESP)
|
||||
{
|
||||
m_Session->ResetTimeOutTime(false);
|
||||
}
|
||||
|
||||
// OK, give the packet to WorldSession
|
||||
aptr.release();
|
||||
m_Session->QueuePacket(new_pct);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_ERROR("server", "WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
|
||||
@@ -1074,7 +1074,6 @@ int WorldSocket::HandlePing(WorldPacket& recvPacket)
|
||||
if (m_Session)
|
||||
{
|
||||
m_Session->SetLatency (latency);
|
||||
m_Session->ResetClientTimeDelay();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user