少年修仙传客户端代码仓库
client_linchunjie
2018-08-27 d106f11e7f44c748f595da36e0cdfd54849649e6
System/Chat/ChatCenter.cs
@@ -1,721 +1,721 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using TableConfig;
using UnityEngine;
namespace Snxxz.UI
{
    public class ChatCenter : Model, IBeforePlayerDataInitialize, IPlayerLoginOk, ISwitchAccount
    {
        public override void Init()
        {
            ParseConfig();
            //var _uiframe = UIFrameMgr.Inst;
            SpeechTranslate.Instance.translateResultEvent += TranslateResultEvent;
            VoiceWarehouse.voiceRecoderEvent += VoiceRecoderEvent;
            SDKUtility.Instance.onNetStatusChanged += OnNetStatusChanged;
            ChatSetting.Instance.RefreshChatSetAct += RefreshChatSetAct;
            WindowCenter.Instance.windowAfterCloseEvent += WindowAfterCloseEvent;
            var httpRequest = VoiceHttpRequest.Instance;
            TimeMgr.Instance.OnSyntonyEvent += OnSyntonyEvent;
            VoiceHttpRequest.Instance.samplesDecodecComplete += SamplesDecodecComplete;
            WindowCenter.Instance.windowAfterOpenEvent += WindowAfterOpenEvent;
            StageManager.Instance.onStageLoadFinish += OnStageLoadFinish;
        }
        public override void UnInit()
        {
        }
        bool serverInited = false;
        public int chatCharacterLimit { get; private set; }
        public int bugleItem { get; private set; }
        public List<ChatInfoType> chatChannels { get; private set; }
        public int chatInputLength { get; set; }
        public StringBuilder m_EncodeBuilder = new StringBuilder();
        void ParseConfig()
        {
            chatCharacterLimit = int.Parse(ConfigManager.Instance.GetTemplate<FuncConfigConfig>("MessageLength").Numerical1);
            var _funcCfg = ConfigManager.Instance.GetTemplate<FuncConfigConfig>("BugleItem");
            bugleItem = int.Parse(_funcCfg.Numerical1);
            chatChannels = new List<ChatInfoType>();
            for (int i = (int)ChatInfoType.System; i <= (int)ChatInfoType.Friend; i++)
            {
                chatChannels.Add((ChatInfoType)i);
            }
        }
        public event Action<string, bool, bool> UpdateChatValueEvent;
        public void ChangeChatValue(string _msg, bool _add, bool _force)
        {
            if (UpdateChatValueEvent != null)
            {
                UpdateChatValueEvent(_msg, _add, _force);
            }
        }
        public event Action UpdateChatType;
        public void ChangeChatType()
        {
            if (UpdateChatType != null)
            {
                UpdateChatType();
            }
        }
        public event Action UpdateChatContent;
        public void UpdateChatContentPos()
        {
            if (UpdateChatContent != null)
            {
                UpdateChatContent();
            }
        }
        public ChatData GetChatData(ChatInfoType _type, int _index, int _pteChatId = 0)
        {
            ChatData chat = null;
            if (_type == ChatInfoType.Friend)
            {
                var _list = ChatCtrl.Inst.GetChatInfo(_pteChatId == 0 ? ChatCtrl.Inst.PteChatID : _pteChatId);
                if (_list == null || _index >= _list.Count)
                {
                    return null;
                }
                chat = _list[_index];
            }
            else
            {
                List<ChatData> _list = ChatCtrl.Inst.GetChatInfo(_type);
                if (_list == null || _index >= _list.Count)
                {
                    return null;
                }
                chat = _list[_index];
            }
            return chat;
        }
        public const int RecentlyChatNum = 8;
        public List<RecentlyChat> recentlyChats = new List<RecentlyChat>(RecentlyChatNum);
        public event Action RecentlyChatChangeEvent;
        public RecentlyChat recentlyChat = null;
        public RecentlyChat SaveRecentlyChat(string _chat)
        {
            if (ChatCtrl.Inst.IsInviteChat(_chat)
                || Regex.IsMatch(_chat, ChatCtrl.KILL_IDENTIFY))
            {
                return null;
            }
            if (s_VoiceRegex.IsMatch(_chat))
            {
                _chat = s_VoiceRegex.Replace(_chat, string.Empty);
            }
            if (recentlyChats.FindIndex((x) =>
             {
                 return x.display.Equals(_chat);
             }) != -1)
            {
                return null;
            }
            if (recentlyChats.Count >= RecentlyChatNum)
            {
                var _old = recentlyChats[0];
                recentlyChats.RemoveAt(0);
                _old = null;
            }
            var _recentlyChat = new RecentlyChat(_chat);
            recentlyChats.Add(_recentlyChat);
            if (RecentlyChatChangeEvent != null)
            {
                RecentlyChatChangeEvent();
            }
            return _recentlyChat;
        }
        public void OnBeforePlayerDataInitialize()
        {
            recentlyChat = null;
            serverInited = false;
            m_VoiceChatDict.Clear();
            autoPlayVoices.Clear();
            voicePlaying = false;
            netState = 0;
        }
        public void OnSwitchAccount()
        {
            ClearAllVoice();
        }
        private void OnStageLoadFinish()
        {
            bool isDungeon = StageManager.Instance.CurrentStage is DungeonStage;
            if (!isDungeon)
            {
                ClearAllVoice();
            }
        }
        void ClearAllVoice()
        {
            speechDict.Clear();
            requestSpeechTime.Clear();
        }
        public class RecentlyChat
        {
            public string display = string.Empty;
            public List<string> itemInfos = new List<string>();
            public List<int> itemIndexs = new List<int>();
            public List<string> itemNames = new List<string>();
            public RecentlyChat(string _chat)
            {
                display = _chat;
            }
            public void Add(string _name, string _itemInfo)
            {
                itemNames.Add(_name);
                itemInfos.Add(_itemInfo);
            }
            public void Reset()
            {
                itemIndexs.Clear();
                for (int i = 0; i < itemInfos.Count; i++)
                {
                    itemIndexs.Add(i);
                }
            }
        }
        #region 语音聊天
        public static readonly Regex s_VoiceRegex = new Regex("<v=([0-9]+)_([0-9]+)>");
        private Dictionary<int, VoiceChat> m_VoiceChatDict = new Dictionary<int, VoiceChat>();
        public class VoiceChat
        {
            public ChatInfoType chatType;
            public int index;
            public int toPlayer;
            public long tick;
            public byte length;
            public bool translate = false;
            public byte[] encode;
            public string result = string.Empty;
        }
        public void SetVoice(int _instance, ChatInfoType _type, float _length, int _toPlayer = 0)
        {
            if (!m_VoiceChatDict.ContainsKey(_instance))
            {
                VoiceChat _chat = new VoiceChat()
                {
                    chatType = _type,
                    index = _instance,
                    toPlayer = _toPlayer,
                    tick = TimeUtility.ServerNow.Ticks,
                    translate = false,
                    encode = null,
                    length = (byte)Mathf.Min((int)(_length * 10), 100),
                };
                m_VoiceChatDict.Add(_instance, _chat);
            }
        }
        private void VoiceRecoderEvent(int _instance)
        {
            VoiceChat _chat;
            byte[] _encode;
            if (m_VoiceChatDict.TryGetValue(_instance, out _chat)
                && VoiceWarehouse.TryGetVoice(_instance, out _encode))
            {
                if (_chat.translate)
                {
                    m_VoiceChatDict.Remove(_instance);
                    SendSpeech(_encode, _chat.tick);
                }
                else
                {
                    _chat.encode = _encode;
                }
            }
        }
        private void TranslateResultEvent(int _instance, bool isOk, string _result)
        {
            VoiceChat _chat;
            if (m_VoiceChatDict.TryGetValue(_instance, out _chat))
            {
                if (!isOk)
                {
                    _result = string.Empty;
                }
                if (DirtyWordConfig.IsDirtWord(_result))
                {
                    _result = DirtyWordConfig.IsDirtWord(_result, '*');
                }
                if (_chat.chatType != ChatInfoType.World && _chat.chatType != ChatInfoType.Area
                    && _chat.chatType != ChatInfoType.Fairy && _chat.chatType != ChatInfoType.Friend
                    && _chat.chatType != ChatInfoType.Team)
                {
                    m_VoiceChatDict.Remove(_instance);
                    return;
                }
                _chat.translate = true;
                _chat.result = _result;
                _result = StringUtility.Contact("<v=", _chat.tick, "_", _chat.length, ">", _chat.result);
                if (_chat.chatType == ChatInfoType.Friend)
                {
                    if (_chat.toPlayer != 0)
                    {
                        ChatExtraData _info = ChatExtraData.Default;
                        _info.infoint1 = _chat.toPlayer;
                        ChatCtrl.Inst.SendChatInfo(_chat.chatType, _result, _info);
                    }
                }
                else
                {
                    ChatCtrl.Inst.SendChatInfo(_chat.chatType, _result);
                }
                if (null != _chat.encode)
                {
                    SendSpeech(_chat.encode, _chat.tick);
                    m_VoiceChatDict.Remove(_instance);
                }
            }
        }
        const string downloadUrl = "http://{0}.voice.secondworld.net.cn:53001/voice/download";
        private void SendSpeech(byte[] encode, long _tick)
        {
            VoiceHttpRequest.Instance.Enqueue(encode, _tick, (int)PlayerDatas.Instance.PlayerId);
        }
        public void DownloadSpeech(int _playerId, long _tick)
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();
            dict.Add("voiceID", _tick.ToString());
            dict.Add("playerID", _playerId.ToString());
            dict.Add("appid", string.Empty);
            dict.Add("content", string.Empty);
            HttpRequest.Instance.RequestHttpPost(string.Format(downloadUrl, VersionConfig.Get().appId), dict, HttpRequest.defaultHttpContentType, 3, (bool isOk, string _result) =>
               {
                   if (isOk)
                  {
                      try
                      {
                          var speech = LitJson.JsonMapper.ToObject<HttpSpeech>(_result);
                          var tick = long.Parse(speech.voiceID);
                          var _player = int.Parse(speech.playerID);
                          if (string.IsNullOrEmpty(speech.content))
                          {
                              if ((TimeUtility.ServerNow - TimeUtility.ClientOriginalTime.AddTicks(_tick)).TotalMinutes < 2)//可能是语音未上传成功
                              {
                                  AutoPlayVoice();
                              }
                              else
                              {
                                  if (autoPlayVoices.Count > 0
                                     && autoPlayVoices[0].playerId == _player
                                     && autoPlayVoices[0].tick == tick)
                                  {
                                      RemoveAutoVoice(autoPlayVoices[0].playerId, autoPlayVoices[0].tick);
                                      AutoPlayVoice();
                                  }
                                  else
                                  {
                                      SysNotifyMgr.Instance.ShowTip("VoiceOutTime");
                                  }
                              }
                              return;
                          }
                          var bytes = Convert.FromBase64String(speech.content);
                          SaveSpeech(_player, tick, bytes);
                          if (autoPlayVoices.Count > 0
                          && autoPlayVoices[0].playerId == _player
                          && autoPlayVoices[0].tick == tick)
                          {
                              AutoPlayVoice();
                          }
                      }
                      catch (Exception e)
                      {
                          DesignDebug.LogError(e.Message);
                      }
                  }
              });
        }
        private bool CheckRequestTimeLimit(int _playerId, long _tick)
        {
            AudioClip _clip = null;
            if (TryGetSpeech(_playerId, _tick, out _clip))
            {
                return false;
            }
            Dictionary<long, DateTime> dict = null;
            if (!requestSpeechTime.TryGetValue(_playerId, out dict))
            {
                dict = new Dictionary<long, DateTime>();
                requestSpeechTime.Add(_playerId, dict);
            }
            if (dict.ContainsKey(_tick) &&
                (DateTime.Now - dict[_tick]).TotalSeconds < 3.0f)
            {
                return true;
            }
            dict[_tick] = DateTime.Now;
            return false;
        }
        private Dictionary<int, Dictionary<long, DateTime>> requestSpeechTime = new Dictionary<int, Dictionary<long, DateTime>>();
        Dictionary<int, Dictionary<long, AudioClip>> speechDict = new Dictionary<int, Dictionary<long, AudioClip>>();
        public event Action<int, long> speechDownloadSuccess;
        private void SaveSpeech(int _playerId, long _tick, byte[] encode)
        {
            VoiceCodec.Decode(encode, (float[] samples) =>
             {
                 VoiceHttpRequest.Instance.Enqueue(samples, _tick, _playerId);
             });
        }
        private void SamplesDecodecComplete(VoiceHttpRequest.VoiceDecodec _decodec)
        {
            Dictionary<long, AudioClip> dict = null;
            if (!speechDict.TryGetValue(_decodec.playerId, out dict))
            {
                dict = new Dictionary<long, AudioClip>();
                speechDict.Add(_decodec.playerId, dict);
            }
            var clip = AudioClip.Create("Sound", _decodec.samples.Length, 1, VoiceSettings.frequency, false);
            clip.SetData(_decodec.samples, 0);
            dict.Add(_decodec.tick, clip);
            if (_decodec.playerId == cachePlayerId && cacheTick == _decodec.tick)
            {
                PlaySpeech(clip, cacheLength);
            }
            if (speechDownloadSuccess != null)
            {
                speechDownloadSuccess(_decodec.playerId, _decodec.tick);
            }
        }
        public bool TryGetSpeech(int _playerId, long _tick, out AudioClip _clip)
        {
            Dictionary<long, AudioClip> _dict = null;
            if (speechDict.TryGetValue(_playerId, out _dict))
            {
                if (_dict.ContainsKey(_tick))
                {
                    _clip = _dict[_tick];
                    return true;
                }
            }
            _clip = null;
            return false;
        }
        private int cachePlayerId = 0;
        private long cacheTick = 0;
        private float cacheLength = 0;
        public void PlaySpeech(int _playerId, long _tick, float _length)
        {
            if (CheckRequestTimeLimit(_playerId, _tick))
            {
                return;
            }
            AudioClip _clip = null;
            if (TryGetSpeech(_playerId, _tick, out _clip))
            {
                PlaySpeech(_clip, _length);
                cachePlayerId = 0;
                cacheTick = 0;
                cacheLength = 0;
            }
            else
            {
                cachePlayerId = _playerId;
                cacheTick = _tick;
                cacheLength = _length;
                DownloadSpeech(_playerId, _tick);
            }
        }
        public void PlaySpeech(AudioClip _clip, float _length)
        {
            SoundPlayer.Instance.mute = true;
            _length = Mathf.Max(1.0f, _length);
            voicePlaying = true;
            TimeMgr.Instance.Register(TimeMgr.SyntonyType.Audio, _length);
            SoundPlayer.Instance.PlayAudio(_clip);
        }
        private void OnSyntonyEvent(TimeMgr.SyntonyType _type)
        {
            if (_type == TimeMgr.SyntonyType.Audio)
            {
                SoundPlayer.Instance.mute = false;
                voicePlaying = false;
                AutoPlayVoice();
            }
        }
        public struct HttpSpeech
        {
            public string voiceID;
            public string playerID;
            public string content;
        }
        byte GetPakChannelType(ChatInfoType _type)
        {
            switch (_type)
            {
                case ChatInfoType.World:
                    return 1;
                case ChatInfoType.Area:
                    return 5;
                case ChatInfoType.Team:
                    return 4;
                case ChatInfoType.Fairy:
                    return 2;
                case ChatInfoType.Friend:
                    return 3;
            }
            return 1;
        }
        ChatInfoType GetPakChannelType(byte _type)
        {
            switch (_type)
            {
                case 5:
                    return ChatInfoType.Area;
                case 1:
                    return ChatInfoType.World;
                case 2:
                    return ChatInfoType.Fairy;
                case 3:
                    return ChatInfoType.Friend;
                case 4:
                    return ChatInfoType.Team;
            }
            return ChatInfoType.World;
        }
        int netState = 0;
        private void OnNetStatusChanged(int _state)
        {
            netState = _state;
            if (netState != 1 && netState != 4)
            {
                autoPlayVoices.Clear();
            }
        }
        public bool voicePlaying { get; private set; }
        public List<VoiceInfo> autoPlayVoices = new List<VoiceInfo>();
        public void CheckAutoPlayVoice(ChatData _chat)
        {
            var _netState = netState;
#if UNITY_EDITOR
            _netState = 1;
#endif
            if (!serverInited)
            {
                return;
            }
            if (SystemSetting.Instance.GetSoundVolume() <= 0.01f)
            {
                return;
            }
            var _speechChat = _chat as ChatUeseData;
            if (null == _speechChat || !_speechChat.IsSound)
            {
                return;
            }
            if (_speechChat.player == PlayerDatas.Instance.PlayerId)
            {
                return;
            }
            if (!ChatSetting.Instance.GetAutoPlayVoice(_chat.type, _netState))
            {
                return;
            }
            if (autoPlayVoices.FindIndex((x) =>
             {
                 return x.playerId == _speechChat.player && x.tick == _speechChat.soundTick;
             }) != -1)
            {
                return;
            }
            SnxxzGame.Instance.StartCoroutine(Co_AutoPlay(new VoiceInfo()
            {
                playerId = _speechChat.player,
                tick = _speechChat.soundTick,
                type = _speechChat.type,
                length = _speechChat.soundLength,
            }));
        }
        private void WindowAfterCloseEvent(Window _win)
        {
            if (_win is LoadingWin)
            {
                AutoPlayVoice();
            }
            CheckChatFloatOpen();
        }
        IEnumerator Co_AutoPlay(VoiceInfo _info)
        {
            yield return WaitingForSecondConst.WaitMS500;
            if (serverInited)
            {
                autoPlayVoices.Add(_info);
                AutoPlayVoice();
            }
        }
        private void AutoPlayVoice()
        {
            if (voicePlaying || WindowCenter.Instance.CheckOpen<LoadingWin>()
                || !(StageManager.Instance.CurrentStage is DungeonStage))
            {
                return;
            }
            if (autoPlayVoices.Count > 0)
            {
                var _speech = autoPlayVoices[0];
                AudioClip _clip;
                if (TryGetSpeech(_speech.playerId, _speech.tick, out _clip))
                {
                    PlaySpeech(_clip, _speech.length);
                    autoPlayVoices.RemoveAt(0);
                }
                else
                {
                    DownloadSpeech(_speech.playerId, _speech.tick);
                }
            }
        }
        private void RefreshChatSetAct(ChatBoolType _type, bool _open)
        {
            switch (_type)
            {
                case ChatBoolType.GradVoice4G:
                case ChatBoolType.GradVoiceWifi:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Fairy, 1)
                        && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Fairy, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.Fairy);
                    }
                    break;
                case ChatBoolType.PrivatChatVoice4G:
                case ChatBoolType.PrivateChatVoiceWifi:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Friend, 1)
                        && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Friend, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.Friend);
                    }
                    break;
                case ChatBoolType.TeamVoice4G:
                case ChatBoolType.TeamVoiceWifi:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Team, 1)
                       && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Team, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.Team);
                    }
                    break;
                case ChatBoolType.WorldVoice4G:
                case ChatBoolType.WorldVoiceWifi:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.World, 1)
                       && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.World, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.World);
                    }
                    break;
                case ChatBoolType.AreaVoiceWifi:
                case ChatBoolType.AreaVoice4G:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Area, 1)
                       && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Area, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.Area);
                    }
                    break;
            }
        }
        private void RemoveAutoVoice(int _playerId,long _tick)
        {
            autoPlayVoices.RemoveAll((x) =>
            {
                return x.playerId == _playerId && x.tick == _tick;
            });
        }
        private void RemoveAutoVoice(ChatInfoType _type)
        {
            autoPlayVoices.RemoveAll((x) =>
            {
                return x.type == _type;
            });
        }
        public struct VoiceInfo
        {
            public int playerId;
            public long tick;
            public float length;
            public ChatInfoType type;
        }
#endregion
        public void OnPlayerLoginOk()
        {
            serverInited = true;
        }
        #region 聊天浮动
        private void WindowAfterOpenEvent(Window win)
        {
            CheckChatFloatOpen();
        }
        private void CheckChatFloatOpen()
        {
            if (WindowCenter.Instance.ExitAnyFullScreenOrMaskWin() && !WindowCenter.Instance.CheckOpen<LoadingWin>()
                && StageManager.Instance.CurrentStage is DungeonStage && !WindowCenter.Instance.CheckOpen<TreasureLevelUpWin>())
            {
                if (!WindowCenter.Instance.CheckOpen<ChatFloatWin>())
                {
                    WindowCenter.Instance.Open<ChatFloatWin>();
                }
            }
            else
            {
                if (WindowCenter.Instance.CheckOpen<ChatFloatWin>())
                {
                    WindowCenter.Instance.CloseImmediately<ChatFloatWin>();
                }
            }
        }
        #endregion
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using TableConfig;
using UnityEngine;
namespace Snxxz.UI
{
    public class ChatCenter : Model, IBeforePlayerDataInitialize, IPlayerLoginOk, ISwitchAccount
    {
        public override void Init()
        {
            ParseConfig();
            //var _uiframe = UIFrameMgr.Inst;
            SpeechTranslate.Instance.translateResultEvent += TranslateResultEvent;
            VoiceWarehouse.voiceRecoderEvent += VoiceRecoderEvent;
            SDKUtility.Instance.OnNetworkStatusChanged += OnNetStatusChanged;
            ChatSetting.Instance.RefreshChatSetAct += RefreshChatSetAct;
            WindowCenter.Instance.windowAfterCloseEvent += WindowAfterCloseEvent;
            var httpRequest = VoiceHttpRequest.Instance;
            TimeMgr.Instance.OnSyntonyEvent += OnSyntonyEvent;
            VoiceHttpRequest.Instance.samplesDecodecComplete += SamplesDecodecComplete;
            WindowCenter.Instance.windowAfterOpenEvent += WindowAfterOpenEvent;
            StageManager.Instance.onStageLoadFinish += OnStageLoadFinish;
        }
        public override void UnInit()
        {
        }
        bool serverInited = false;
        public int chatCharacterLimit { get; private set; }
        public int bugleItem { get; private set; }
        public List<ChatInfoType> chatChannels { get; private set; }
        public int chatInputLength { get; set; }
        public StringBuilder m_EncodeBuilder = new StringBuilder();
        void ParseConfig()
        {
            chatCharacterLimit = int.Parse(Config.Instance.Get<FuncConfigConfig>("MessageLength").Numerical1);
            var _funcCfg = Config.Instance.Get<FuncConfigConfig>("BugleItem");
            bugleItem = int.Parse(_funcCfg.Numerical1);
            chatChannels = new List<ChatInfoType>();
            for (int i = (int)ChatInfoType.System; i <= (int)ChatInfoType.Friend; i++)
            {
                chatChannels.Add((ChatInfoType)i);
            }
        }
        public event Action<string, bool, bool> UpdateChatValueEvent;
        public void ChangeChatValue(string _msg, bool _add, bool _force)
        {
            if (UpdateChatValueEvent != null)
            {
                UpdateChatValueEvent(_msg, _add, _force);
            }
        }
        public event Action UpdateChatType;
        public void ChangeChatType()
        {
            if (UpdateChatType != null)
            {
                UpdateChatType();
            }
        }
        public event Action UpdateChatContent;
        public void UpdateChatContentPos()
        {
            if (UpdateChatContent != null)
            {
                UpdateChatContent();
            }
        }
        public ChatData GetChatData(ChatInfoType _type, int _index, int _pteChatId = 0)
        {
            ChatData chat = null;
            if (_type == ChatInfoType.Friend)
            {
                var _list = ChatCtrl.Inst.GetChatInfo(_pteChatId == 0 ? ChatCtrl.Inst.PteChatID : _pteChatId);
                if (_list == null || _index >= _list.Count)
                {
                    return null;
                }
                chat = _list[_index];
            }
            else
            {
                List<ChatData> _list = ChatCtrl.Inst.GetChatInfo(_type);
                if (_list == null || _index >= _list.Count)
                {
                    return null;
                }
                chat = _list[_index];
            }
            return chat;
        }
        public const int RecentlyChatNum = 8;
        public List<RecentlyChat> recentlyChats = new List<RecentlyChat>(RecentlyChatNum);
        public event Action RecentlyChatChangeEvent;
        public RecentlyChat recentlyChat = null;
        public RecentlyChat SaveRecentlyChat(string _chat)
        {
            if (ChatCtrl.Inst.IsInviteChat(_chat)
                || Regex.IsMatch(_chat, ChatCtrl.KILL_IDENTIFY))
            {
                return null;
            }
            if (s_VoiceRegex.IsMatch(_chat))
            {
                _chat = s_VoiceRegex.Replace(_chat, string.Empty);
            }
            if (recentlyChats.FindIndex((x) =>
             {
                 return x.display.Equals(_chat);
             }) != -1)
            {
                return null;
            }
            if (recentlyChats.Count >= RecentlyChatNum)
            {
                var _old = recentlyChats[0];
                recentlyChats.RemoveAt(0);
                _old = null;
            }
            var _recentlyChat = new RecentlyChat(_chat);
            recentlyChats.Add(_recentlyChat);
            if (RecentlyChatChangeEvent != null)
            {
                RecentlyChatChangeEvent();
            }
            return _recentlyChat;
        }
        public void OnBeforePlayerDataInitialize()
        {
            recentlyChat = null;
            serverInited = false;
            m_VoiceChatDict.Clear();
            autoPlayVoices.Clear();
            voicePlaying = false;
            netState = 0;
        }
        public void OnSwitchAccount()
        {
            ClearAllVoice();
        }
        private void OnStageLoadFinish()
        {
            bool isDungeon = StageManager.Instance.CurrentStage is DungeonStage;
            if (!isDungeon)
            {
                ClearAllVoice();
            }
        }
        void ClearAllVoice()
        {
            speechDict.Clear();
            requestSpeechTime.Clear();
        }
        public class RecentlyChat
        {
            public string display = string.Empty;
            public List<string> itemInfos = new List<string>();
            public List<int> itemIndexs = new List<int>();
            public List<string> itemNames = new List<string>();
            public RecentlyChat(string _chat)
            {
                display = _chat;
            }
            public void Add(string _name, string _itemInfo)
            {
                itemNames.Add(_name);
                itemInfos.Add(_itemInfo);
            }
            public void Reset()
            {
                itemIndexs.Clear();
                for (int i = 0; i < itemInfos.Count; i++)
                {
                    itemIndexs.Add(i);
                }
            }
        }
        #region 语音聊天
        public static readonly Regex s_VoiceRegex = new Regex("<v=([0-9]+)_([0-9]+)>");
        private Dictionary<int, VoiceChat> m_VoiceChatDict = new Dictionary<int, VoiceChat>();
        public class VoiceChat
        {
            public ChatInfoType chatType;
            public int index;
            public int toPlayer;
            public long tick;
            public byte length;
            public bool translate = false;
            public byte[] encode;
            public string result = string.Empty;
        }
        public void SetVoice(int _instance, ChatInfoType _type, float _length, int _toPlayer = 0)
        {
            if (!m_VoiceChatDict.ContainsKey(_instance))
            {
                VoiceChat _chat = new VoiceChat()
                {
                    chatType = _type,
                    index = _instance,
                    toPlayer = _toPlayer,
                    tick = TimeUtility.ServerNow.Ticks,
                    translate = false,
                    encode = null,
                    length = (byte)Mathf.Min((int)(_length * 10), 100),
                };
                m_VoiceChatDict.Add(_instance, _chat);
            }
        }
        private void VoiceRecoderEvent(int _instance)
        {
            VoiceChat _chat;
            byte[] _encode;
            if (m_VoiceChatDict.TryGetValue(_instance, out _chat)
                && VoiceWarehouse.TryGetVoice(_instance, out _encode))
            {
                if (_chat.translate)
                {
                    m_VoiceChatDict.Remove(_instance);
                    SendSpeech(_encode, _chat.tick);
                }
                else
                {
                    _chat.encode = _encode;
                }
            }
        }
        private void TranslateResultEvent(int _instance, bool isOk, string _result)
        {
            VoiceChat _chat;
            if (m_VoiceChatDict.TryGetValue(_instance, out _chat))
            {
                if (!isOk)
                {
                    _result = string.Empty;
                }
                if (DirtyWordConfig.IsDirtWord(_result))
                {
                    _result = DirtyWordConfig.IsDirtWord(_result, '*');
                }
                if (_chat.chatType != ChatInfoType.World && _chat.chatType != ChatInfoType.Area
                    && _chat.chatType != ChatInfoType.Fairy && _chat.chatType != ChatInfoType.Friend
                    && _chat.chatType != ChatInfoType.Team)
                {
                    m_VoiceChatDict.Remove(_instance);
                    return;
                }
                _chat.translate = true;
                _chat.result = _result;
                _result = StringUtility.Contact("<v=", _chat.tick, "_", _chat.length, ">", _chat.result);
                if (_chat.chatType == ChatInfoType.Friend)
                {
                    if (_chat.toPlayer != 0)
                    {
                        ChatExtraData _info = ChatExtraData.Default;
                        _info.infoint1 = _chat.toPlayer;
                        ChatCtrl.Inst.SendChatInfo(_chat.chatType, _result, _info);
                    }
                }
                else
                {
                    ChatCtrl.Inst.SendChatInfo(_chat.chatType, _result);
                }
                if (null != _chat.encode)
                {
                    SendSpeech(_chat.encode, _chat.tick);
                    m_VoiceChatDict.Remove(_instance);
                }
            }
        }
        const string downloadUrl = "http://{0}.voice.2460web.com:53001/voice/download";
        private void SendSpeech(byte[] encode, long _tick)
        {
            VoiceHttpRequest.Instance.Enqueue(encode, _tick, (int)PlayerDatas.Instance.PlayerId);
        }
        public void DownloadSpeech(int _playerId, long _tick)
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();
            dict.Add("voiceID", _tick.ToString());
            dict.Add("playerID", _playerId.ToString());
            dict.Add("appid", string.Empty);
            dict.Add("content", string.Empty);
            HttpRequest.Instance.RequestHttpPost(string.Format(downloadUrl, VersionConfig.Get().appId), dict, HttpRequest.defaultHttpContentType, 3, (bool isOk, string _result) =>
               {
                   if (isOk)
                   {
                       try
                       {
                           var speech = LitJson.JsonMapper.ToObject<HttpSpeech>(_result);
                           var tick = long.Parse(speech.voiceID);
                           var _player = int.Parse(speech.playerID);
                           if (string.IsNullOrEmpty(speech.content))
                           {
                               if ((TimeUtility.ServerNow - TimeUtility.ClientOriginalTime.AddTicks(_tick)).TotalMinutes < 2)//可能是语音未上传成功
                               {
                                   AutoPlayVoice();
                               }
                               else
                               {
                                   if (autoPlayVoices.Count > 0
                                      && autoPlayVoices[0].playerId == _player
                                      && autoPlayVoices[0].tick == tick)
                                   {
                                       RemoveAutoVoice(autoPlayVoices[0].playerId, autoPlayVoices[0].tick);
                                       AutoPlayVoice();
                                   }
                                   else
                                   {
                                       SysNotifyMgr.Instance.ShowTip("VoiceOutTime");
                                   }
                               }
                               return;
                           }
                           var bytes = Convert.FromBase64String(speech.content);
                           SaveSpeech(_player, tick, bytes);
                           if (autoPlayVoices.Count > 0
                           && autoPlayVoices[0].playerId == _player
                           && autoPlayVoices[0].tick == tick)
                           {
                               AutoPlayVoice();
                           }
                       }
                       catch (Exception e)
                       {
                           DebugEx.LogError(e.Message);
                       }
                   }
               });
        }
        private bool CheckRequestTimeLimit(int _playerId, long _tick)
        {
            AudioClip _clip = null;
            if (TryGetSpeech(_playerId, _tick, out _clip))
            {
                return false;
            }
            Dictionary<long, DateTime> dict = null;
            if (!requestSpeechTime.TryGetValue(_playerId, out dict))
            {
                dict = new Dictionary<long, DateTime>();
                requestSpeechTime.Add(_playerId, dict);
            }
            if (dict.ContainsKey(_tick) &&
                (DateTime.Now - dict[_tick]).TotalSeconds < 3.0f)
            {
                return true;
            }
            dict[_tick] = DateTime.Now;
            return false;
        }
        private Dictionary<int, Dictionary<long, DateTime>> requestSpeechTime = new Dictionary<int, Dictionary<long, DateTime>>();
        Dictionary<int, Dictionary<long, AudioClip>> speechDict = new Dictionary<int, Dictionary<long, AudioClip>>();
        public event Action<int, long> speechDownloadSuccess;
        private void SaveSpeech(int _playerId, long _tick, byte[] encode)
        {
            VoiceCodec.Decode(encode, (float[] samples) =>
             {
                 VoiceHttpRequest.Instance.Enqueue(samples, _tick, _playerId);
             });
        }
        private void SamplesDecodecComplete(VoiceHttpRequest.VoiceDecodec _decodec)
        {
            Dictionary<long, AudioClip> dict = null;
            if (!speechDict.TryGetValue(_decodec.playerId, out dict))
            {
                dict = new Dictionary<long, AudioClip>();
                speechDict.Add(_decodec.playerId, dict);
            }
            var clip = AudioClip.Create("Sound", _decodec.samples.Length, 1, VoiceSettings.frequency, false);
            clip.SetData(_decodec.samples, 0);
            dict.Add(_decodec.tick, clip);
            if (_decodec.playerId == cachePlayerId && cacheTick == _decodec.tick)
            {
                PlaySpeech(clip, cacheLength);
            }
            if (speechDownloadSuccess != null)
            {
                speechDownloadSuccess(_decodec.playerId, _decodec.tick);
            }
        }
        public bool TryGetSpeech(int _playerId, long _tick, out AudioClip _clip)
        {
            Dictionary<long, AudioClip> _dict = null;
            if (speechDict.TryGetValue(_playerId, out _dict))
            {
                if (_dict.ContainsKey(_tick))
                {
                    _clip = _dict[_tick];
                    return true;
                }
            }
            _clip = null;
            return false;
        }
        private int cachePlayerId = 0;
        private long cacheTick = 0;
        private float cacheLength = 0;
        public void PlaySpeech(int _playerId, long _tick, float _length)
        {
            if (CheckRequestTimeLimit(_playerId, _tick))
            {
                return;
            }
            AudioClip _clip = null;
            if (TryGetSpeech(_playerId, _tick, out _clip))
            {
                PlaySpeech(_clip, _length);
                cachePlayerId = 0;
                cacheTick = 0;
                cacheLength = 0;
            }
            else
            {
                cachePlayerId = _playerId;
                cacheTick = _tick;
                cacheLength = _length;
                DownloadSpeech(_playerId, _tick);
            }
        }
        public void PlaySpeech(AudioClip _clip, float _length)
        {
            SoundPlayer.Instance.mute = true;
            _length = Mathf.Max(1.0f, _length);
            voicePlaying = true;
            TimeMgr.Instance.Register(TimeMgr.SyntonyType.Audio, _length);
            SoundPlayer.Instance.PlayAudio(_clip);
        }
        private void OnSyntonyEvent(TimeMgr.SyntonyType _type)
        {
            if (_type == TimeMgr.SyntonyType.Audio)
            {
                SoundPlayer.Instance.mute = false;
                voicePlaying = false;
                AutoPlayVoice();
            }
        }
        public struct HttpSpeech
        {
            public string voiceID;
            public string playerID;
            public string content;
        }
        byte GetPakChannelType(ChatInfoType _type)
        {
            switch (_type)
            {
                case ChatInfoType.World:
                    return 1;
                case ChatInfoType.Area:
                    return 5;
                case ChatInfoType.Team:
                    return 4;
                case ChatInfoType.Fairy:
                    return 2;
                case ChatInfoType.Friend:
                    return 3;
            }
            return 1;
        }
        ChatInfoType GetPakChannelType(byte _type)
        {
            switch (_type)
            {
                case 5:
                    return ChatInfoType.Area;
                case 1:
                    return ChatInfoType.World;
                case 2:
                    return ChatInfoType.Fairy;
                case 3:
                    return ChatInfoType.Friend;
                case 4:
                    return ChatInfoType.Team;
            }
            return ChatInfoType.World;
        }
        int netState = 0;
        private void OnNetStatusChanged(NetworkReachability _state)
        {
            netState = (int)_state;
            if (netState != 1 && netState != 4)
            {
                autoPlayVoices.Clear();
            }
        }
        public bool voicePlaying { get; private set; }
        public List<VoiceInfo> autoPlayVoices = new List<VoiceInfo>();
        public void CheckAutoPlayVoice(ChatData _chat)
        {
            var _netState = netState;
#if UNITY_EDITOR
            _netState = 1;
#endif
            if (!serverInited)
            {
                return;
            }
            if (SystemSetting.Instance.GetSoundVolume() <= 0.01f)
            {
                return;
            }
            var _speechChat = _chat as ChatUeseData;
            if (null == _speechChat || !_speechChat.IsSound)
            {
                return;
            }
            if (_speechChat.player == PlayerDatas.Instance.PlayerId)
            {
                return;
            }
            if (!ChatSetting.Instance.GetAutoPlayVoice(_chat.type, _netState))
            {
                return;
            }
            if (autoPlayVoices.FindIndex((x) =>
             {
                 return x.playerId == _speechChat.player && x.tick == _speechChat.soundTick;
             }) != -1)
            {
                return;
            }
            SnxxzGame.Instance.StartCoroutine(Co_AutoPlay(new VoiceInfo()
            {
                playerId = _speechChat.player,
                tick = _speechChat.soundTick,
                type = _speechChat.type,
                length = _speechChat.soundLength,
            }));
        }
        private void WindowAfterCloseEvent(Window _win)
        {
            if (_win is LoadingWin)
            {
                AutoPlayVoice();
            }
            CheckChatFloatOpen();
        }
        IEnumerator Co_AutoPlay(VoiceInfo _info)
        {
            yield return WaitingForSecondConst.WaitMS500;
            if (serverInited)
            {
                autoPlayVoices.Add(_info);
                AutoPlayVoice();
            }
        }
        private void AutoPlayVoice()
        {
            if (voicePlaying || WindowCenter.Instance.CheckOpen<LoadingWin>()
                || !(StageManager.Instance.CurrentStage is DungeonStage))
            {
                return;
            }
            if (autoPlayVoices.Count > 0)
            {
                var _speech = autoPlayVoices[0];
                AudioClip _clip;
                if (TryGetSpeech(_speech.playerId, _speech.tick, out _clip))
                {
                    PlaySpeech(_clip, _speech.length);
                    autoPlayVoices.RemoveAt(0);
                }
                else
                {
                    DownloadSpeech(_speech.playerId, _speech.tick);
                }
            }
        }
        private void RefreshChatSetAct(ChatBoolType _type, bool _open)
        {
            switch (_type)
            {
                case ChatBoolType.GradVoice4G:
                case ChatBoolType.GradVoiceWifi:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Fairy, 1)
                        && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Fairy, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.Fairy);
                    }
                    break;
                case ChatBoolType.PrivatChatVoice4G:
                case ChatBoolType.PrivateChatVoiceWifi:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Friend, 1)
                        && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Friend, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.Friend);
                    }
                    break;
                case ChatBoolType.TeamVoice4G:
                case ChatBoolType.TeamVoiceWifi:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Team, 1)
                       && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Team, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.Team);
                    }
                    break;
                case ChatBoolType.WorldVoice4G:
                case ChatBoolType.WorldVoiceWifi:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.World, 1)
                       && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.World, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.World);
                    }
                    break;
                case ChatBoolType.AreaVoiceWifi:
                case ChatBoolType.AreaVoice4G:
                    if (!ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Area, 1)
                       && !ChatSetting.Instance.GetAutoPlayVoice(ChatInfoType.Area, 4))
                    {
                        RemoveAutoVoice(ChatInfoType.Area);
                    }
                    break;
            }
        }
        private void RemoveAutoVoice(int _playerId, long _tick)
        {
            autoPlayVoices.RemoveAll((x) =>
            {
                return x.playerId == _playerId && x.tick == _tick;
            });
        }
        private void RemoveAutoVoice(ChatInfoType _type)
        {
            autoPlayVoices.RemoveAll((x) =>
            {
                return x.type == _type;
            });
        }
        public struct VoiceInfo
        {
            public int playerId;
            public long tick;
            public float length;
            public ChatInfoType type;
        }
        #endregion
        public void OnPlayerLoginOk()
        {
            serverInited = true;
        }
        #region 聊天浮动
        private void WindowAfterOpenEvent(Window win)
        {
            CheckChatFloatOpen();
        }
        private void CheckChatFloatOpen()
        {
            if (WindowCenter.Instance.ExitAnyFullScreenOrMaskWin() && !WindowCenter.Instance.CheckOpen<LoadingWin>()
                && StageManager.Instance.CurrentStage is DungeonStage && !WindowCenter.Instance.CheckOpen<TreasureLevelUpWin>())
            {
                if (!WindowCenter.Instance.CheckOpen<ChatFloatWin>())
                {
                    WindowCenter.Instance.Open<ChatFloatWin>();
                }
            }
            else
            {
                if (WindowCenter.Instance.CheckOpen<ChatFloatWin>())
                {
                    WindowCenter.Instance.CloseImmediately<ChatFloatWin>();
                }
            }
        }
        #endregion
    }
}