mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-18 19:35:42 +00:00
feat(Core/PacketIO): Implement STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT (#15059)
Co-authored-by: Vladimir Merzliakov <29081+VladimirMangos@users.noreply.github.com> Co-authored-by: megamage <35114+megamage@users.noreply.github.com> Co-authored-by: Shauren <shauren.trinity@gmail.com> Co-authored-by: Giacomo Pozzoni <giacomopoz@gmail.com>
This commit is contained in:
@@ -481,6 +481,10 @@ void WorldSession::HandlePlayerLogoutOpcode(WorldPackets::Character::PlayerLogou
|
||||
|
||||
void WorldSession::HandleLogoutCancelOpcode(WorldPackets::Character::LogoutCancel& /*logoutCancel*/)
|
||||
{
|
||||
// Player have already logged out serverside, too late to cancel
|
||||
if (!GetPlayer())
|
||||
return;
|
||||
|
||||
SetLogoutStartTime(0);
|
||||
|
||||
SendPacket(WorldPackets::Character::LogoutCancelAck().Write());
|
||||
|
||||
@@ -527,7 +527,7 @@ void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
|
||||
void WorldSession::SendCancelTrade()
|
||||
{
|
||||
if (PlayerLogout())
|
||||
if (PlayerRecentlyLoggedOut() || PlayerLogout())
|
||||
return;
|
||||
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
@@ -535,7 +535,9 @@ void WorldSession::SendCancelTrade()
|
||||
|
||||
void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
_player->TradeCancel(true);
|
||||
// sended also after LOGOUT COMPLETE
|
||||
if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
|
||||
_player->TradeCancel(true);
|
||||
}
|
||||
|
||||
void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
|
||||
|
||||
@@ -206,7 +206,7 @@ void OpcodeTable::Initialize()
|
||||
/*0x04B*/ DEFINE_HANDLER(CMSG_LOGOUT_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutRequestOpcode );
|
||||
/*0x04C*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_RESPONSE, STATUS_NEVER);
|
||||
/*0x04D*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_COMPLETE, STATUS_NEVER);
|
||||
/*0x04E*/ DEFINE_HANDLER(CMSG_LOGOUT_CANCEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutCancelOpcode );
|
||||
/*0x04E*/ DEFINE_HANDLER(CMSG_LOGOUT_CANCEL, STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutCancelOpcode);
|
||||
/*0x04F*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_CANCEL_ACK, STATUS_NEVER);
|
||||
/*0x050*/ DEFINE_HANDLER(CMSG_NAME_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleNameQueryOpcode );
|
||||
/*0x051*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_NAME_QUERY_RESPONSE, STATUS_NEVER);
|
||||
@@ -412,7 +412,7 @@ void OpcodeTable::Initialize()
|
||||
/*0x119*/ DEFINE_HANDLER(CMSG_IGNORE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleIgnoreTradeOpcode );
|
||||
/*0x11A*/ DEFINE_HANDLER(CMSG_ACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptTradeOpcode );
|
||||
/*0x11B*/ DEFINE_HANDLER(CMSG_UNACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode );
|
||||
/*0x11C*/ DEFINE_HANDLER(CMSG_CANCEL_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTradeOpcode );
|
||||
/*0x11C*/ DEFINE_HANDLER(CMSG_CANCEL_TRADE, STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTradeOpcode);
|
||||
/*0x11D*/ DEFINE_HANDLER(CMSG_SET_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeItemOpcode );
|
||||
/*0x11E*/ DEFINE_HANDLER(CMSG_CLEAR_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleClearTradeItemOpcode );
|
||||
/*0x11F*/ DEFINE_HANDLER(CMSG_SET_TRADE_GOLD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeGoldOpcode );
|
||||
|
||||
@@ -1353,9 +1353,10 @@ typedef Opcodes OpcodeServer;
|
||||
/// Player state
|
||||
enum SessionStatus
|
||||
{
|
||||
STATUS_AUTHED = 0, // Player authenticated (_player == nullptr, m_GUID has garbage)
|
||||
STATUS_AUTHED = 0, // Player authenticated (_player == nullptr, m_playerRecentlyLogout = false or will be reset before handler call, m_GUID have garbage)
|
||||
STATUS_LOGGEDIN, // Player in game (_player != nullptr, m_GUID == _player->GetGUID(), inWorld())
|
||||
STATUS_TRANSFER, // Player transferring to another map (_player != nullptr, m_GUID == _player->GetGUID(), !inWorld())
|
||||
STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, // _player != nullptr or _player == nullptr && m_playerRecentlyLogout && m_playerLogout, m_GUID store last _player guid)
|
||||
STATUS_NEVER, // Opcode not accepted from client (deprecated or server side only)
|
||||
STATUS_UNHANDLED, // Opcode not handled yet
|
||||
};
|
||||
|
||||
@@ -121,6 +121,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldS
|
||||
m_inQueue(false),
|
||||
m_playerLoading(false),
|
||||
m_playerLogout(false),
|
||||
m_playerRecentlyLogout(false),
|
||||
m_playerSave(false),
|
||||
m_sessionDbcLocale(sWorld->GetDefaultDbcLocale()),
|
||||
m_sessionDbLocaleIndex(locale),
|
||||
@@ -326,28 +327,48 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
case STATUS_LOGGEDIN:
|
||||
if (!_player)
|
||||
{
|
||||
// pussywizard: such packets were sent to do something for a character that has already logged out, skip them
|
||||
}
|
||||
else if (!_player->IsInWorld())
|
||||
{
|
||||
// pussywizard: such packets may do something important and the player is just being teleported, move to the end of the queue
|
||||
// pussywizard: previously such were skipped, so leave it as it is xD proper code below if we wish to change that
|
||||
|
||||
// pussywizard: requeue only important packets not related to maps (PROCESS_THREADUNSAFE)
|
||||
/*if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
|
||||
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
|
||||
//! If player didn't log out a while ago, it means packets are being sent while the server does not recognize
|
||||
//! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later.
|
||||
if (!m_playerRecentlyLogout)
|
||||
{
|
||||
if (!firstDelayedPacket)
|
||||
firstDelayedPacket = packet;
|
||||
requeuePackets.push_back(packet);
|
||||
deletePacket = false;
|
||||
QueuePacket(packet);
|
||||
}*/
|
||||
}
|
||||
else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
if (!sScriptMgr->CanPacketReceive(this, *packet))
|
||||
{
|
||||
break;
|
||||
|
||||
LOG_DEBUG("network", "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. "
|
||||
"Player {} is currently not in world yet.", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())), GetPlayerInfo());
|
||||
}
|
||||
}
|
||||
else if (_player->IsInWorld())
|
||||
{
|
||||
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
if (!sScriptMgr->CanPacketReceive(this, *packet))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
opHandle->Call(this, *packet);
|
||||
LogUnprocessedTail(packet);
|
||||
}
|
||||
else
|
||||
processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE; // break out of packet processing loop
|
||||
}
|
||||
|
||||
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
|
||||
break;
|
||||
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
|
||||
if (!_player && !m_playerRecentlyLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout
|
||||
{
|
||||
LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
|
||||
"the player has not logged in yet and not recently logout");
|
||||
}
|
||||
else if (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
// not expected _player or must checked in packet hanlder
|
||||
if (!sScriptMgr->CanPacketReceive(this, *packet))
|
||||
break;
|
||||
|
||||
opHandle->Call(this, *packet);
|
||||
LogUnprocessedTail(packet);
|
||||
@@ -373,6 +394,11 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
if (m_inQueue) // prevent cheating
|
||||
break;
|
||||
|
||||
// some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes
|
||||
// however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process.
|
||||
if (packet->GetOpcode() == CMSG_CHAR_ENUM)
|
||||
m_playerRecentlyLogout = false;
|
||||
|
||||
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
if (!sScriptMgr->CanPacketReceive(this, *packet))
|
||||
@@ -714,6 +740,7 @@ void WorldSession::LogoutPlayer(bool save)
|
||||
|
||||
m_playerLogout = false;
|
||||
m_playerSave = false;
|
||||
m_playerRecentlyLogout = true;
|
||||
SetLogoutStartTime(0);
|
||||
}
|
||||
|
||||
@@ -1261,6 +1288,8 @@ void WorldSession::SendAddonsInfo()
|
||||
void WorldSession::SetPlayer(Player* player)
|
||||
{
|
||||
_player = player;
|
||||
|
||||
// set m_GUID that can be used while player loggined and later until m_playerRecentlyLogout not reset
|
||||
if (_player)
|
||||
m_GUIDLow = _player->GetGUID().GetCounter();
|
||||
}
|
||||
|
||||
@@ -334,6 +334,7 @@ public:
|
||||
|
||||
bool PlayerLoading() const { return m_playerLoading; }
|
||||
bool PlayerLogout() const { return m_playerLogout; }
|
||||
bool PlayerRecentlyLoggedOut() const { return m_playerRecentlyLogout; }
|
||||
bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; }
|
||||
|
||||
void ReadAddonsInfo(ByteBuffer& data);
|
||||
@@ -1139,7 +1140,7 @@ private:
|
||||
// characters who failed on Player::BuildEnumData shouldn't login
|
||||
GuidSet _legitCharacters;
|
||||
|
||||
ObjectGuid::LowType m_GUIDLow;
|
||||
ObjectGuid::LowType m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set)
|
||||
Player* _player;
|
||||
std::shared_ptr<WorldSocket> m_Socket;
|
||||
std::string m_Address;
|
||||
@@ -1160,6 +1161,7 @@ private:
|
||||
bool m_inQueue; // session wait in auth.queue
|
||||
bool m_playerLoading; // code processed in LoginPlayer
|
||||
bool m_playerLogout; // code processed in LogoutPlayer
|
||||
bool m_playerRecentlyLogout;
|
||||
bool m_playerSave;
|
||||
LocaleConstant m_sessionDbcLocale;
|
||||
LocaleConstant m_sessionDbLocaleIndex;
|
||||
|
||||
Reference in New Issue
Block a user