Пример #1
0
 /// <summary>
 /// 异步登出客户端
 /// </summary>
 public void LogoutAsync()
 {
     Task.Factory.StartNew(() =>
     {
         if (baseRequest != null)
         {
             try
             {
                 string result = Logout();
                 asyncOperation.Post(
                     new SendOrPostCallback((obj) =>
                 {
                     LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj));
                 }), user);
             }
             catch (Exception e)
             {
                 asyncOperation.Post(
                     new SendOrPostCallback((obj) =>
                 {
                     ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
                 }), e);
                 throw e;
             }
         }
     });
 }
Пример #2
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);
        }
Пример #3
0
 void OnLogoutComplete(bool isSuccess, string reason) =>
 LogoutComplete?.Invoke(this, new LogoutEventArgs {
     IsSuccessful = isSuccess, Reason = reason
 });
Пример #4
0
        /// <summary>
        /// 开始轮询检测是否有新消息
        /// </summary>
        private void Sync()
        {
            while (syncPolling)
            {
                try
                {
                    string syncCheckUrl    = string.Format(pushHost + "/cgi-bin/mmwebwx-bin/synccheck?r={0}&skey={1}&sid={2}&uin={3}&deviceid={4}&synckey={5}&_={6}", Utils.GetJavaTimeStamp(), baseRequest.Skey, baseRequest.Sid, baseRequest.Uin, baseRequest.DeviceID, syncKey.ToString(), syncKey.Step);
                    string syncCheckResult = httpClient.GetString(syncCheckUrl);
                    if (!syncPolling)
                    {
                        return;
                    }
                    MatchCollection matchCollection = Regex.Matches(syncCheckResult, @"\d+");
                    string          retcode         = matchCollection[0].Value;
                    string          selector        = matchCollection[1].Value;
                    Utils.Debug("retcode:" + retcode + " selector:" + selector);
                    switch (retcode)
                    {
                    case "0":
                        if (selector != "0")
                        {
                            //有新消息,拉取信息。
                            SyncRequest syncRequest = new SyncRequest();
                            syncRequest.BaseRequest = baseRequest;
                            syncRequest.SyncKey     = syncKey;
                            syncRequest.rr          = Utils.Get_r();
                            string       syncUrl      = string.Format(host + "/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&pass_ticket={2}", baseRequest.Sid, baseRequest.Skey, passTicket);
                            SyncResponse syncResponse = httpClient.PostJson <SyncResponse>(syncUrl, syncRequest);
                            if (!syncPolling)
                            {
                                return;
                            }
                            else
                            {
                                syncKey = syncResponse.SyncKey;
                                //只要不是0,就是有消息,有消息我们处理就行了,不管selector是几
                                if (syncResponse.AddMsgCount == 0 && syncResponse.DelContactCount == 0 && syncResponse.ModContactCount == 0 && syncResponse.ModChatRoomMemberCount == 0)
                                {
                                    //会有这么一种情况,selector=2,但是没有任何消息体,这样会导致持续快速的空交互
                                    //除非下次有新消息,或者主动点击手机触发消息
                                    //为了防止这种情况,做个5秒停顿。
                                    Thread.Sleep(5000);
                                }
                                else
                                {
                                    if (syncResponse.AddMsgList.Count > 0)
                                    {
                                        asyncOperation.Post(
                                            new SendOrPostCallback((obj) =>
                                        {
                                            ReceiveMsg?.Invoke(this, new TEventArgs <List <AddMsg> >((List <AddMsg>)obj));
                                        }), syncResponse.AddMsgList);
                                    }

                                    if (syncResponse.ModContactCount > 0)
                                    {
                                        asyncOperation.Post(
                                            new SendOrPostCallback((obj) =>
                                        {
                                            ModContactListComplete?.Invoke(this, new TEventArgs <List <ModContactItem> >((List <ModContactItem>)obj));
                                        }), syncResponse.ModContactList);
                                    }
                                    if (syncResponse.DelContactCount > 0)
                                    {
                                        asyncOperation.Post(
                                            new SendOrPostCallback((obj) =>
                                        {
                                            DelContactListComplete?.Invoke(this, new TEventArgs <List <DelContactItem> >((List <DelContactItem>)obj));
                                        }), syncResponse.DelContactList);
                                    }
                                    if (syncResponse.ModChatRoomMemberCount > 0)
                                    {
                                        //待分析,这个消息基本没有
                                    }
                                }
                            }
                        }
                        break;

                    case "1100":
                        //登出了微信,很可能是wx.qq.com和wx2.qq.com调用接口不一致导致的,注意登陆时候的跳转地址
                        Close();
                        asyncOperation.Post(
                            new SendOrPostCallback((obj) =>
                        {
                            LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj));
                        }), user);
                        break;

                    case "1101":
                        Close();
                        asyncOperation.Post(
                            new SendOrPostCallback((obj) =>
                        {
                            LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj));
                        }), user);
                        throw new Exception("1101可能其他地方登录/登出了 WEB 版微信,请检查手机端已登出WEB微信,然后稍后再试");
                        break;

                    case "1102":
                        Close();
                        asyncOperation.Post(
                            new SendOrPostCallback((obj) =>
                        {
                            LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj));
                        }), user);
                        throw new Exception("1102被强制登出(很可能cookie冲突),请检查手机端已登出WEB微信,然后稍后再试");
                        break;

                    default:
                        //有其他任何异常,取消轮询
                        throw new Exception("轮询结果异常,停止轮询:" + syncCheckResult);
                        break;
                    }
                    Thread.Sleep(1000);
                }
                catch (Exception ex)
                {
                    FileLog.Exception("Init", ex);
                    asyncOperation.Post(
                        new SendOrPostCallback((obj) =>
                    {
                        ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
                    }), ex);
                }
            }
        }
Пример #5
0
 internal void OnLogoutComplete(SessionEventArgs e)
 {
     LogoutComplete.RaiseEvent(this, e);
 }