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()
|
void WorldSession::SendCancelTrade()
|
||||||
{
|
{
|
||||||
if (m_playerRecentlyLogout)
|
if (PlayerRecentlyLoggedOut() || PlayerLogout())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
|
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_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_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_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_NEVER, // Opcode not accepted from client (deprecated or server side only)
|
||||||
STATUS_UNHANDLED, // Opcode not handled yet
|
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
|
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
|
||||||
break;
|
break;
|
||||||
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
|
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",
|
LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
|
||||||
"the player has not logged in yet and not recently logout");
|
"the player has not logged in yet and not recently logout");
|
||||||
else
|
else
|
||||||
@@ -404,7 +404,7 @@ void WorldSession::LogoutPlayer(bool Save)
|
|||||||
|
|
||||||
if (_player)
|
if (_player)
|
||||||
{
|
{
|
||||||
if (uint64 lguid = GetPlayer()->GetLootGUID())
|
if (uint64 lguid = _player->GetLootGUID())
|
||||||
DoLootRelease(lguid);
|
DoLootRelease(lguid);
|
||||||
|
|
||||||
///- If the player just died before logging out, make him appear as a ghost
|
///- 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)
|
if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket)
|
||||||
_player->RemoveFromGroup();
|
_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())
|
if (_player->GetGroup())
|
||||||
{
|
{
|
||||||
_player->GetGroup()->SendUpdate();
|
_player->GetGroup()->SendUpdate();
|
||||||
_player->GetGroup()->ResetMaxEnchantingLevel();
|
_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->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true);
|
||||||
sSocialMgr->RemovePlayerSocial(_player->GetGUIDLow());
|
sSocialMgr->RemovePlayerSocial(_player->GetGUIDLow());
|
||||||
|
|
||||||
// Call script hook before deletion
|
//! Call script hook before deletion
|
||||||
sScriptMgr->OnPlayerLogout(GetPlayer());
|
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
|
// the player may not be in the world when logging out
|
||||||
// e.g if he got disconnected during a transfer to another map
|
// e.g if he got disconnected during a transfer to another map
|
||||||
// calls to GetMap in this case may cause crashes
|
// 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());
|
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())
|
if (Map* _map = _player->FindMap())
|
||||||
_map->RemovePlayerFromMap(_player, true);
|
_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);
|
WorldPacket data(SMSG_LOGOUT_COMPLETE, 0);
|
||||||
SendPacket(&data);
|
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");
|
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;
|
m_playerLogout = false;
|
||||||
|
|||||||
@@ -221,6 +221,7 @@ class WorldSession
|
|||||||
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 PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; }
|
bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; }
|
||||||
|
bool PlayerRecentlyLoggedOut() const { return m_playerRecentlyLogout; }
|
||||||
|
|
||||||
void SizeError(WorldPacket const& packet, uint32 size) const;
|
void SizeError(WorldPacket const& packet, uint32 size) const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user