Core/Session: Fixed error "received unexpected opcode CMSG_CANCEL_TRADE" when a player is logging out.
This commit is contained in:
@@ -531,7 +531,7 @@ void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/)
|
||||
|
||||
void WorldSession::SendCancelTrade()
|
||||
{
|
||||
if (m_playerRecentlyLogout)
|
||||
if (PlayerRecentlyLoggedOut() || PlayerLogout())
|
||||
return;
|
||||
|
||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
||||
|
||||
@@ -1354,7 +1354,7 @@ enum SessionStatus
|
||||
STATUS_AUTHED = 0, // Player authenticated (_player == NULL, m_playerRecentlyLogout = false or will be reset before handler call, m_GUID have garbage)
|
||||
STATUS_LOGGEDIN, // Player in game (_player != NULL, m_GUID == _player->GetGUID(), inWorld())
|
||||
STATUS_TRANSFER, // Player transferring to another map (_player != NULL, m_GUID == _player->GetGUID(), !inWorld())
|
||||
STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, // _player!= NULL or _player == NULL && m_playerRecentlyLogout, m_GUID store last _player guid)
|
||||
STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, // _player != NULL or _player == NULL && 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
|
||||
};
|
||||
|
||||
@@ -290,7 +290,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
// 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)
|
||||
if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // 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
|
||||
@@ -404,7 +404,7 @@ void WorldSession::LogoutPlayer(bool Save)
|
||||
|
||||
if (_player)
|
||||
{
|
||||
if (uint64 lguid = GetPlayer()->GetLootGUID())
|
||||
if (uint64 lguid = _player->GetLootGUID())
|
||||
DoLootRelease(lguid);
|
||||
|
||||
///- If the player just died before logging out, make him appear as a ghost
|
||||
@@ -518,21 +518,21 @@ void WorldSession::LogoutPlayer(bool Save)
|
||||
if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket)
|
||||
_player->RemoveFromGroup();
|
||||
|
||||
///- Send update to group and reset stored max enchanting level
|
||||
//! Send update to group and reset stored max enchanting level
|
||||
if (_player->GetGroup())
|
||||
{
|
||||
_player->GetGroup()->SendUpdate();
|
||||
_player->GetGroup()->ResetMaxEnchantingLevel();
|
||||
}
|
||||
|
||||
///- Broadcast a logout message to the player's friends
|
||||
//! Broadcast a logout message to the player's friends
|
||||
sSocialMgr->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true);
|
||||
sSocialMgr->RemovePlayerSocial(_player->GetGUIDLow());
|
||||
|
||||
// Call script hook before deletion
|
||||
sScriptMgr->OnPlayerLogout(GetPlayer());
|
||||
//! Call script hook before deletion
|
||||
sScriptMgr->OnPlayerLogout(_player);
|
||||
|
||||
///- Remove the player from the world
|
||||
//! Remove the player from the world
|
||||
// the player may not be in the world when logging out
|
||||
// e.g if he got disconnected during a transfer to another map
|
||||
// calls to GetMap in this case may cause crashes
|
||||
@@ -540,22 +540,19 @@ void WorldSession::LogoutPlayer(bool Save)
|
||||
sLog->outChar("Account: %d (IP: %s) Logout Character:[%s] (GUID: %u) Level: %d", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName(), _player->GetGUIDLow(), _player->getLevel());
|
||||
if (Map* _map = _player->FindMap())
|
||||
_map->RemovePlayerFromMap(_player, true);
|
||||
SetPlayer(NULL); // deleted in Remove call
|
||||
|
||||
///- Send the 'logout complete' packet to the client
|
||||
SetPlayer(NULL); //! Pointer already deleted during RemovePlayerFromMap
|
||||
|
||||
//! Send the 'logout complete' packet to the client
|
||||
//! Client will respond by sending 3x CMSG_CANCEL_TRADE, which we currently dont handle
|
||||
WorldPacket data(SMSG_LOGOUT_COMPLETE, 0);
|
||||
SendPacket(&data);
|
||||
|
||||
///- Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline
|
||||
//No SQL injection as AccountId is uint32
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE);
|
||||
|
||||
stmt->setUInt32(0, GetAccountId());
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION: Sent SMSG_LOGOUT_COMPLETE Message");
|
||||
|
||||
//! Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE);
|
||||
stmt->setUInt32(0, GetAccountId());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
m_playerLogout = false;
|
||||
|
||||
@@ -221,6 +221,7 @@ class WorldSession
|
||||
bool PlayerLoading() const { return m_playerLoading; }
|
||||
bool PlayerLogout() const { return m_playerLogout; }
|
||||
bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; }
|
||||
bool PlayerRecentlyLoggedOut() const { return m_playerRecentlyLogout; }
|
||||
|
||||
void SizeError(WorldPacket const& packet, uint32 size) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user