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*/)
|
void WorldSession::HandleLogoutCancelOpcode(WorldPackets::Character::LogoutCancel& /*logoutCancel*/)
|
||||||
{
|
{
|
||||||
|
// Player have already logged out serverside, too late to cancel
|
||||||
|
if (!GetPlayer())
|
||||||
|
return;
|
||||||
|
|
||||||
SetLogoutStartTime(0);
|
SetLogoutStartTime(0);
|
||||||
|
|
||||||
SendPacket(WorldPackets::Character::LogoutCancelAck().Write());
|
SendPacket(WorldPackets::Character::LogoutCancelAck().Write());
|
||||||
|
|||||||
@@ -527,7 +527,7 @@ void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/)
|
|||||||
|
|
||||||
void WorldSession::SendCancelTrade()
|
void WorldSession::SendCancelTrade()
|
||||||
{
|
{
|
||||||
if (PlayerLogout())
|
if (PlayerRecentlyLoggedOut() || PlayerLogout())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||||
@@ -535,6 +535,8 @@ void WorldSession::SendCancelTrade()
|
|||||||
|
|
||||||
void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/)
|
void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||||
{
|
{
|
||||||
|
// sended also after LOGOUT COMPLETE
|
||||||
|
if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
|
||||||
_player->TradeCancel(true);
|
_player->TradeCancel(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ void OpcodeTable::Initialize()
|
|||||||
/*0x04B*/ DEFINE_HANDLER(CMSG_LOGOUT_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutRequestOpcode );
|
/*0x04B*/ DEFINE_HANDLER(CMSG_LOGOUT_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutRequestOpcode );
|
||||||
/*0x04C*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_RESPONSE, STATUS_NEVER);
|
/*0x04C*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_RESPONSE, STATUS_NEVER);
|
||||||
/*0x04D*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_COMPLETE, 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);
|
/*0x04F*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_CANCEL_ACK, STATUS_NEVER);
|
||||||
/*0x050*/ DEFINE_HANDLER(CMSG_NAME_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleNameQueryOpcode );
|
/*0x050*/ DEFINE_HANDLER(CMSG_NAME_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleNameQueryOpcode );
|
||||||
/*0x051*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_NAME_QUERY_RESPONSE, STATUS_NEVER);
|
/*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 );
|
/*0x119*/ DEFINE_HANDLER(CMSG_IGNORE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleIgnoreTradeOpcode );
|
||||||
/*0x11A*/ DEFINE_HANDLER(CMSG_ACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptTradeOpcode );
|
/*0x11A*/ DEFINE_HANDLER(CMSG_ACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptTradeOpcode );
|
||||||
/*0x11B*/ DEFINE_HANDLER(CMSG_UNACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode );
|
/*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 );
|
/*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 );
|
/*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 );
|
/*0x11F*/ DEFINE_HANDLER(CMSG_SET_TRADE_GOLD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeGoldOpcode );
|
||||||
|
|||||||
@@ -1353,9 +1353,10 @@ typedef Opcodes OpcodeServer;
|
|||||||
/// Player state
|
/// Player state
|
||||||
enum SessionStatus
|
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_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_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_NEVER, // Opcode not accepted from client (deprecated or server side only)
|
||||||
STATUS_UNHANDLED, // Opcode not handled yet
|
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_inQueue(false),
|
||||||
m_playerLoading(false),
|
m_playerLoading(false),
|
||||||
m_playerLogout(false),
|
m_playerLogout(false),
|
||||||
|
m_playerRecentlyLogout(false),
|
||||||
m_playerSave(false),
|
m_playerSave(false),
|
||||||
m_sessionDbcLocale(sWorld->GetDefaultDbcLocale()),
|
m_sessionDbcLocale(sWorld->GetDefaultDbcLocale()),
|
||||||
m_sessionDbLocaleIndex(locale),
|
m_sessionDbLocaleIndex(locale),
|
||||||
@@ -326,23 +327,22 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
|||||||
case STATUS_LOGGEDIN:
|
case STATUS_LOGGEDIN:
|
||||||
if (!_player)
|
if (!_player)
|
||||||
{
|
{
|
||||||
// pussywizard: such packets were sent to do something for a character that has already logged out, skip them
|
// 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
|
||||||
else if (!_player->IsInWorld())
|
//! 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)
|
||||||
{
|
{
|
||||||
// pussywizard: such packets may do something important and the player is just being teleported, move to the end of the queue
|
requeuePackets.push_back(packet);
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
if (!firstDelayedPacket)
|
|
||||||
firstDelayedPacket = packet;
|
|
||||||
deletePacket = false;
|
deletePacket = false;
|
||||||
QueuePacket(packet);
|
QueuePacket(packet);
|
||||||
}*/
|
|
||||||
|
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() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
}
|
||||||
|
else if (_player->IsInWorld())
|
||||||
|
{
|
||||||
|
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||||
{
|
{
|
||||||
if (!sScriptMgr->CanPacketReceive(this, *packet))
|
if (!sScriptMgr->CanPacketReceive(this, *packet))
|
||||||
{
|
{
|
||||||
@@ -354,6 +354,27 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE; // break out of packet processing loop
|
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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE; // break out of packet processing loop
|
||||||
break;
|
break;
|
||||||
case STATUS_TRANSFER:
|
case STATUS_TRANSFER:
|
||||||
if (_player && !_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
if (_player && !_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||||
@@ -373,6 +394,11 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
|||||||
if (m_inQueue) // prevent cheating
|
if (m_inQueue) // prevent cheating
|
||||||
break;
|
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 (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||||
{
|
{
|
||||||
if (!sScriptMgr->CanPacketReceive(this, *packet))
|
if (!sScriptMgr->CanPacketReceive(this, *packet))
|
||||||
@@ -714,6 +740,7 @@ void WorldSession::LogoutPlayer(bool save)
|
|||||||
|
|
||||||
m_playerLogout = false;
|
m_playerLogout = false;
|
||||||
m_playerSave = false;
|
m_playerSave = false;
|
||||||
|
m_playerRecentlyLogout = true;
|
||||||
SetLogoutStartTime(0);
|
SetLogoutStartTime(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1261,6 +1288,8 @@ void WorldSession::SendAddonsInfo()
|
|||||||
void WorldSession::SetPlayer(Player* player)
|
void WorldSession::SetPlayer(Player* player)
|
||||||
{
|
{
|
||||||
_player = player;
|
_player = player;
|
||||||
|
|
||||||
|
// set m_GUID that can be used while player loggined and later until m_playerRecentlyLogout not reset
|
||||||
if (_player)
|
if (_player)
|
||||||
m_GUIDLow = _player->GetGUID().GetCounter();
|
m_GUIDLow = _player->GetGUID().GetCounter();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,6 +334,7 @@ public:
|
|||||||
|
|
||||||
bool PlayerLoading() const { return m_playerLoading; }
|
bool PlayerLoading() const { return m_playerLoading; }
|
||||||
bool PlayerLogout() const { return m_playerLogout; }
|
bool PlayerLogout() const { return m_playerLogout; }
|
||||||
|
bool PlayerRecentlyLoggedOut() const { return m_playerRecentlyLogout; }
|
||||||
bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; }
|
bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; }
|
||||||
|
|
||||||
void ReadAddonsInfo(ByteBuffer& data);
|
void ReadAddonsInfo(ByteBuffer& data);
|
||||||
@@ -1139,7 +1140,7 @@ private:
|
|||||||
// characters who failed on Player::BuildEnumData shouldn't login
|
// characters who failed on Player::BuildEnumData shouldn't login
|
||||||
GuidSet _legitCharacters;
|
GuidSet _legitCharacters;
|
||||||
|
|
||||||
ObjectGuid::LowType m_GUIDLow;
|
ObjectGuid::LowType m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set)
|
||||||
Player* _player;
|
Player* _player;
|
||||||
std::shared_ptr<WorldSocket> m_Socket;
|
std::shared_ptr<WorldSocket> m_Socket;
|
||||||
std::string m_Address;
|
std::string m_Address;
|
||||||
@@ -1160,6 +1161,7 @@ private:
|
|||||||
bool m_inQueue; // session wait in auth.queue
|
bool m_inQueue; // session wait in auth.queue
|
||||||
bool m_playerLoading; // code processed in LoginPlayer
|
bool m_playerLoading; // code processed in LoginPlayer
|
||||||
bool m_playerLogout; // code processed in LogoutPlayer
|
bool m_playerLogout; // code processed in LogoutPlayer
|
||||||
|
bool m_playerRecentlyLogout;
|
||||||
bool m_playerSave;
|
bool m_playerSave;
|
||||||
LocaleConstant m_sessionDbcLocale;
|
LocaleConstant m_sessionDbcLocale;
|
||||||
LocaleConstant m_sessionDbLocaleIndex;
|
LocaleConstant m_sessionDbLocaleIndex;
|
||||||
|
|||||||
Reference in New Issue
Block a user