core: add clientless WorldSession mode

This commit is contained in:
Nico committed 2026-10-11 08:23:48 +00:00
1 parent 9b4985b5aa
commit fa8e7d07dd
2 files changed
+42 -13

No files matched your search

+29 -12
View File
@@ -108,12 +108,13 @@ bool WorldSessionFilter::Process(WorldPacket* packet)
}
/// WorldSession constructor
WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter) :
WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter, WorldSession::WorldSessionMode sessionMode) :
m_muteTime(mute_time),
m_timeOutTime(0),
AntiDOS(this),
m_GUIDLow(0),
_player(nullptr),
_sessionMode(sessionMode),
_security(sec),
_accountId(id),
_accountName(std::move(name)),
@@ -147,12 +148,18 @@ WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldS
_timeSyncNextCounter = 0;
_timeSyncTimer = 0;
if (sock)
if (IsNetworkSession() && sock)
{
m_Address = sock->GetRemoteIpAddress().to_string();
ResetTimeOutTime(false);
LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); // One-time query
}
else if (IsClientless())
{
// Clientless sessions deliberately have no remote endpoint.
// Keep a stable diagnostic value for logs that include GetRemoteAddress().
m_Address = "<clientless>";
}
m_Socket[CONNECTION_TYPE_REALM] = sock;
_instanceConnectKey.Raw = UI64LIT(0);
@@ -185,7 +192,8 @@ WorldSession::~WorldSession()
while (_recvQueue.next(packet))
delete packet;
LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId()); // One-time query
if (IsNetworkSession())
LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId()); // One-time query
}
bool WorldSession::PlayerDisconnected() const
@@ -223,6 +231,12 @@ ObjectGuid::LowType WorldSession::GetGUIDLow() const
/// Send a packet to the client
void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/)
{
// A clientless session intentionally has no packet transport. Outbound
// packets are a normal side effect of Player/Core code and are discarded
// without producing "non existent socket" errors.
if (IsClientless())
return;
if (packet->GetOpcode() == NULL_OPCODE)
{
TC_LOG_ERROR("network.opcode", "Prevented sending of NULL_OPCODE to %s", GetPlayerInfo().c_str());
@@ -340,13 +354,16 @@ void WorldSession::LogUnprocessedTail(WorldPacket const* packet)
/// Update the WorldSession (triggered by World update)
bool WorldSession::Update(uint32 diff, PacketFilter& updater)
{
/// Update Timeout timer.
UpdateTimeOutTime(diff);
if (IsNetworkSession())
{
/// Update Timeout timer.
UpdateTimeOutTime(diff);
///- Before we process anything:
/// If necessary, kick the player from the character select screen
if (IsConnectionIdle() && !HasPermission(rbac::RBAC_PERM_IGNORE_IDLE_CONNECTION))
m_Socket[CONNECTION_TYPE_REALM]->CloseSocket();
///- Before we process anything:
/// If necessary, kick the player from the character select screen
if (IsConnectionIdle() && !HasPermission(rbac::RBAC_PERM_IGNORE_IDLE_CONNECTION) && m_Socket[CONNECTION_TYPE_REALM])
m_Socket[CONNECTION_TYPE_REALM]->CloseSocket();
}
///- Retrieve packets from the receive queue and call the appropriate handlers
/// not process packets if socket already closed
@@ -478,7 +495,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
if (m_Socket[0] && m_Socket[0]->IsOpen() && _warden)
_warden->Update();
if (!updater.ProcessUnsafe()) // <=> updater is of type MapSessionFilter
if (IsNetworkSession() && !updater.ProcessUnsafe()) // <=> updater is of type MapSessionFilter
{
// Send time sync packet every 5s.
if (_timeSyncTimer > 0)
@@ -523,8 +540,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
}
}
if (!m_Socket[CONNECTION_TYPE_REALM])
return false; //Will remove this session from the world session map
if (IsNetworkSession() && !m_Socket[CONNECTION_TYPE_REALM])
return false; // Will remove this network session from the world session map
}
return true;
+13 -1
View File
@@ -475,7 +475,14 @@ struct PacketCounter
class TC_GAME_API WorldSession
{
public:
WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter);
enum class WorldSessionMode : uint8
{
Network,
Clientless
};
WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter,
WorldSessionMode sessionMode = WorldSessionMode::Network);
~WorldSession();
bool PlayerLoading() const { return !m_playerLoading.IsEmpty(); }
@@ -513,6 +520,10 @@ class TC_GAME_API WorldSession
AccountTypes GetSecurity() const { return _security; }
uint32 GetAccountId() const { return _accountId; }
WorldSessionMode GetSessionMode() const { return _sessionMode; }
bool IsNetworkSession() const { return _sessionMode == WorldSessionMode::Network; }
bool IsClientless() const { return _sessionMode == WorldSessionMode::Clientless; }
bool HasNetworkTransport() const { return m_Socket[CONNECTION_TYPE_REALM] != nullptr; }
Player* GetPlayer() const { return _player; }
std::string const& GetPlayerName() const;
std::string GetPlayerInfo() const;
@@ -1353,6 +1364,7 @@ class TC_GAME_API WorldSession
ObjectGuid::LowType m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set)
Player* _player;
WorldSessionMode _sessionMode;
std::shared_ptr<WorldSocket> m_Socket[2];
std::string m_Address; // Current Remote Address
// std::string m_LAddress; // Last Attempted Remote Adress - we can not set attempted ip for a non-existing session!