void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recvData*/) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got MSG_MOVE_WORLDPORT_ACK."); #endif HandleMoveWorldportAckOpcode(); }
void WorldSession::HandleTeleportTimeout(bool updateInSessions) { // pussywizard: handle teleport ack timeout if (m_Socket && !m_Socket->IsClosed() && GetPlayer() && GetPlayer()->IsBeingTeleported()) { time_t currTime = time(NULL); if (updateInSessions) // session update from World::UpdateSessions { if (GetPlayer()->IsBeingTeleportedFar() && GetPlayer()->GetSemaphoreTeleportFar()+sWorld->getIntConfig(CONFIG_TELEPORT_TIMEOUT_FAR) < currTime) while (GetPlayer() && GetPlayer()->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); } else // session update from Map::Update { if (GetPlayer()->IsBeingTeleportedNear() && GetPlayer()->GetSemaphoreTeleportNear()+sWorld->getIntConfig(CONFIG_TELEPORT_TIMEOUT_NEAR) < currTime) while (GetPlayer() && GetPlayer()->IsInWorld() && GetPlayer()->IsBeingTeleportedNear()) { Player* plMover = GetPlayer()->m_mover->ToPlayer(); if (!plMover) break; WorldPacket pkt(MSG_MOVE_TELEPORT_ACK, 20); pkt.append(plMover->GetPackGUID()); pkt << uint32(0); // flags pkt << uint32(0); // time HandleMoveTeleportAck(pkt); } } } }
void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recv_data) { ObjectGuid playerGuid; recv_data >> playerGuid; Player* pCurrChar = nullptr; pCurrChar = ObjectAccessor::FindPlayer(playerGuid, false); WorldPacket data(SMSG_CHARACTER_LOGIN_FAILED, 1); if (PlayerLoading()) { sLog.outError("HandlePlayerLoginOpcode> Player try to login again while already in loading stage, AccountId = %u", GetAccountId()); data << (uint8)CHAR_LOGIN_DUPLICATE_CHARACTER; SendPacket(data, true); return; } if (_player) { // player is reconnecting if (!pCurrChar) { sLog.outError("HandlePlayerLoginOpcode> %s try to login a second char, AccountId = %u", _player->GetGuidStr().c_str(), GetAccountId()); data << (uint8)CHAR_LOGIN_DUPLICATE_CHARACTER; SendPacket(data, true); return; } if (!isLogingOut()) { sLog.outError("HandlePlayerLoginOpcode> %s try to login again, AccountId = %u", pCurrChar->GetGuidStr().c_str(), GetAccountId()); data << (uint8)CHAR_LOGIN_FAILED; SendPacket(data, true); return; } if (!_player->IsInWorld()) // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); HandlePlayerReconnect(); return; } DEBUG_LOG("WORLD: Received opcode Player Logon Message"); LoginQueryHolder* holder = new LoginQueryHolder(GetAccountId(), playerGuid); if (!holder->Initialize()) { delete holder; // delete all unprocessed queries m_playerLoading = false; return; } CharacterDatabase.DelayQueryHolder(&chrHandler, &CharacterHandler::HandlePlayerLoginCallback, holder); }
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket& recvPacket) { uint8 bit; uint32 data = 0; bit = !recvPacket.ReadBit(); if (bit) { recvPacket >> data; } sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got MSG_MOVE_WORLDPORT_ACK. %u %u %u", recvPacket.size(), bit, data); HandleMoveWorldportAckOpcode(); }
// Log the player out void WorldSession::LogoutPlayer(bool Save) { // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = Save; if (_player) { if (uint64 lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); // If the player just died before logging out, make him appear as a ghost // FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (!_player->getAttackers().empty()) { _player->CombatStop(); _player->getHostileRefManager().setOnlineOfflineState(false); _player->RemoveAllAurasOnDeath(); // build set of player who attack _player or who have pet attacking of _player std::set<Player*> aset; for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) { Unit* owner = (*itr)->GetOwner(); // including player controlled case if (owner) { if (owner->GetTypeId() == TYPEID_PLAYER) aset.insert(owner->ToPlayer()); } else if ((*itr)->GetTypeId() == TYPEID_PLAYER) aset.insert((*itr)->ToPlayer()); } _player->SetPvPDeath(!aset.empty()); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); // give honor to all attackers from set like group case for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) (*itr)->RewardHonor(_player,aset.size()); // give bg rewards and update counters like kill by first from attackers // this can't be called for all attackers. if (!aset.empty()) if (BattleGround* bg = _player->GetBattleGround()) bg->HandleKillPlayer(_player,*aset.begin()); } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT); //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } //drop a flag if player is carrying it if (BattleGround* bg = _player->GetBattleGround()) bg->EventPlayerLoggedOut(_player); // Teleport to home if the player is in an invalid instance if (!_player->m_InstanceValid && !_player->isGameMaster()) { _player->TeleportToHomebind(); //this is a bad place to call for far teleport because we need player to be in world for successful logout //maybe we should implement delayed far teleport logout? } // FG: finish pending transfers after starting the logout // this should fix players beeing able to logout and login back with full hp at death position while (_player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); sOutdoorPvPMgr.HandlePlayerLeaveZone(_player,_player->GetZoneId()); for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { if (int32 bgTypeId = _player->GetBattleGroundQueueId(i)) { _player->RemoveBattleGroundQueueId(bgTypeId); sBattleGroundMgr.m_BattleGroundQueues[ bgTypeId ].RemovePlayer(_player->GetGUID(), true); } } // If the player is in a guild, update the guild roster and broadcast a logout message to other guild members if (Guild *guild = objmgr.GetGuildById(_player->GetGuildId())) { guild->LoadPlayerStatsByGuid(_player->GetGUID()); guild->UpdateLogoutTime(_player->GetGUID()); guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetGUID(), _player->GetName()); } // Remove pet _player->RemovePet(NULL, PET_SAVE_AS_CURRENT, true); // empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (Save) { uint32 eslot; for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) { eslot = j - BUYBACK_SLOT_START; _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); } _player->SaveToDB(); } // Leave all channels before player delete... _player->CleanupChannels(); // If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) _player->RemoveFromGroup(); // Send update to group if (_player->GetGroup()) _player->GetGroup()->SendUpdate(); // Broadcast a logout message to the player's friends sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ()); // 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 _player->CleanupsBeforeDelete(); Map* _map = _player->GetMap(); _map->Remove(_player, true); _player = NULL; // deleted in Remove call // Send the 'logout complete' packet to the client 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 CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'", GetAccountId()); sLog.outDebug("SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); } //Hook for OnLogout Event sScriptMgr.OnLogout(_player); m_playerLogout = false; m_playerSave = false; m_playerRecentlyLogout = true; LogoutRequest(0); }
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recvData*/) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: got MSG_MOVE_WORLDPORT_ACK."); HandleMoveWorldportAckOpcode(); }
/// %Log the player out void WorldSession::LogoutPlayer(bool Save) { // finish pending transfers before starting the logout while(_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = Save; if (_player) { // Playerbot mod: log out all player bots owned by this toon if (GetPlayer()->GetPlayerbotMgr()) GetPlayer()->GetPlayerbotMgr()->LogoutAllBots(); sLog.outChar("Account: %d (IP: %s) Logout Character:[%s] (guid: %u)", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName() ,_player->GetGUIDLow()); if (ObjectGuid lootGuid = GetPlayer()->GetLootGuid()) DoLootRelease(lootGuid); ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (!_player->getAttackers().empty()) { _player->CombatStop(); _player->getHostileRefManager().setOnlineOfflineState(false); _player->RemoveAllAurasOnDeath(); // build set of player who attack _player or who have pet attacking of _player std::set<Player*> aset; for(Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) { Unit* owner = (*itr)->GetOwner(); // including player controlled case if(owner) { if(owner->GetTypeId()==TYPEID_PLAYER) aset.insert((Player*)owner); } else if((*itr)->GetTypeId()==TYPEID_PLAYER) aset.insert((Player*)(*itr)); } _player->SetPvPDeath(!aset.empty()); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); // give honor to all attackers from set like group case for(std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) (*itr)->RewardHonor(_player,aset.size()); // give bg rewards and update counters like kill by first from attackers // this can't be called for all attackers. if(!aset.empty()) if(BattleGround *bg = _player->GetBattleGround()) bg->HandleKillPlayer(_player,*aset.begin()); } else if(_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT); //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->HasPendingBind()) { _player->RepopAtGraveyard(); _player->SetPendingBind(NULL, 0); } //drop a flag if player is carrying it if(BattleGround *bg = _player->GetBattleGround()) bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if(!_player->m_InstanceValid && !_player->isGameMaster()) { _player->TeleportToHomebind(); //this is a bad place to call for far teleport because we need player to be in world for successful logout //maybe we should implement delayed far teleport logout? } // FG: finish pending transfers after starting the logout // this should fix players beeing able to logout and login back with full hp at death position while(_player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { if(BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i)) { _player->RemoveBattleGroundQueueId(bgQueueTypeId); sBattleGroundMgr.m_BattleGroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetObjectGuid(), true); } } ///- Reset the online field in the account table // no point resetting online in character table here as Player::SaveToDB() will set it to 1 since player has not been removed from world at this stage // No SQL injection as AccountID is uint32 if (!GetPlayer()->GetPlayerbotAI()) { static SqlStatementID id; SqlStatement stmt = LoginDatabase.CreateStatement(id, "UPDATE account SET active_realm_id = ? WHERE id = ?"); stmt.PExecute(uint32(0), GetAccountId()); } ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members if (Guild* guild = sGuildMgr.GetGuildById(_player->GetGuildId())) { if (MemberSlot* slot = guild->GetMemberSlot(_player->GetObjectGuid())) { slot->SetMemberStats(_player); slot->UpdateLogoutTime(); } guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetObjectGuid(), _player->GetName()); } ///- Remove pet _player->RemovePet(PET_SAVE_AS_CURRENT); _player->InterruptNonMeleeSpells(true); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if(Save) _player->SaveToDB(); ///- Leave all channels before player delete... _player->CleanupChannels(); // LFG cleanup sLFGMgr.Leave(_player); ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if(_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) _player->RemoveFromGroup(); ///- Send update to group if(_player->GetGroup()) _player->GetGroup()->SendUpdate(); ///- Broadcast a logout message to the player's friends sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetObjectGuid(), true); sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ()); // Playerbot - remember player GUID for update SQL below uint32 guid = GetPlayer()->GetGUIDLow(); ///- 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 if (_player->IsInWorld()) { Map* _map = _player->GetMap(); _map->Remove(_player, true); } else { _player->CleanupsBeforeDelete(); Map::DeleteFromWorld(_player); } SetPlayer(NULL); // deleted in Remove/DeleteFromWorld call ///- Send the 'logout complete' packet to the client WorldPacket data( SMSG_LOGOUT_COMPLETE, 0 ); SendPacket( &data ); static SqlStatementID updChars; // Playerbot mod: commented out above and do this one instead SqlStatement stmt = CharacterDatabase.CreateStatement(updChars, "UPDATE characters SET online = 0 WHERE guid = ?"); stmt.PExecute(guid); DEBUG_LOG( "SESSION: Sent SMSG_LOGOUT_COMPLETE Message" ); } m_playerLogout = false; m_playerSave = false; m_playerRecentlyLogout = true; LogoutRequest(0); }
/// %Log the player out void WorldSession::LogoutPlayer(bool save) { // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = save; if (_player) { if (uint64 lguid = _player->GetLootGUID()) DoLootRelease(lguid); ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->HasPendingBind()) { _player->RepopAtGraveyard(); _player->SetPendingBind(0, 0); } //drop a flag if player is carrying it if (Battleground* bg = _player->GetBattleground()) bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if (!_player->m_InstanceValid && !_player->IsGameMaster()) _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId()); for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { if (BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i)) { _player->RemoveBattlegroundQueueId(bgQueueTypeId); BattlegroundQueue& queue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); queue.RemovePlayer(_player->GetGUID(), true); } } // Repop at GraveYard or other player far teleport will prevent saving player because of not present map // Teleport player immediately for correct player save while (_player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members if (Guild* guild = sGuildMgr->GetGuildById(_player->GetGuildId())) guild->HandleMemberLogout(this); ///- Remove pet _player->RemovePet(NULL, PET_SAVE_AS_CURRENT, true); ///- Clear whisper whitelist _player->ClearWhisperWhiteList(); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (save) { uint32 eslot; for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) { eslot = j - BUYBACK_SLOT_START; _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); } _player->SaveToDB(); } ///- Leave all channels before player delete... _player->CleanupChannels(); ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) _player->RemoveFromGroup(); //! 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 sSocialMgr->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); sSocialMgr->RemovePlayerSocial(_player->GetGUIDLow()); //! Call script hook before deletion sScriptMgr->OnPlayerLogout(_player); //! 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 _player->CleanupsBeforeDelete(); TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %d (IP: %s) Logout Character:[%s] (GUID: %u) Level: %d", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName().c_str(), _player->GetGUIDLow(), _player->getLevel()); if (Map* _map = _player->FindMap()) _map->RemovePlayerFromMap(_player, true); 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); TC_LOG_DEBUG(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_playerSave = false; m_playerRecentlyLogout = true; LogoutRequest(0); }
/// %Log the player out void WorldSession::LogoutPlayer(bool save) { // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = save; if (_player) { if (uint64 lguid = _player->GetLootGUID()) DoLootRelease(lguid); ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->HasPendingBind()) { _player->RepopAtGraveyard(); _player->SetPendingBind(0, 0); } // pussywizard: leave whole bg on logout (character stays ingame when necessary) // pussywizard: GetBattleground() checked inside _player->LeaveBattleground(); // pussywizard: checked first time if (!_player->IsBeingTeleportedFar() && !_player->m_InstanceValid && !_player->IsGameMaster()) _player->RepopAtGraveyard(); sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId()); // pussywizard: remove from battleground queues on logout for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) if (BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i)) { _player->RemoveBattlegroundQueueId(bgQueueTypeId); sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(_player->GetGUID(), false, i); // track if player logs out after invited to join BG if(_player->IsInvitedForBattlegroundInstance() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS)) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK); stmt->setUInt32(0, _player->GetGUIDLow()); stmt->setUInt8(1, BG_DESERTION_TYPE_INVITE_LOGOUT); CharacterDatabase.Execute(stmt); } } ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members if (Guild* guild = sGuildMgr->GetGuildById(_player->GetGuildId())) guild->HandleMemberLogout(this); ///- Remove pet _player->RemovePet(NULL, PET_SAVE_AS_CURRENT); // pussywizard: on logout remove auras that are removed at map change (before saving to db) // there are some positive auras from boss encounters that can be kept by logging out and logging in after boss is dead, and may be used on next bosses _player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP); ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && !_player->GetGroup()->isLFGGroup() && m_Socket) _player->RemoveFromGroup(); // pussywizard: checked second time after being removed from a group if (!_player->IsBeingTeleportedFar() && !_player->m_InstanceValid && !_player->IsGameMaster()) _player->RepopAtGraveyard(); // Repop at GraveYard or other player far teleport will prevent saving player because of not present map // Teleport player immediately for correct player save while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) SavingSystemMgr::InsertToSavingSkipListIfNeeded(_player->GetNextSave()); // pussywizard if (save) { uint32 eslot; for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) { eslot = j - BUYBACK_SLOT_START; _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); } _player->SaveToDB(false, true); } ///- Leave all channels before player delete... _player->CleanupChannels(); //! 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 if (AccountMgr::IsGMAccount(GetSecurity())) // pussywizard: only for non-gms sSocialMgr->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); sSocialMgr->RemovePlayerSocial(_player->GetGUIDLow()); //! Call script hook before deletion sScriptMgr->OnPlayerLogout(_player); sLog->outChar("Account: %d (IP: %s) Logout Character:[%s] (GUID: %u) Level: %d", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName().c_str(), _player->GetGUIDLow(), _player->getLevel()); //! 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 _player->CleanupsBeforeDelete(); if (Map* _map = _player->FindMap()) { _map->RemovePlayerFromMap(_player, true); _map->AfterPlayerUnlinkFromMap(); } SetPlayer(NULL); // pointer already deleted //! 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); #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); #endif //! 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_playerSave = false; LogoutRequest(0); }
void WorldSession::HandleMoveWorldportAckOpcode( WorldPacket & /*recv_data*/ ) { DEBUG_LOG( "WORLD: got MSG_MOVE_WORLDPORT_ACK." ); HandleMoveWorldportAckOpcode(); }
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recvData*/) { TC_LOG_DEBUG("network", "WORLD: got MSG_MOVE_WORLDPORT_ACK."); HandleMoveWorldportAckOpcode(); }
/// %Log the player out void WorldSession::LogoutPlayer(bool Save) { // fix exploit with Aura Bind Sight _player->StopCastingBindSight(); _player->StopCastingCharm(); _player->RemoveAurasByType(SPELL_AURA_BIND_SIGHT); // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = Save; if (_player) { if (uint64 lguid = _player->GetLootGUID()) DoLootRelease(lguid); ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (!_player->getAttackers().empty()) { // build set of player who attack _player or who have pet attacking of _player std::set<Player*> aset; for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) { Unit* owner = (*itr)->GetOwner(); // including player controlled case if (owner && owner->GetTypeId() == TYPEID_PLAYER) aset.insert(owner->ToPlayer()); else if ((*itr)->GetTypeId() == TYPEID_PLAYER) aset.insert((Player*)(*itr)); } // CombatStop() method is removing all attackers from the AttackerSet // That is why it must be AFTER building current set of attackers _player->CombatStop(); _player->getHostileRefManager().setOnlineOfflineState(false); _player->RemoveAllAurasOnDeath(); _player->SetPvPDeath(!aset.empty()); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); // give honor to all attackers from set like group case for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) (*itr)->RewardHonor(_player, aset.size()); // give bg rewards and update counters like kill by first from attackers // this can't be called for all attackers. if (!aset.empty()) if (Battleground* bg = _player->GetBattleground()) bg->HandleKillPlayer(_player, *aset.begin()); } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->HasPendingBind()) { _player->RepopAtGraveyard(); _player->SetPendingBind(0, 0); } else if (_player->GetVehicleBase() && _player->isInCombat()) { _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->isInCombat() && sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_NORMAL && _player->IsPvP()) { _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } //drop a flag if player is carrying it if (Battleground* bg = _player->GetBattleground()) bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if (!_player->m_InstanceValid && !_player->isGameMaster()) _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId()); for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { if (BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i)) { _player->RemoveBattlegroundQueueId(bgQueueTypeId); sBattlegroundMgr->m_BattlegroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetGUID(), true); } } // Repop at GraveYard or other player far teleport will prevent saving player because of not present map // Teleport player immediately for correct player save while (_player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members if (Guild* guild = sGuildMgr->GetGuildById(_player->GetGuildId())) guild->HandleMemberLogout(this); ///- Remove pet if (_player->getClass() != CLASS_WARLOCK) { if (Pet* _pet = _player->GetPet()) _player->RemovePet(_pet, PET_SLOT_ACTUAL_PET_SLOT, true, _pet->m_Stampeded); else _player->RemovePet(NULL, PET_SLOT_ACTUAL_PET_SLOT, true, true); } else { if (Pet* _pet = _player->GetPet()) _pet->SavePetToDB(PET_SLOT_ACTUAL_PET_SLOT); } ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (Save) { uint32 eslot; for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) { eslot = j - BUYBACK_SLOT_START; _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); } _player->SaveToDB(); } ///- Leave all channels before player delete... _player->CleanupChannels(); ///- If the player is not in a group, but invited to it, remove him. If then the group has only 1 person, disband it. if (!_player->GetGroup() && _player->GetGroupInvite()) _player->UninviteFromGroup(); /// Remove player from group if he is: a) in a group; b) not in a raid group; c) logging out normally (not being kicked or disconnected). if (m_Socket && _player->GetGroup() && !_player->GetGroup()->isRaidGroup()) _player->RemoveFromGroup(); //! Send update to raid 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 sSocialMgr->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); sSocialMgr->RemovePlayerSocial(_player->GetGUIDLow()); //! Call script hook before deletion sScriptMgr->OnPlayerLogout(_player); //! 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 _player->CleanupsBeforeDelete(); sLog->outInfo(LOG_FILTER_CHARACTER, "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); //! 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, 1 + 8); ObjectGuid guid = 0; // Autolog guid - 0 for logout data.WriteBit(0); // Dafuck ? 1st bit twice read ?????? data.WriteBit(guid[7]); data.WriteBit(guid[3]); data.WriteBit(guid[1]); data.WriteBit(guid[5]); data.WriteBit(guid[0]); data.WriteBit(guid[6]); data.WriteBit(guid[4]); data.WriteBit(guid[2]); data.FlushBits(); data.WriteByteSeq(guid[0]); data.WriteByteSeq(guid[5]); data.WriteByteSeq(guid[1]); data.WriteByteSeq(guid[2]); data.WriteByteSeq(guid[6]); data.WriteByteSeq(guid[3]); data.WriteByteSeq(guid[4]); data.WriteByteSeq(guid[7]); SendPacket(&data); 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 CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'", GetAccountId()); } m_playerLogout = false; m_playerSave = false; m_playerRecentlyLogout = true; LogoutRequest(0); }
/// %Log the player out void WorldSession::LogoutPlayer(bool Save) { if (!_player) return; if (_player->IsMounted()) _player->Unmount(); // PlayerBot mod: log out all playerbots owned by this character //while(!m_playerBots.empty()) // LogoutPlayerBot(m_playerBots.begin()->first, Save); PlayerBotMap m_pBots; uint8 m_botCount = 0; for(PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); itr != GetPlayerBotsEnd(); ++itr) { Player *bot = itr->second; (m_pBots)[itr->first] = bot; ++m_botCount; } // Create a solo bind for player if player is currently in group in instance with all bots Group *m_Group = _player->GetGroup(); bool rebound = false; if(m_botCount > 0 && m_Group && m_botCount == m_Group->GetMembersCount()-1) if (InstanceSave *save = sInstanceSaveManager.GetInstanceSave(_player->GetInstanceId())) { _player->BindToInstance(save, false); save->SetCanReset(false); rebound = true; } for(PlayerBotMap::const_iterator itr2 = m_pBots.begin(); itr2 != m_pBots.end(); ++itr2) { Player *botPlayer = itr2->second; if (!botPlayer) continue; LogoutPlayerBot(botPlayer->GetGUID(), Save); } if (rebound) _player->m_InstanceValid = true; // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = Save; if (_player) { sLFGMgr.Leave(_player); GetPlayer()->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); GetPlayer()->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); GetPlayer()->GetSession()->SendLfgUpdateSearch(false); if (uint64 lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (!_player->getAttackers().empty()) { _player->CombatStop(); _player->getHostileRefManager().setOnlineOfflineState(false); _player->RemoveAllAurasOnDeath(); // build set of player who attack _player or who have pet attacking of _player std::set<Player*> aset; for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) { Unit* owner = (*itr)->GetOwner(); // including player controlled case if (owner) { if (owner->GetTypeId() == TYPEID_PLAYER) aset.insert(owner->ToPlayer()); } else if ((*itr)->GetTypeId() == TYPEID_PLAYER) aset.insert((Player*)(*itr)); } _player->SetPvPDeath(!aset.empty()); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); // give honor to all attackers from set like group case for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) (*itr)->RewardHonor(_player,aset.size()); // give bg rewards and update counters like kill by first from attackers // this can't be called for all attackers. if (!aset.empty()) if (BattleGround *bg = _player->GetBattleGround()) bg->HandleKillPlayer(_player,*aset.begin()); } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } //drop a flag if player is carrying it if (BattleGround *bg = _player->GetBattleGround()) bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if ((!_player->m_InstanceValid && !_player->isGameMaster()) || (_player->IsPlayerbot() && _player->GetMap()->IsDungeon())) _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); sOutdoorPvPMgr.HandlePlayerLeaveZone(_player,_player->GetZoneId()); for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { if (BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i)) { _player->RemoveBattleGroundQueueId(bgQueueTypeId); sBattleGroundMgr.m_BattleGroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetGUID(), true); } } // Repop at GraveYard or other player far teleport will prevent saving player because of not present map // Teleport player immediately for correct player save while (_player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members Guild *guild = objmgr.GetGuildById(_player->GetGuildId()); if (guild) { guild->SetMemberStats(_player->GetGUID()); guild->UpdateLogoutTime(_player->GetGUID()); guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetGUID(), 1, _player->GetName(), "", ""); } ///- Remove pet _player->RemovePet(NULL,PET_SAVE_AS_CURRENT, true); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (Save) { uint32 eslot; for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) { eslot = j - BUYBACK_SLOT_START; _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); } _player->SaveToDB(); } ///- Leave all channels before player delete... _player->CleanupChannels(); ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if ((_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) || (_player->IsPlayerbot() && _player->GetGroup())) _player->RemoveFromGroup(); ///- 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 sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ()); ///- 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 _player->CleanupsBeforeDelete(); sLog.outChar("Account: %d (IP: %s) Logout Character:[%s] (GUID: %u)", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName() ,_player->GetGUIDLow()); Map* _map = _player->GetMap(); uint32 guid = _player->GetGUIDLow(); _map->Remove(_player, true); SetPlayer(NULL); // deleted in Remove call ///- Send the 'logout complete' packet to the client 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 CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'", guid); sLog.outDebug("SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); } //Hook for OnLogout Event sScriptMgr.OnLogout(_player); m_playerLogout = false; m_playerSave = false; m_playerRecentlyLogout = true; LogoutRequest(0); }
/// %Log the player out void WorldSession::LogoutPlayer(bool Save) { // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = Save; if (_player) { #ifdef BUILD_PLAYERBOT // Log out all player bots owned by this toon if (_player->GetPlayerbotMgr()) _player->GetPlayerbotMgr()->LogoutAllBots(); #endif sLog.outChar("Account: %d (IP: %s) Logout Character:[%s] (guid: %u)", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName(), _player->GetGUIDLow()); if (Loot* loot = sLootMgr.GetLoot(_player)) loot->Release(_player); if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT); //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->isInCombat()) _player->CombatStop(true, true); // drop a flag if player is carrying it if (BattleGround* bg = _player->GetBattleGround()) bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if (!_player->m_InstanceValid && !_player->isGameMaster()) { _player->TeleportToHomebind(); // this is a bad place to call for far teleport because we need player to be in world for successful logout // maybe we should implement delayed far teleport logout? } // FG: finish pending transfers after starting the logout // this should fix players beeing able to logout and login back with full hp at death position while (_player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); for (int i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { if (BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i)) { _player->RemoveBattleGroundQueueId(bgQueueTypeId); sBattleGroundMgr.m_BattleGroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetObjectGuid(), true); } } ///- Reset the online field in the account table // no point resetting online in character table here as Player::SaveToDB() will set it to 1 since player has not been removed from world at this stage // No SQL injection as AccountID is uint32 static SqlStatementID id; #ifdef BUILD_PLAYERBOT if (!_player->GetPlayerbotAI()) { // Unmodded core code below SqlStatement stmt = LoginDatabase.CreateStatement(id, "UPDATE account SET active_realm_id = ? WHERE id = ?"); stmt.PExecute(uint32(0), GetAccountId()); } #else SqlStatement stmt = LoginDatabase.CreateStatement(id, "UPDATE account SET active_realm_id = ? WHERE id = ?"); stmt.PExecute(uint32(0), GetAccountId()); #endif ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members if (Guild* guild = sGuildMgr.GetGuildById(_player->GetGuildId())) { if (MemberSlot* slot = guild->GetMemberSlot(_player->GetObjectGuid())) { slot->SetMemberStats(_player); slot->UpdateLogoutTime(); } guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetObjectGuid(), _player->GetName()); } ///- Remove pet _player->RemovePet(PET_SAVE_AS_CURRENT); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (Save) _player->SaveToDB(); ///- Leave all channels before player delete... _player->CleanupChannels(); ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket && !m_Socket->IsClosed()) _player->RemoveFromGroup(); ///- Send update to group if (Group* group = _player->GetGroup()) group->UpdatePlayerOnlineStatus(_player, false); ///- Broadcast a logout message to the player's friends sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetObjectGuid(), true); sSocialMgr.RemovePlayerSocial(_player->GetGUIDLow()); #ifdef BUILD_PLAYERBOT // Remember player GUID for update SQL below uint32 guid = _player->GetGUIDLow(); #endif ///- 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 if (_player->IsInWorld()) { Map* _map = _player->GetMap(); _map->Remove(_player, true); } else { _player->CleanupsBeforeDelete(); Map::DeleteFromWorld(_player); } SetPlayer(nullptr); // deleted in Remove/DeleteFromWorld call ///- Send the 'logout complete' packet to the client WorldPacket data(SMSG_LOGOUT_COMPLETE, 0); SendPacket(data); static SqlStatementID updChars; #ifdef BUILD_PLAYERBOT // Set for only character instead of accountid // Different characters can be alive as bots SqlStatement stmt = CharacterDatabase.CreateStatement(updChars, "UPDATE characters SET online = 0 WHERE guid = ?"); stmt.PExecute(guid); #else ///- 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 stmt = CharacterDatabase.CreateStatement(updChars, "UPDATE characters SET online = 0 WHERE account = ?"); stmt.PExecute(GetAccountId()); #endif DEBUG_LOG("SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); } m_playerLogout = false; m_playerSave = false; m_playerRecentlyLogout = true; LogoutRequest(0); }
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket& recvPacket) { //sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got MSG_MOVE_WORLDPORT_ACK. %u %u %u", recvPacket.size(), bit, data); HandleMoveWorldportAckOpcode(); }
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recvData*/) { ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got MSG_MOVE_WORLDPORT_ACK."); HandleMoveWorldportAckOpcode(); }
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recv_data*/) { sLog->outDebug("WORLD: got MSG_MOVE_WORLDPORT_ACK."); HandleMoveWorldportAckOpcode(); }
void WorldSession::HandleMoveWorldportAckOpcode(WorldPackets::Movement::WorldPortResponse& /*packet*/) { HandleMoveWorldportAckOpcode(); }
/// %Log the player out void WorldSession::LogoutPlayer(bool Save) { // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = Save; if (_player) { if (uint64 lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (!_player->getAttackers().empty()) { _player->CombatStop(); _player->getHostileRefManager().setOnlineOfflineState(false); _player->RemoveAllAurasOnDeath(); // build set of player who attack _player or who have pet attacking of _player std::set<Player*> aset; for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) { Unit* owner = (*itr)->GetOwner(); // including player controlled case if (owner && owner->GetTypeId() == TYPEID_PLAYER) aset.insert(owner->ToPlayer()); else if ((*itr)->GetTypeId() == TYPEID_PLAYER) aset.insert((Player*)(*itr)); } _player->SetPvPDeath(!aset.empty()); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); // give honor to all attackers from set like group case for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) (*itr)->RewardHonor(_player, aset.size()); // give bg rewards and update counters like kill by first from attackers // this can't be called for all attackers. if (!aset.empty()) if (Battleground* bg = _player->GetBattleground()) bg->HandleKillPlayer(_player, *aset.begin()); } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->HasPendingBind()) { _player->RepopAtGraveyard(); _player->SetPendingBind(0, 0); } //drop a flag if player is carrying it if (Battleground* bg = _player->GetBattleground()) bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if (!_player->m_InstanceValid && !_player->isGameMaster()) _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId()); for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { if (BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i)) { _player->RemoveBattlegroundQueueId(bgQueueTypeId); sBattlegroundMgr->m_BattlegroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetGUID(), true); } } // Repop at GraveYard or other player far teleport will prevent saving player because of not present map // Teleport player immediately for correct player save while (_player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members if (Guild* guild = sGuildMgr->GetGuildById(_player->GetGuildId())) guild->HandleMemberLogout(this); ///- Remove pet _player->RemovePet(NULL, PET_SAVE_AS_CURRENT, true); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (Save) { uint32 eslot; for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) { eslot = j - BUYBACK_SLOT_START; _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); } _player->SaveToDB(); } ///- Leave all channels before player delete... _player->CleanupChannels(); ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) _player->RemoveFromGroup(); ///- 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 sSocialMgr->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); sSocialMgr->RemovePlayerSocial (_player->GetGUIDLow ()); // Call script hook before deletion sScriptMgr->OnPlayerLogout(GetPlayer()); ///- 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 _player->CleanupsBeforeDelete(); 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 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"); } m_playerLogout = false; m_playerSave = false; m_playerRecentlyLogout = true; LogoutRequest(0); }
/// %Log the player out void WorldSession::LogoutPlayer(bool Save) { // finish pending transfers before starting the logout while(_player && _player->IsBeingTeleported()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; if (_player) { if (uint64 lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostilRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (!_player->getAttackers().empty()) { _player->CombatStop(); _player->getHostilRefManager().setOnlineOfflineState(false); _player->RemoveAllAurasOnDeath(); // build set of player who attack _player or who have pet attacking of _player std::set<Player*> aset; for(Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) { Unit* owner = (*itr)->GetOwner(); // including player controlled case if(owner) { if(owner->GetTypeId()==TYPEID_PLAYER) aset.insert((Player*)owner); } else if((*itr)->GetTypeId()==TYPEID_PLAYER) aset.insert((Player*)(*itr)); } _player->SetPvPDeath(!aset.empty()); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); // give honor to all attackers from set like group case for(std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) (*itr)->RewardHonor(_player,aset.size()); // give bg rewards and update counters like kill by first from attackers // this can't be called for all attackers. if(!aset.empty()) if(BattleGround *bg = _player->GetBattleGround()) bg->HandleKillPlayer(_player,*aset.begin()); } else if(_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT); //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } //drop a flag if player is carrying it if(BattleGround *bg = _player->GetBattleGround()) bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if(!_player->m_InstanceValid && !_player->isGameMaster()) _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) { if(BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i)) { _player->RemoveBattleGroundQueueId(bgQueueTypeId); sBattleGroundMgr.m_BattleGroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetGUID(), true); } } ///- Reset the online field in the account table // no point resetting online in character table here as Player::SaveToDB() will set it to 1 since player has not been removed from world at this stage //No SQL injection as AccountID is uint32 loginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = '%u'", GetAccountId()); ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members Guild *guild = objmgr.GetGuildById(_player->GetGuildId()); if(guild) { guild->LoadPlayerStatsByGuid(_player->GetGUID()); guild->UpdateLogoutTime(_player->GetGUID()); WorldPacket data(SMSG_GUILD_EVENT, (1+1+12+8)); // name limited to 12 in character table. data<<(uint8)GE_SIGNED_OFF; data<<(uint8)1; data<<_player->GetName(); data<<_player->GetGUID(); guild->BroadcastPacket(&data); } ///- Remove pet _player->RemovePet(NULL,PET_SAVE_AS_CURRENT, true); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if(Save) { uint32 eslot; for(int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; j++) { eslot = j - BUYBACK_SLOT_START; _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1+eslot*2,0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1+eslot,0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1+eslot,0); } _player->SaveToDB(); } ///- Leave all channels before player delete... _player->CleanupChannels(); ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if(_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) _player->RemoveFromGroup(); ///- 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 if(_player->IsInWorld()) _player->GetMap()->Remove(_player, false); // RemoveFromWorld does cleanup that requires the player to be in the accessor ObjectAccessor::Instance().RemoveObject(_player); ///- Send update to group if(_player->GetGroup()) _player->GetGroup()->SendUpdate(); ///- Broadcast a logout message to the player's friends sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); ///- Delete the player object _player->CleanupsBeforeDelete(); // do some cleanup before deleting to prevent crash at crossreferences to already deleted data sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ()); delete _player; _player = NULL; ///- Send the 'logout complete' packet to the client 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 CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'", GetAccountId()); sLog.outDebug( "SESSION: Sent SMSG_LOGOUT_COMPLETE Message" ); } m_playerLogout = false; m_playerRecentlyLogout = true; LogoutRequest(0); }