aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Server')
-rw-r--r--src/server/game/Server/Packets/MiscPackets.h2
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
-rw-r--r--src/server/game/Server/WorldPacket.h7
-rw-r--r--src/server/game/Server/WorldSession.cpp50
-rw-r--r--src/server/game/Server/WorldSession.h27
-rw-r--r--src/server/game/Server/WorldSocket.cpp6
6 files changed, 82 insertions, 12 deletions
diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h
index 75119e91e89..2e107094c2d 100644
--- a/src/server/game/Server/Packets/MiscPackets.h
+++ b/src/server/game/Server/Packets/MiscPackets.h
@@ -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
};
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 43fb5bbbf01..f0a7262d2e2 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -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);
diff --git a/src/server/game/Server/WorldPacket.h b/src/server/game/Server/WorldPacket.h
index 99e06b2b1cd..cb9565b1fd3 100644
--- a/src/server/game/Server/WorldPacket.h
+++ b/src/server/game/Server/WorldPacket.h
@@ -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
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 1f34512a9b6..a1416d18410 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -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);
+}
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index f2f4fb03159..24354eccd30 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -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;
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index 72519fbd15f..5df8e8853cb 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -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());