Esempio n. 1
0
        public void LogoutPlayer(bool save)
        {
            // finish pending transfers before starting the logout
            while (_player && _player.IsBeingTeleportedFar())
            {
                HandleMoveWorldportAck();
            }

            m_playerLogout = true;
            m_playerSave   = save;

            if (_player)
            {
                if (!_player.GetLootGUID().IsEmpty())
                {
                    DoLootReleaseAll();
                }

                // 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 (GetPlayer().GetDeathTimer() != 0)
                {
                    _player.getHostileRefManager().deleteReferences();
                    _player.BuildPlayerRepop();
                    _player.RepopAtGraveyard();
                }
                else if (GetPlayer().HasAuraType(AuraType.SpiritOfRedemption))
                {
                    // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION
                    _player.RemoveAurasByType(AuraType.ModShapeshift);
                    _player.KillPlayer();
                    _player.BuildPlayerRepop();
                    _player.RepopAtGraveyard();
                }
                else if (GetPlayer().HasPendingBind())
                {
                    _player.RepopAtGraveyard();
                    _player.SetPendingBind(0, 0);
                }

                //drop a flag if player is carrying it
                Battleground bg = GetPlayer().GetBattleground();
                if (bg)
                {
                    bg.EventPlayerLoggedOut(GetPlayer());
                }

                // Teleport to home if the player is in an invalid instance
                if (!_player.m_InstanceValid && !_player.IsGameMaster())
                {
                    _player.TeleportTo(_player.GetHomebind());
                }

                Global.OutdoorPvPMgr.HandlePlayerLeaveZone(_player, _player.GetZoneId());

                for (uint i = 0; i < SharedConst.MaxPlayerBGQueues; ++i)
                {
                    BattlegroundQueueTypeId bgQueueTypeId = GetPlayer().GetBattlegroundQueueTypeId(i);
                    if (bgQueueTypeId != 0)
                    {
                        _player.RemoveBattlegroundQueueId(bgQueueTypeId);
                        BattlegroundQueue queue = Global.BattlegroundMgr.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())
                {
                    HandleMoveWorldportAck();
                }

                // If the player is in a guild, update the guild roster and broadcast a logout message to other guild members
                Guild guild = Global.GuildMgr.GetGuildById(_player.GetGuildId());
                if (guild)
                {
                    guild.HandleMemberLogout(this);
                }

                // Remove pet
                _player.RemovePet(null, PetSaveMode.AsCurrent, 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)
                {
                    for (int j = InventorySlots.BuyBackStart; j < InventorySlots.BuyBackEnd; ++j)
                    {
                        int eslot = j - InventorySlots.BuyBackStart;
                        _player.SetGuidValue(PlayerFields.InvSlotHead + (j * 4), ObjectGuid.Empty);
                        _player.SetUInt32Value(PlayerFields.BuyBackPrice1 + eslot, 0);
                        _player.SetUInt32Value(PlayerFields.BuyBackTimestamp1 + 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[(int)ConnectionType.Realm] != null)
                {
                    _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
                Global.SocialMgr.SendFriendStatus(_player, FriendsResult.Offline, _player.GetGUID(), true);
                _player.RemoveSocial();

                //! Call script hook before deletion
                Global.ScriptMgr.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
                GetPlayer().CleanupsBeforeDelete();
                Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Logout Character:[{2}] (GUID: {3}) Level: {4}",
                            GetAccountId(), GetRemoteAddress(), _player.GetName(), _player.GetGUID().ToString(), _player.getLevel());

                Map map = GetPlayer().GetMap();
                if (map != null)
                {
                    map.RemovePlayerFromMap(GetPlayer(), true);
                }

                SetPlayer(null);

                //! Send the 'logout complete' packet to the client
                //! Client will respond by sending 3x CMSG_CANCEL_TRADE, which we currently dont handle
                LogoutComplete logoutComplete = new LogoutComplete();
                SendPacket(logoutComplete);

                //! 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 = DB.Characters.GetPreparedStatement(CharStatements.UPD_ACCOUNT_ONLINE);
                stmt.AddValue(0, GetAccountId());
                DB.Characters.Execute(stmt);
            }

            if (m_Socket[(int)ConnectionType.Instance] != null)
            {
                m_Socket[(int)ConnectionType.Instance].CloseSocket();
                m_Socket[(int)ConnectionType.Instance] = null;
            }

            m_playerLogout         = false;
            m_playerSave           = false;
            m_playerRecentlyLogout = true;
            SetLogoutStartTime(0);
        }
        void HandleBattleFieldPort(BattlefieldPort battlefieldPort)
        {
            if (!GetPlayer().InBattlegroundQueue())
            {
                Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Player not in queue!",
                             GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
                return;
            }

            BattlegroundQueueTypeId bgQueueTypeId = GetPlayer().GetBattlegroundQueueTypeId(battlefieldPort.Ticket.Id);

            if (bgQueueTypeId == BattlegroundQueueTypeId.None)
            {
                Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Invalid queueSlot!",
                             GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
                return;
            }

            BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);

            //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue.RemovePlayer() function
            GroupQueueInfo ginfo;

            if (!bgQueue.GetPlayerGroupInfoData(GetPlayer().GetGUID(), out ginfo))
            {
                Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Player not in queue (No player Group Info)!",
                             GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
                return;
            }
            // if action == 1, then instanceId is required
            if (ginfo.IsInvitedToBGInstanceGUID == 0 && battlefieldPort.AcceptedInvite)
            {
                Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Player is not invited to any bg!",
                             GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
                return;
            }

            BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.BGTemplateId(bgQueueTypeId);
            // BGTemplateId returns Battleground_AA when it is arena queue.
            // Do instance id search as there is no AA bg instances.
            Battleground bg = Global.BattlegroundMgr.GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId == BattlegroundTypeId.AA ? BattlegroundTypeId.None : bgTypeId);

            if (!bg)
            {
                if (battlefieldPort.AcceptedInvite)
                {
                    Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Cant find BG with id {5}!",
                                 GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite, ginfo.IsInvitedToBGInstanceGUID);
                    return;
                }

                bg = Global.BattlegroundMgr.GetBattlegroundTemplate(bgTypeId);
                if (!bg)
                {
                    Log.outError(LogFilter.Network, "BattlegroundHandler: bg_template not found for type id {0}.", bgTypeId);
                    return;
                }
            }

            // get real bg type
            bgTypeId = bg.GetTypeID();

            // expected bracket entry
            PVPDifficultyRecord bracketEntry = Global.DB2Mgr.GetBattlegroundBracketByLevel(bg.GetMapId(), GetPlayer().getLevel());

            if (bracketEntry == null)
            {
                return;
            }

            //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
            if (battlefieldPort.AcceptedInvite && ginfo.ArenaType == 0)
            {
                //if player is trying to enter Battleground(not arena!) and he has deserter debuff, we must just remove him from queue
                if (!GetPlayer().CanJoinToBattleground(bg))
                {
                    // send bg command result to show nice message
                    BattlefieldStatusFailed battlefieldStatus;
                    Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatus, bg, GetPlayer(), battlefieldPort.Ticket.Id, 0, GroupJoinBattlegroundResult.Deserters);
                    SendPacket(battlefieldStatus);
                    battlefieldPort.AcceptedInvite = false;
                    Log.outDebug(LogFilter.Battleground, "Player {0} ({1}) has a deserter debuff, do not port him to Battleground!", GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
                }
                //if player don't match Battlegroundmax level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue
                if (GetPlayer().getLevel() > bg.GetMaxLevel())
                {
                    Log.outDebug(LogFilter.Network, "Player {0} ({1}) has level ({2}) higher than maxlevel ({3}) of Battleground({4})! Do not port him to Battleground!",
                                 GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), GetPlayer().getLevel(), bg.GetMaxLevel(), bg.GetTypeID());
                    battlefieldPort.AcceptedInvite = false;
                }
            }

            if (battlefieldPort.AcceptedInvite)
            {
                // check Freeze debuff
                if (GetPlayer().HasAura(9454))
                {
                    return;
                }

                if (!GetPlayer().IsInvitedForBattlegroundQueueType(bgQueueTypeId))
                {
                    return;                                 // cheating?
                }
                if (!GetPlayer().InBattleground())
                {
                    GetPlayer().SetBattlegroundEntryPoint();
                }

                // resurrect the player
                if (!GetPlayer().IsAlive())
                {
                    GetPlayer().ResurrectPlayer(1.0f);
                    GetPlayer().SpawnCorpseBones();
                }
                // stop taxi flight at port
                if (GetPlayer().IsInFlight())
                {
                    GetPlayer().GetMotionMaster().MovementExpired();
                    GetPlayer().CleanupAfterTaxiFlight();
                }

                BattlefieldStatusActive battlefieldStatus;
                Global.BattlegroundMgr.BuildBattlegroundStatusActive(out battlefieldStatus, bg, GetPlayer(), battlefieldPort.Ticket.Id, GetPlayer().GetBattlegroundQueueJoinTime(bgQueueTypeId), bg.GetArenaType());
                SendPacket(battlefieldStatus);

                // remove BattlegroundQueue status from BGmgr
                bgQueue.RemovePlayer(GetPlayer().GetGUID(), false);
                // this is still needed here if Battleground"jumping" shouldn't add deserter debuff
                // also this is required to prevent stuck at old Battlegroundafter SetBattlegroundId set to new
                Battleground currentBg = GetPlayer().GetBattleground();
                if (currentBg)
                {
                    currentBg.RemovePlayerAtLeave(GetPlayer().GetGUID(), false, true);
                }

                // set the destination instance id
                GetPlayer().SetBattlegroundId(bg.GetInstanceID(), bgTypeId);
                // set the destination team
                GetPlayer().SetBGTeam(ginfo.Team);

                Global.BattlegroundMgr.SendToBattleground(GetPlayer(), ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
                Log.outDebug(LogFilter.Battleground, "Battleground: player {0} ({1}) joined battle for bg {2}, bgtype {3}, queue type {4}.", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), bg.GetInstanceID(), bg.GetTypeID(), bgQueueTypeId);
            }
            else // leave queue
            {
                // if player leaves rated arena match before match start, it is counted as he played but he lost
                if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID != 0)
                {
                    ArenaTeam at = Global.ArenaTeamMgr.GetArenaTeamById((uint)ginfo.Team);
                    if (at != null)
                    {
                        Log.outDebug(LogFilter.Battleground, "UPDATING memberLost's personal arena rating for {0} by opponents rating: {1}, because he has left queue!", GetPlayer().GetGUID().ToString(), ginfo.OpponentsTeamRating);
                        at.MemberLost(GetPlayer(), ginfo.OpponentsMatchmakerRating);
                        at.SaveToDB();
                    }
                }
                BattlefieldStatusNone battlefieldStatus = new BattlefieldStatusNone();
                battlefieldStatus.Ticket = battlefieldPort.Ticket;
                SendPacket(battlefieldStatus);

                GetPlayer().RemoveBattlegroundQueueId(bgQueueTypeId);  // must be called this way, because if you move this call to queue.removeplayer, it causes bugs
                bgQueue.RemovePlayer(GetPlayer().GetGUID(), true);
                // player left queue, we should update it - do not update Arena Queue
                if (ginfo.ArenaType == 0)
                {
                    Global.BattlegroundMgr.ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry.GetBracketId());
                }

                Log.outDebug(LogFilter.Battleground, "Battleground: player {0} ({1}) left queue for bgtype {2}, queue type {3}.", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), bg.GetTypeID(), bgQueueTypeId);
            }
        }