| using LitJson;  | 
| using System;  | 
| using System.Collections.Generic;  | 
| using System.Linq;  | 
| using UnityEngine;  | 
|   | 
| public enum PhantasmPavilionTab  | 
| {  | 
|     Avatar,                 // 0 - 头像  | 
|     AvatarFrame,            // 1 - 头像框  | 
|     ChatExpression,         // 2 - 聊天表情  | 
|     ChatBubble              // 3 - 聊天气泡  | 
| }  | 
|   | 
| public class PhantasmPavilionModel : GameSystemManager<PhantasmPavilionModel>  | 
| {  | 
|     public readonly int MaxItemRowCount = 2;    // 一行展示x个物品  | 
|     public readonly int MaxEmojiCount = 10;  | 
|     public readonly int FuncId = 236;  | 
|     private PhantasmPavilionTab m_SelectTab;  | 
|     //当前选中的标签页  | 
|     public PhantasmPavilionTab selectTab  | 
|     {  | 
|         get { return m_SelectTab; }  | 
|         set  | 
|         {  | 
|             m_SelectTab = value;  | 
|             TabChangeEvent?.Invoke();  | 
|         }  | 
|     }  | 
|   | 
|     private int m_selectItemId;  | 
|     public int selectItemId  | 
|     {  | 
|         get { return m_selectItemId; }  | 
|         set  | 
|         {  | 
|             m_selectItemId = value;  | 
|             ItemIdChangeEvent?.Invoke();  | 
|         }  | 
|     }  | 
|   | 
|     //当前选中的表情包组  | 
|   | 
|     private int m_SelectEmojiPackID;  | 
|     public int selectEmojiPackID  | 
|     {  | 
|         get { return m_SelectEmojiPackID; }  | 
|         set  | 
|         {  | 
|             m_SelectEmojiPackID = value;  | 
|             EmojiPackIDChangeEvent?.Invoke();  | 
|         }  | 
|     }  | 
|   | 
|     private Dictionary<PhantasmPavilionTab, IPhantasmPavilionTabHandler> handlers = new Dictionary<PhantasmPavilionTab, IPhantasmPavilionTabHandler>();  | 
|     public Dictionary<PhantasmPavilionTab, Dictionary<int, PhantasmPavilionInfo>> infoDict = new Dictionary<PhantasmPavilionTab, Dictionary<int, PhantasmPavilionInfo>>();  | 
|     public Dictionary<PhantasmPavilionTab, Dictionary<int, int>> defaultIDDict = new Dictionary<PhantasmPavilionTab, Dictionary<int, int>>();  | 
|     public Dictionary<PhantasmPavilionTab, int> nowIDDict = new Dictionary<PhantasmPavilionTab, int>();  | 
|   | 
|     // 幻境阁入口红点 459  | 
|     Redpoint mainRedPoint = new Redpoint(10101, MainRedDot.PhantasmPavilionRepoint);  | 
|   | 
|     //标签页红点 4591 - 4594  | 
|     public Dictionary<PhantasmPavilionTab, Redpoint> tabRedPointDict = new Dictionary<PhantasmPavilionTab, Redpoint>();  | 
|   | 
|     public Dictionary<PhantasmPavilionTab, Dictionary<int, Redpoint>> itemRedPointDict = new Dictionary<PhantasmPavilionTab, Dictionary<int, Redpoint>>();  | 
|   | 
|     public event Action TabChangeEvent;         //切换标签页  | 
|     public event Action ItemIdChangeEvent;      //切换选中项  | 
|     public event Action EmojiPackIDChangeEvent;      //切换选中项  | 
|     public event Action UpdateFaceInfoEvent;  | 
|     public event Action UpdateFacePicInfoEvent;  | 
|     public event Action UpdateEmojiPackInfoEvent;  | 
|     public event Action UpdateChatBubbleBoxInfoEvent;  | 
|     public Action<string> SendChatAction;  | 
|   | 
|   | 
|     public override void Init()  | 
|     {  | 
|         PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerDataRefreshEvent;  | 
|         PackManager.Instance.RefreshItemEvent += OnRefreshItemCountEvent;  | 
|         GlobalTimeEvent.Instance.secondEvent += CheckRedPoint;  | 
|         InitHandler();  | 
|         InitTable();  | 
|         InitRedPoint();  | 
|     }  | 
|   | 
|     public override void Release()  | 
|     {  | 
|         PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerDataRefreshEvent;  | 
|         PackManager.Instance.RefreshItemEvent -= OnRefreshItemCountEvent;  | 
|         GlobalTimeEvent.Instance.fiveSecondEvent -= CheckRedPoint;  | 
|     }  | 
|   | 
|     private void OnRefreshItemCountEvent(PackType type, int arg2, int arg3)  | 
|     {  | 
|         m_CheckRedPoint = true;  | 
|     }  | 
|   | 
|     bool m_CheckRedPoint = false;  | 
|     void CheckRedPoint()  | 
|     {  | 
|         if (m_CheckRedPoint)  | 
|         {  | 
|             UpdateRedPoint();  | 
|             m_CheckRedPoint = false;  | 
|         }  | 
|     }  | 
|   | 
|   | 
|     public void OnBeforePlayerDataInitialize()  | 
|     {  | 
|         infoDict.Clear();  | 
|     }  | 
|   | 
|     public void OnPlayerLoginOk()  | 
|     {  | 
|         selectTab = PhantasmPavilionTab.Avatar;  | 
|         var list = ShowItemList(selectTab, out int fristIndex);  | 
|         if (!list.IsNullOrEmpty())  | 
|             selectItemId = fristIndex;  | 
|   | 
|         nowIDDict[PhantasmPavilionTab.Avatar] = PlayerDatas.Instance.baseData.face;  | 
|         nowIDDict[PhantasmPavilionTab.AvatarFrame] = PlayerDatas.Instance.baseData.facePic;  | 
|         nowIDDict[PhantasmPavilionTab.ChatBubble] = (int)PlayerDatas.Instance.baseData.bubbleId;  | 
|     }  | 
|   | 
|     private void OnPlayerDataRefreshEvent(PlayerDataType type)  | 
|     {  | 
|         if (type == PlayerDataType.Face)  | 
|         {  | 
|             nowIDDict[PhantasmPavilionTab.Avatar] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.Face);  | 
|         }  | 
|         else if (type == PlayerDataType.FacePic)  | 
|         {  | 
|             nowIDDict[PhantasmPavilionTab.AvatarFrame] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.FacePic);  | 
|         }  | 
|         else if (type == PlayerDataType.ExAttr10)  | 
|         {  | 
|             nowIDDict[PhantasmPavilionTab.ChatBubble] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr10);  | 
|         }  | 
|   | 
|         if (type == PlayerDataType.LV)  | 
|         {  | 
|             UpdateRedPoint();  | 
|         }  | 
|     }  | 
|   | 
|     private void InitHandler()  | 
|     {  | 
|         handlers = new Dictionary<PhantasmPavilionTab, IPhantasmPavilionTabHandler>();  | 
|         handlers[PhantasmPavilionTab.Avatar] = new PhantasmPavilionAvatarHandler();  | 
|         handlers[PhantasmPavilionTab.AvatarFrame] = new PhantasmPavilionAvatarFrameHandler();  | 
|         handlers[PhantasmPavilionTab.ChatExpression] = new PhantasmPavilionChatExpressionHandler();  | 
|         handlers[PhantasmPavilionTab.ChatBubble] = new PhantasmPavilionChatBubbleHandler();  | 
|     }  | 
|   | 
|     private void InitTable()  | 
|     {  | 
|         InitDefault();  | 
|     }  | 
|   | 
|     private void InitRedPoint()  | 
|     {  | 
|         InitTabRedPoint();  | 
|         InitItemRedPoint(PhantasmPavilionTab.Avatar, PlayerFaceConfig.GetKeys());  | 
|         InitItemRedPoint(PhantasmPavilionTab.AvatarFrame, PlayerFacePicConfig.GetKeys());  | 
|         InitItemRedPoint(PhantasmPavilionTab.ChatExpression, EmojiPackConfig.GetKeys());  | 
|         InitItemRedPoint(PhantasmPavilionTab.ChatBubble, ChatBubbleBoxConfig.GetKeys());  | 
|     }  | 
|   | 
|     private void InitDefault()  | 
|     {  | 
|         var tabValues = Enum.GetValues(typeof(PhantasmPavilionTab));  | 
|         for (int i = 0; i < tabValues.Length; i++)  | 
|         {  | 
|             PhantasmPavilionTab tab = (PhantasmPavilionTab)tabValues.GetValue(i);  | 
|             if (!defaultIDDict.ContainsKey(tab))  | 
|             {  | 
|                 defaultIDDict[tab] = new Dictionary<int, int>();  | 
|             }  | 
|         }  | 
|   | 
|         var config = FuncConfigConfig.Get("PhantasmPavilion");  | 
|         var jsonData = JsonMapper.ToObject(config.Numerical1);  | 
|         List<string> keyList = jsonData.Keys.ToList();  | 
|         for (int i = 0; i < keyList.Count; i++)  | 
|         {  | 
|             int key = int.Parse(keyList[i]);  | 
|             int value = int.Parse(jsonData[keyList[i]].ToString());  | 
|             defaultIDDict[PhantasmPavilionTab.Avatar][key] = value;  | 
|         }  | 
|   | 
|         jsonData = JsonMapper.ToObject(config.Numerical2);  | 
|         keyList = jsonData.Keys.ToList();  | 
|         for (int i = 0; i < keyList.Count; i++)  | 
|         {  | 
|             int key = int.Parse(keyList[i]);  | 
|             int value = int.Parse(jsonData[keyList[i]].ToString());  | 
|             defaultIDDict[PhantasmPavilionTab.AvatarFrame][key] = value;  | 
|         }  | 
|         //defaultIDDict[PhantasmPavilionTab.ChatExpression][0] = int.Parse(config.Numerical3);  | 
|         defaultIDDict[PhantasmPavilionTab.ChatBubble][0] = int.Parse(config.Numerical3);  | 
|     }  | 
|   | 
|     private void InitTabRedPoint()  | 
|     {  | 
|         var values = Enum.GetValues(typeof(PhantasmPavilionTab));  | 
|         for (int i = 0; i < values.Length; i++)  | 
|         {  | 
|             PhantasmPavilionTab tab = (PhantasmPavilionTab)values.GetValue(i);  | 
|             int id = MainRedDot.PhantasmPavilionRepoint * 10 + (int)tab + 1;  | 
|             tabRedPointDict[tab] = new Redpoint(MainRedDot.PhantasmPavilionRepoint, id);  | 
|         }  | 
|     }  | 
|   | 
|     private void InitItemRedPoint(PhantasmPavilionTab tab, List<int> idList)  | 
|     {  | 
|         if (!infoDict.ContainsKey(tab))  | 
|             itemRedPointDict[tab] = new Dictionary<int, Redpoint>();  | 
|   | 
|         for (int i = 0; i < idList.Count; i++)  | 
|         {  | 
|             int id = idList[i];  | 
|             int baseValue = MainRedDot.PhantasmPavilionRepoint * 10 + (int)tab + 1;  | 
|             itemRedPointDict[tab][id] = new Redpoint(baseValue, baseValue * 10000 + id);  | 
|         }  | 
|     }  | 
|   | 
|     public void UpdateRedPoint()  | 
|     {  | 
|         var values = Enum.GetValues(typeof(PhantasmPavilionTab));  | 
|         for (int i = 0; i < values.Length; i++)  | 
|         {  | 
|             PhantasmPavilionTab key = (PhantasmPavilionTab)values.GetValue(i);  | 
|             tabRedPointDict[key].state = RedPointState.None;  | 
|             var keyList = itemRedPointDict[key].Keys.ToList();  | 
|             for (int j = 0; j < keyList.Count; j++)  | 
|             {  | 
|                 int id = keyList[j];  | 
|                 itemRedPointDict[key][id].state = RedPointState.None;  | 
|                 //可激活  | 
|                 if (GetUnLockState(key, id) == 1)  | 
|                 {  | 
|                     itemRedPointDict[key][id].state = RedPointState.Simple;  | 
|   | 
|                     if (selectTab != key)  | 
|                     {  | 
|                         tabRedPointDict[key].state = RedPointState.Simple;  | 
|                     }  | 
|                 }  | 
|   | 
|             }  | 
|         }  | 
|     }  | 
|   | 
|   | 
|     public bool IsCustom(int faceID, out int customPlayerID)  | 
|     {  | 
|         customPlayerID = 0;  | 
|         if (!PlayerFaceConfig.HasKey(faceID))  | 
|             return false;  | 
|         customPlayerID = PlayerFaceConfig.Get(faceID).CustomPlayerID;  | 
|         if (customPlayerID <= 0)  | 
|             return false;  | 
|         return true;  | 
|     }  | 
|   | 
|   | 
|     //获取不同职业对应的默认值  | 
|     public bool TryGetDefaultID(PhantasmPavilionTab key, int job, out int defaultID)  | 
|     {  | 
|         defaultID = 0;  | 
|         if (defaultIDDict == null || !defaultIDDict.TryGetValue(key, out var dict) || dict == null)  | 
|             return false;  | 
|         // 尝试获取 job 对应的值,如果没有则获取 key 为 0 的值  | 
|         return dict.TryGetValue(job, out defaultID) || dict.TryGetValue(0, out defaultID);  | 
|     }  | 
|   | 
|     public bool TryGetNowShowID(PhantasmPavilionTab key, out int result)  | 
|     {  | 
|         result = 0;  | 
|         int job = PlayerDatas.Instance.baseData.Job;  | 
|         // 如果 nowIDDict 为空或没有当前 ID,直接尝试获取默认 ID  | 
|         if (nowIDDict == null || !TryGetDefaultID(key, job, out int defaultID))  | 
|             return false;  | 
|   | 
|         // 获取当前 ID,如果存在则赋值给 result  | 
|         if (nowIDDict.TryGetValue(key, out int nowID) && IsUnlock(key, nowID))  | 
|         {  | 
|             result = nowID;  | 
|         }  | 
|         else  | 
|         {  | 
|             result = defaultID;  | 
|         }  | 
|   | 
|         return true;  | 
|     }  | 
|   | 
|     public bool TryGetInfo(PhantasmPavilionTab tab, int id, out PhantasmPavilionInfo info)  | 
|     {  | 
|         info = new PhantasmPavilionInfo();  | 
|         if (!Has(tab, id))  | 
|             return false;  | 
|         if (infoDict == null || !infoDict.TryGetValue(tab, out var tempInfoDict))  | 
|         {  | 
|             // 定制的默认激活0星  | 
|             if (IsCustom(id, out int customPlayerID))  | 
|             {  | 
|                 if (customPlayerID == PlayerDatas.Instance.baseData.PlayerID)  | 
|                 {  | 
|                     info = new PhantasmPavilionInfo()  | 
|                     {  | 
|                         ID = id,  | 
|                         Star = 0,  | 
|                         State = true   | 
|                     };  | 
|                     return true;  | 
|                 }  | 
|             }  | 
|             return false;  | 
|         }  | 
|         if (tempInfoDict == null || !tempInfoDict.TryGetValue(id, out info))  | 
|         {  | 
|             // 定制的默认激活0星  | 
|             if (IsCustom(id, out int customPlayerID))  | 
|             {  | 
|                 if (customPlayerID == PlayerDatas.Instance.baseData.PlayerID)  | 
|                 {  | 
|                     info = new PhantasmPavilionInfo()  | 
|                     {  | 
|                         ID = id,  | 
|                         Star = 0,  | 
|                         State = true  | 
|                     };  | 
|                     return true;  | 
|                 }  | 
|             }  | 
|             return false;  | 
|         }  | 
|         return true;  | 
|     }  | 
|   | 
|   | 
|     public List<int> ShowItemList(PhantasmPavilionTab tab, out int fristIndex)  | 
|     {  | 
|         fristIndex = 0;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return new List<int>();  | 
|   | 
|         var resList = handler.GetTableKeys();  | 
|         resList.Sort((int a, int b) => Cmp(a, b, tab));  | 
|   | 
|         if (tab == PhantasmPavilionTab.Avatar)  | 
|         {  | 
|             for (int i = resList.Count - 1; i >= 0; i--)  | 
|             {  | 
|                 int id = resList[i];  | 
|                 int[] JobShowList = PlayerFaceConfig.Get(id).JobShowList;  | 
|                 if (JobShowList != null && !JobShowList.Contains(PlayerDatas.Instance.baseData.Job) && resList.Contains(id))  | 
|                 {  | 
|                     resList.Remove(id);  | 
|                 }  | 
|             }  | 
|         }  | 
|   | 
|         fristIndex = resList.First();  | 
|         return resList;  | 
|     }  | 
|   | 
|     public int Cmp(int a, int b, PhantasmPavilionTab tab)  | 
|     {  | 
|         // 获取 a 和 b 的解锁状态  | 
|         int stateA = GetUnLockState(tab, a);  | 
|         int stateB = GetUnLockState(tab, b);  | 
|   | 
|         // 将状态重新定义为优先级排序数值:可激活 > 已激活 > 未激活最后  | 
|         int priorityA = stateA == 1 ? 0 : (stateA == 2 ? 1 : 2);  | 
|         int priorityB = stateB == 1 ? 0 : (stateB == 2 ? 1 : 2);  | 
|   | 
|         if (priorityA != priorityB)  | 
|         {  | 
|             return priorityA.CompareTo(priorityB);  | 
|         }  | 
|   | 
|         // 如果激活状态相同,比较 SortNum  | 
|         int sortNumA = GetSortNum(tab, a);  | 
|         int sortNumB = GetSortNum(tab, b);  | 
|   | 
|         if (sortNumA != sortNumB)  | 
|         {  | 
|             if (tab == PhantasmPavilionTab.Avatar)  | 
|             {  | 
|                 return sortNumB.CompareTo(sortNumA);  | 
|             }  | 
|             else  | 
|             {  | 
|                 return sortNumA.CompareTo(sortNumB);  | 
|             }  | 
|         }  | 
|   | 
|         return a.CompareTo(b);  | 
|     }  | 
|   | 
|     ////获得当前状态 0 - 未激活 1 - 可激活 2 - 已激活  | 
|     public int GetUnLockState(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return 0;  | 
|   | 
|         if (IsCustom(id, out int customPlayerID))  | 
|         {  | 
|             if (customPlayerID == PlayerDatas.Instance.baseData.PlayerID)  | 
|                 return 2;  | 
|             return 0;  | 
|         }  | 
|   | 
|         //没激活  | 
|         if (!IsUnlock(tab, id))  | 
|         {  | 
|             //没有填激活物品  | 
|             if (!TryGetUnLockNeedItem(tab, id, out int itemId, out int count))  | 
|                 return 0;  | 
|             if (!ItemConfig.HasKey(itemId))  | 
|                 return 0;  | 
|             ItemConfig itemConfig = ItemConfig.Get(itemId);  | 
|             if (itemConfig.UseLV > PlayerDatas.Instance.baseData.LV)  | 
|                 return 0;  | 
|             //激活物品数量不足  | 
|             var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, itemId);  | 
|             if (hasCnt < count)  | 
|                 return 0;  | 
|             return 1;  | 
|         }  | 
|         return 2;  | 
|     }  | 
|   | 
|     //获得属性展示样式类型  0 加号 1 箭头 false不展示  | 
|     public bool TryGetAttrShowType(PhantasmPavilionTab tab, int faceId, out int type)  | 
|     {  | 
|         type = 0;  | 
|         //int unLockState = GetUnLockState(tab, faceId);// 0 - 未激活 1 - 可激活 2 - 已激活  | 
|         // bool isHaveUnLockAttr = TryGetUnLockAttr(tab, selectItemId, out int[] lightAttrTypeArr, out int[] lightAttrValueArr);  | 
|   | 
|         // if (!isHaveUnLockAttr)  | 
|         //     return false;  | 
|   | 
|         return false;  | 
|     }  | 
|   | 
|       | 
|     #region 表情包接入相关  | 
|   | 
|     public List<int> GetUnlockIDList()  | 
|     {  | 
|         List<int> allList = EmojiPackConfig.GetKeys();  | 
|         List<int> result = new List<int>();  | 
|         for (int i = 0; i < allList.Count; i++)  | 
|         {  | 
|             int id = allList[i];  | 
|             if (IsUnlock(PhantasmPavilionTab.ChatExpression, id))  | 
|             {  | 
|                 result.Add(id);  | 
|             }  | 
|         }  | 
|         return result;  | 
|     }  | 
|   | 
|     public List<string> GetEmojiList(int id)  | 
|     {  | 
|         var info = FrameAnimationConfig.GetEmojiPackList();  | 
|         if (info == null || !info.TryGetValue(id, out var list) || list == null)  | 
|             return new List<string>();  | 
|         return list;  | 
|     }  | 
|   | 
|     public int GetShowEmojiInfo(float itemWidth, int id, out int rowCount, out int emojiCount, out int space)  | 
|     {  | 
|         emojiCount = 0;  | 
|         rowCount = 0;  | 
|         space = 0; // 默认值  | 
|   | 
|         int minSpace = 5; // 最小间隔  | 
|         int maxSpace = 50; // 最大间隔  | 
|         int width = Mathf.CeilToInt(itemWidth);  | 
|   | 
|         GetEmojiShowSize(id, out int emojiWidth, out int emojiHeight);  | 
|         List<string> emojiList = GetEmojiList(id);  | 
|         if (emojiList == null || emojiList.Count == 0 || emojiWidth == 0)  | 
|             return 0;  | 
|   | 
|         int listCount = emojiList.Count;  | 
|         emojiCount = Mathf.Min(MaxEmojiCount, Mathf.Min(width / emojiWidth, listCount));  | 
|   | 
|         if (emojiCount > 1)  | 
|         {  | 
|             int availableWidthForSpaces = width - (emojiCount * emojiWidth);  | 
|             space = availableWidthForSpaces / (emojiCount - 1);  | 
|             space = Mathf.Clamp(space, minSpace, maxSpace);  | 
|         }  | 
|         else  | 
|         {  | 
|             space = 0; // 没有空间可分配间隔或者间隔之间只有一个表情  | 
|         }  | 
|   | 
|         rowCount = Mathf.CeilToInt((float)listCount / emojiCount);  | 
|         return 0;  | 
|     }  | 
|   | 
|     // 获得表情包中表情最大的尺寸  | 
|     public void GetEmojiShowSize(int id, out int width, out int height)  | 
|     {  | 
|         width = 0;  | 
|         height = 0;  | 
|   | 
|         List<string> emojiList = GetEmojiList(id);  | 
|         if (emojiList.IsNullOrEmpty())  | 
|             return;  | 
|   | 
|         for (int i = 0; i < emojiList.Count; i++)  | 
|         {  | 
|             string imgSrc = emojiList[i];  | 
|   | 
|             if (UIFrameMgr.Inst.ContainsDynamicImage(imgSrc))  | 
|             {  | 
|                 List<UnityEngine.Sprite> spriteList = UIFrameMgr.Inst.GetDynamicImage(imgSrc);  | 
|                 if (!spriteList.IsNullOrEmpty())  | 
|                 {  | 
|                     for (int j = 0; j < spriteList.Count; j++)  | 
|                     {  | 
|                         UpdateMaxSize(spriteList[j], ref width, ref height);  | 
|                     }  | 
|                 }  | 
|             }  | 
|             else if (IconConfig.HasKey(imgSrc))  | 
|             {  | 
|                 UnityEngine.Sprite sprite = UILoader.LoadSprite(imgSrc);  | 
|                 UpdateMaxSize(sprite, ref width, ref height);  | 
|             }  | 
|         }  | 
|     }  | 
|   | 
|     // 更新最大尺寸的方法  | 
|     private void UpdateMaxSize(UnityEngine.Sprite sprite, ref int width, ref int height)  | 
|     {  | 
|         float nowWidth = sprite.rect.width;  | 
|         float nowHeight = sprite.rect.height;  | 
|         if (width < nowWidth)  | 
|             width = Mathf.CeilToInt(nowWidth);  | 
|         if (height < nowHeight)  | 
|             height = Mathf.CeilToInt(nowHeight);  | 
|     }  | 
|   | 
|     #endregion  | 
|   | 
|     //获得自己的聊天气泡ID  | 
|     public int GetNowChatBubbleID()  | 
|     {  | 
|         PhantasmPavilionTab key = PhantasmPavilionTab.ChatBubble;  | 
|         int job = 0;  | 
|         // 尝试获取当前 ID  | 
|         if (nowIDDict.TryGetValue(key, out int nowID) && ChatBubbleBoxConfig.HasKey(nowID) && IsUnlock(key, nowID))  | 
|             return nowID;  | 
|         // 如果当前 ID 不存在或未解锁,尝试获取默认 ID  | 
|         return TryGetDefaultID(key, job, out int defaultID) ? defaultID : -1;  | 
|     }  | 
|   | 
|     //获得其他玩家的聊天气泡ID  | 
|     public int GetNowOtherChatBubbleID(int nowID)  | 
|     {  | 
|         PhantasmPavilionTab key = PhantasmPavilionTab.AvatarFrame;  | 
|         // 尝试获取当前 ID  | 
|         if (ChatBubbleBoxConfig.HasKey(nowID))  | 
|             return nowID;  | 
|         // 如果当前 ID 不存在或未解锁,尝试获取默认 ID  | 
|         return TryGetDefaultID(key, 0, out int defaultID) ? defaultID : -1;  | 
|     }  | 
|   | 
|     public bool IsUnlock(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return false;  | 
|         int unlockDefault = GetUnlockDefault(tab, id);  | 
|         //配默认激活的 不做其他判定直接激活  | 
|         if (unlockDefault == 1)  | 
|             return true;  | 
|         // 封包中没有  | 
|         if (!TryGetInfo(tab, id, out var info))  | 
|             return false;  | 
|         // 状态是未激活  | 
|         if (!info.State)  | 
|             return false;  | 
|         // 时效不为永久 且时效用完  | 
|         if (info.EndTime > 0 && info.EndTime < TimeUtility.AllSeconds)  | 
|             return false;  | 
|         return true;  | 
|     }  | 
|   | 
|     //是否有时效 true 有时间限制 false 永久(无时间限制)  | 
|     public bool IsLimitTime(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return false;  | 
|         int unlockDefault = GetUnlockDefault(tab, id);  | 
|         int expireMinutes = GetExpireMinutes(tab, id);  | 
|         //没找到  | 
|         if (unlockDefault == -1 || expireMinutes == -1)  | 
|             return false;  | 
|         //默认激活的都是永久的,没有时效限制  | 
|         if (unlockDefault == 1)  | 
|             return false;  | 
|         //时效分钟配0的都是永久的,没有时效限制  | 
|         if (expireMinutes <= 0)  | 
|             return false;  | 
|         return true;  | 
|     }  | 
|   | 
|       | 
|   | 
|     public void ShowImage(PhantasmPavilionTab tab, int id, ImageEx imgTitle)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return;  | 
|         string image = GetImage(tab, id);  | 
|         UIFrame frame = imgTitle.GetComponent<UIFrame>();  | 
|         if (UIFrameMgr.Inst.ContainsDynamicImage(image))  | 
|         {  | 
|             if (frame == null)  | 
|                 frame = imgTitle.gameObject.AddComponent<UIFrame>();  | 
|   | 
|             List<UnityEngine.Sprite> spriteList = UIFrameMgr.Inst.GetDynamicImage(image);  | 
|             if (!spriteList.IsNullOrEmpty())  | 
|             {  | 
|                 imgTitle.rectTransform.sizeDelta = new Vector2(spriteList[0].rect.width, spriteList[0].rect.height);  | 
|             }  | 
|   | 
|             imgTitle.raycastTarget = false;  | 
|             frame.ResetFrame(image);  | 
|             frame.enabled = true;  | 
|         }  | 
|         else  | 
|         {  | 
|             if (frame != null)  | 
|                 frame.enabled = false;  | 
|             imgTitle.SetSprite(image);  | 
|             imgTitle.SetNativeSize();  | 
|         }  | 
|     }  | 
|   | 
|   | 
|   | 
|     #region handler相关  | 
|   | 
|     public bool Has(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return false;  | 
|         return handler.Has(id);  | 
|     }  | 
|     public string GetDescriptive(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return string.Empty;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return string.Empty;  | 
|         return handler.GetDescriptive(id);  | 
|     }  | 
|   | 
|     public int GetSortNum(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return 0;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return 0;  | 
|         return handler.GetSortNum(id);  | 
|     }  | 
|   | 
|     public string GetName(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return string.Empty;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return string.Empty;  | 
|         return handler.GetName(id);  | 
|     }  | 
|   | 
|     public string GetImage(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return string.Empty;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return string.Empty;  | 
|         return handler.GetImage(id);  | 
|     }  | 
|   | 
|     public int GetUnlockDefault(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return 0;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return 0;  | 
|         return handler.GetUnlockDefault(id);  | 
|     }  | 
|   | 
|     public int GetExpireMinutes(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return 0;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return 0;  | 
|         return handler.GetExpireMinutes(id);  | 
|     }  | 
|   | 
|     public bool IsUsing(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return false;  | 
|         if (!TryGetNowShowID(tab, out int result))  | 
|             return false;  | 
|         return result == id;  | 
|     }  | 
|   | 
|     public bool TryGetUnLockAttr(PhantasmPavilionTab tab, int id, out int[] lightAttrTypeArr, out int[] lightAttrValueArr)  | 
|     {  | 
|         lightAttrTypeArr = null;  | 
|         lightAttrValueArr = null;  | 
|         if (!Has(tab, id))  | 
|             return false;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return false;  | 
|         return handler.TryGetUnLockAttr(id, out lightAttrTypeArr, out lightAttrValueArr);  | 
|     }  | 
|   | 
|     public bool TryGetUnLockNeedItem(PhantasmPavilionTab tab, int id, out int itemId, out int count)  | 
|     {  | 
|         itemId = 0;  | 
|         count = 0;  | 
|         if (!Has(tab, id))  | 
|             return false;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return false;  | 
|         return handler.TryGetUnLockNeedItem(id, out itemId, out count);  | 
|     }  | 
|   | 
|   | 
|   | 
|     public bool TryGetEffectID(PhantasmPavilionTab tab, int id, out int effectID)  | 
|     {  | 
|         effectID = 0;  | 
|         if (!Has(tab, id))  | 
|             return false;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return false;  | 
|         return handler.TryGetEffectID(id, out effectID);  | 
|     }  | 
|   | 
|   | 
|   | 
|   | 
|     public void SendUsePack(PhantasmPavilionTab tab, int id)  | 
|     {  | 
|         if (!Has(tab, id))  | 
|             return;  | 
|         if (!handlers.TryGetValue(tab, out var handler))  | 
|             return;  | 
|         handler.SendUsePack(id);  | 
|     }  | 
|   | 
|     #endregion  | 
|   | 
|     #region 发封包  | 
|   | 
|     public void SendCA323UnLockPack(int itemIndex, int count)  | 
|     {  | 
|         var pack = new CA323_tagCMUseItems();  | 
|         pack.ItemIndex = (byte)itemIndex;  | 
|         pack.UseCnt = (ushort)count;  | 
|         GameNetSystem.Instance.SendInfo(pack);  | 
|     }  | 
|   | 
|     public void SendCB226FaceChange(int faceId)  | 
|     {  | 
|         var pack = new CB226_tagCMFaceChange();  | 
|         pack.FaceID = (uint)faceId;  | 
|         GameNetSystem.Instance.SendInfo(pack);  | 
|     }  | 
|   | 
|   | 
|   | 
|     public void SendCB228FacePicChange(int facePicId)  | 
|     {  | 
|         var pack = new CB228_tagCMFacePicChange();  | 
|         pack.FacePicID = (uint)facePicId;  | 
|         GameNetSystem.Instance.SendInfo(pack);  | 
|     }  | 
|   | 
|   | 
|   | 
|     public void SendCA230SetChatBubbleBox(int id)  | 
|     {  | 
|         CA230_tagCMSetChatBubbleBox pak = new CA230_tagCMSetChatBubbleBox();  | 
|         pak.BubbleBoxType = (byte)id;  | 
|         GameNetSystem.Instance.SendInfo(pak);  | 
|     }  | 
|   | 
|   | 
|     #endregion  | 
|   | 
|     #region 收封包  | 
|   | 
|     public void UpdateFaceInfo(HB117_tagMCFaceInfo vNetData)  | 
|     {  | 
|         if (!infoDict.ContainsKey(PhantasmPavilionTab.Avatar))  | 
|             infoDict[PhantasmPavilionTab.Avatar] = new Dictionary<int, PhantasmPavilionInfo>();  | 
|         for (int i = 0; i < vNetData.FaceList.Length; i++)  | 
|         {  | 
|             HB117_tagMCFaceInfo.tagMCFace tagMCFaces = vNetData.FaceList[i];  | 
|             if (!infoDict[PhantasmPavilionTab.Avatar].ContainsKey((int)tagMCFaces.FaceID))  | 
|                 infoDict[PhantasmPavilionTab.Avatar][(int)tagMCFaces.FaceID] = new PhantasmPavilionInfo();  | 
|             infoDict[PhantasmPavilionTab.Avatar][(int)tagMCFaces.FaceID].ID = (int)tagMCFaces.FaceID;  | 
|             infoDict[PhantasmPavilionTab.Avatar][(int)tagMCFaces.FaceID].State = tagMCFaces.State == 1;  | 
|             infoDict[PhantasmPavilionTab.Avatar][(int)tagMCFaces.FaceID].EndTime = tagMCFaces.EndTime;  | 
|         }  | 
|         UpdateRedPoint();  | 
|         UpdateFaceInfoEvent?.Invoke();  | 
|     }  | 
|   | 
|     public void UpdateFacePicInfo(HB118_tagMCFacePicInfo vNetData)  | 
|     {  | 
|         if (!infoDict.ContainsKey(PhantasmPavilionTab.AvatarFrame))  | 
|             infoDict[PhantasmPavilionTab.AvatarFrame] = new Dictionary<int, PhantasmPavilionInfo>();  | 
|   | 
|         for (int i = 0; i < vNetData.FacePicList.Length; i++)  | 
|         {  | 
|             HB118_tagMCFacePicInfo.tagMCFacePic tagMCFacePics = vNetData.FacePicList[i];  | 
|             if (!infoDict[PhantasmPavilionTab.AvatarFrame].ContainsKey((int)tagMCFacePics.FacePicID))  | 
|                 infoDict[PhantasmPavilionTab.AvatarFrame][(int)tagMCFacePics.FacePicID] = new PhantasmPavilionInfo();  | 
|             infoDict[PhantasmPavilionTab.AvatarFrame][(int)tagMCFacePics.FacePicID].ID = (int)tagMCFacePics.FacePicID;  | 
|             infoDict[PhantasmPavilionTab.AvatarFrame][(int)tagMCFacePics.FacePicID].State = tagMCFacePics.State == 1;  | 
|             infoDict[PhantasmPavilionTab.AvatarFrame][(int)tagMCFacePics.FacePicID].EndTime = tagMCFacePics.EndTime;  | 
|         }  | 
|         UpdateRedPoint();  | 
|         UpdateFacePicInfoEvent?.Invoke();  | 
|     }  | 
|   | 
|     public void UpdateEmojiPackInfo(HA721_tagMCEmojiPackInfo vNetData)  | 
|     {  | 
|         if (!infoDict.ContainsKey(PhantasmPavilionTab.ChatExpression))  | 
|             infoDict[PhantasmPavilionTab.ChatExpression] = new Dictionary<int, PhantasmPavilionInfo>();  | 
|   | 
|         for (int i = 0; i < vNetData.EmojiPackList.Length; i++)  | 
|         {  | 
|             HA721_tagMCEmojiPackInfo.tagMCEmojiPack emojiPack = vNetData.EmojiPackList[i];  | 
|             if (!infoDict[PhantasmPavilionTab.ChatExpression].ContainsKey((int)emojiPack.PackID))  | 
|                 infoDict[PhantasmPavilionTab.ChatExpression][(int)emojiPack.PackID] = new PhantasmPavilionInfo();  | 
|             infoDict[PhantasmPavilionTab.ChatExpression][(int)emojiPack.PackID].ID = (int)emojiPack.PackID;  | 
|             infoDict[PhantasmPavilionTab.ChatExpression][(int)emojiPack.PackID].State = emojiPack.State == 1;  | 
|             infoDict[PhantasmPavilionTab.ChatExpression][(int)emojiPack.PackID].EndTime = emojiPack.EndTime;  | 
|         }  | 
|         UpdateRedPoint();  | 
|         UpdateEmojiPackInfoEvent?.Invoke();  | 
|     }  | 
|   | 
|     public void UpdateChatBubbleBoxInfo(HA717_tagMCChatBubbleBoxState vNetData)  | 
|     {  | 
|         if (!infoDict.ContainsKey(PhantasmPavilionTab.ChatBubble))  | 
|             infoDict[PhantasmPavilionTab.ChatBubble] = new Dictionary<int, PhantasmPavilionInfo>();  | 
|   | 
|         for (int i = 0; i < vNetData.BoxList.Length; i++)  | 
|         {  | 
|             HA717_tagMCChatBubbleBoxState.tagMCChatBubbleBox chatBubbleBox = vNetData.BoxList[i];  | 
|             if (!infoDict[PhantasmPavilionTab.ChatBubble].ContainsKey((int)chatBubbleBox.BoxID))  | 
|                 infoDict[PhantasmPavilionTab.ChatBubble][(int)chatBubbleBox.BoxID] = new PhantasmPavilionInfo();  | 
|             infoDict[PhantasmPavilionTab.ChatBubble][(int)chatBubbleBox.BoxID].ID = (int)chatBubbleBox.BoxID;  | 
|             infoDict[PhantasmPavilionTab.ChatBubble][(int)chatBubbleBox.BoxID].State = chatBubbleBox.State == 1;  | 
|             infoDict[PhantasmPavilionTab.ChatBubble][(int)chatBubbleBox.BoxID].EndTime = chatBubbleBox.EndTime;  | 
|         }  | 
|         UpdateRedPoint();  | 
|         UpdateChatBubbleBoxInfoEvent?.Invoke();  | 
|     }  | 
|   | 
|     #endregion  | 
| }  | 
|   | 
| public class PhantasmPavilionInfo  | 
| {  | 
|     public int ID;                  //ID  | 
|     public bool State;              //是否已激活  | 
|     public uint EndTime;            //到期时间戳,0为永久  | 
|     public int Star;               //星级  | 
| } |