Core/Session: Fixed error "received unexpected opcode CMSG_CANCEL_TRADE" when a player is logging out.

This commit is contained in:
kaelima
2012-05-26 18:15:07 +02:00
parent 5956eb9ae2
commit 624aab7d77
4 changed files with 19 additions and 21 deletions
+1 -1
View File
@@ -531,7 +531,7 @@ void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/)
void WorldSession::SendCancelTrade()
{
if (m_playerRecentlyLogout)
if (PlayerRecentlyLoggedOut() || PlayerLogout())
return;
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
+1 -1
View File
@@ -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
};
+16 -19
View File
@@ -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;
+1
View File
@@ -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;