using System; using System.Collections.Generic; using UnityEngine; public partial class PhantasmPavilionManager : GameSystemManager { public event Action OnShowItemListChange; private PhantasmPavilionType m_nowType; public PhantasmPavilionType nowType { get { return m_nowType; } set { if (m_nowType == value) return; m_nowType = value; OnShowItemListChange?.Invoke(value); } } public event Action OnSelectItemIdChange; private int m_selectId; public int selectId { get { return m_selectId; } set { if (m_selectId == value) return; m_selectId = value; RemoveNewHero(nowType, value); OnSelectItemIdChange?.Invoke(value); } } //<类型,> public Dictionary> dataDict = new Dictionary>(); public event Action OnUpdateModelInfoEvent; public event Action OnUpdateFacePicInfo; public event Action OnUpdateChatBoxInfoEvent; public event Action OnUpdateTitleInfoEvent; public event Action OnUpdateFaceInfoEvent; public event Action OnTimeOut; public override void Init() { DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent += OnBeforePlayerDataInitializeEvent; DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent += OnPlayerLoginOk; PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerDataRefreshEvent; PackManager.Instance.RefreshItemEvent += OnRefreshItemEvent; GlobalTimeEvent.Instance.secondEvent += OnSecondEvent; InitTable(); InitTabRedPoint(); } public override void Release() { DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent -= OnBeforePlayerDataInitializeEvent; DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent -= OnPlayerLoginOk; PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerDataRefreshEvent; PackManager.Instance.RefreshItemEvent -= OnRefreshItemEvent; GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent; } private void OnSecondEvent() { CheckTimeOut(); } private void OnRefreshItemEvent(PackType type, int arg2, int arg3) { if (type != PackType.Item) return; UpdateRedPoint(); } private void OnPlayerLoginOk() { InitNowIDDict(); LoadLocal(); RefreshAttr(); UpdateRedPoint(); } public void OnBeforePlayerDataInitializeEvent() { dataDict.Clear(); nowIDDict.Clear(); } private void OnPlayerDataRefreshEvent(PlayerDataType type) { UpdateNowIDDict(type); } public int GetJumpIndex(PhantasmPavilionType type, int tabType = 0) { if (!TryGetRowCountMax(type, out int rowCountMax) || type != nowType) return 0; int id = selectId; List list = ShowItemList(type, tabType); if (list.IsNullOrEmpty() || !list.Contains(id)) return 0; int index = list.IndexOf(id); int rowCount = (int)Math.Ceiling((double)index / rowCountMax); return Mathf.Max(0, rowCount - 1); } public void SetSelectItemId(PhantasmPavilionType type, int tabType = 0) { List list = new List(); switch (type) { case PhantasmPavilionType.Model: list = ModelConfig.GetTabTypeTitles(tabType); break; case PhantasmPavilionType.Title: list = TitleConfig.GetTabTypeTitles(tabType); break; default: list = GetTableKeys(type); break; } if (list.IsNullOrEmpty() || !TryGetNowShowID(type, out int nowShowID)) return; int id = nowShowID; if (list.Contains(id)) { selectId = id; return; } foreach (var key in list) { bool isUnlock = IsUnlock(type, key); if (isUnlock) { selectId = key; return; } } selectId = list[0]; } // 检查是否满足“通过道具升级”的条件 public bool CheckCanUpByItem(PhantasmPavilionType type, int id) { bool isUnlock = IsUnlock(type, id); bool isCanStarAdd = HasStarAddAttr(type, id); bool isStarMax = IsStarMax(type, id); int unlockWay = GetUnlockWay(type, id); int unlockValue = GetUnlockValue(type, id); if (!isUnlock || !isCanStarAdd || isStarMax || unlockWay != 2) return false; int itemId = unlockValue; // 道具配置不存在 if (!ItemConfig.HasKey(itemId)) return false; ItemConfig itemConfig = ItemConfig.Get(itemId); // 玩家等级不足 if (itemConfig.UseLV > PlayerDatas.Instance.baseData.LV) return false; // 道具数量不足 var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, itemId); int upNeedCnt = GetUpNeedCnt(type, id); if (hasCnt < upNeedCnt) return false; return true; } public void ShowFace(ImageEx imgFace, UIEffectPlayer spine, UIFrame uiFrame, EllipseMask ellipseMask, int id) { PhantasmPavilionType type = PhantasmPavilionType.Face; int UnlockWay = GetUnlockWay(type, id); int unlockValue = GetUnlockValue(type, id); int resourceType = GetResourceType(type, id); string resourceValue = GetResourceValue(type, id); if (UnlockWay == 3 && resourceValue == "") { int heroID = unlockValue; if (!HeroConfig.HasKey(heroID)) return; HeroConfig heroConfig = HeroConfig.Get(heroID); int skinID = heroConfig.SkinIDList[0]; if (!HeroSkinConfig.HasKey(skinID)) return; HeroSkinConfig skinConfig = HeroSkinConfig.Get(skinID); var sprite = UILoader.LoadSprite("HeroHead", skinConfig.SquareIcon); if (sprite == null) { Show(imgFace, spine, uiFrame, resourceType, "herohead_default", null, ellipseMask); } else { Show(imgFace, spine, uiFrame, resourceType, string.Empty, sprite, ellipseMask); } } else { resourceValue = GetResourceValue(type, id); Show(imgFace, spine, uiFrame, resourceType, resourceValue, null, ellipseMask); } } public void Show(ImageEx imgFace, UIEffectPlayer spine, UIFrame uiFrame, int resourceType, string resourceValue, Sprite sprite = null, EllipseMask ellipseMask = null) { spine.Stop(); switch (resourceType) { // 静态图 case 1: imgFace.enabled = true; spine.enabled = false; uiFrame.enabled = false; if (sprite == null) { if (!IconConfig.HasKey(resourceValue)) return; imgFace.SetSprite(resourceValue); } else { imgFace.overrideSprite = sprite; } break; case 2: // spine imgFace.enabled = true; uiFrame.enabled = false; spine.enabled = true; imgFace.sprite = null; imgFace.overrideSprite = null; spine.effectId = int.Parse(resourceValue); spine.isPlaySpineLoop = true; spine.Play(); break; // 序列帧 case 3: imgFace.enabled = true; spine.enabled = false; uiFrame.enabled = true; imgFace.sprite = null; imgFace.overrideSprite = null; if (!UIFrameMgr.Inst.ContainsDynamicImage(resourceValue)) break; //List spriteList = UIFrameMgr.Inst.GetDynamicImage(resourceValue); // if (!spriteList.IsNullOrEmpty()) // { // imgFace.rectTransform.sizeDelta = new Vector2(spriteList[0].rect.width, spriteList[0].rect.height); // } uiFrame.ResetFrame(resourceValue); uiFrame.enabled = true; break; } if (ellipseMask != null) { ellipseMask.UpdateChildrenStencil(); } } public bool TryGetInfo(PhantasmPavilionType type, int id, out PhantasmPavilionData info) { info = null; return dataDict.TryGetValue(type, out var dict) && dict.TryGetValue(id, out info); } // 有没有属性 public bool HasInitAttr(PhantasmPavilionType type, int id) { if (!Has(type, id)) return false; int[] attrIDList = GetAttrIDList(type, id); int[] initAttrValueList = GetInitAttrValueList(type, id); if (attrIDList.IsNullOrEmpty() || initAttrValueList.IsNullOrEmpty() || attrIDList.Length != initAttrValueList.Length) return false; return true; } //是否已经升满星 public bool IsStarMax(PhantasmPavilionType type, int id) { if (!HasStarAddAttr(type, id)) return false; if (!TryGetInfo(type, id, out PhantasmPavilionData info)) return false; int starMax = GetStarMax(type, id); return info.Star >= starMax; } // 是否可升星 public bool HasStarAddAttr(PhantasmPavilionType type, int id) { if (!Has(type, id)) return false; if (!HasInitAttr(type, id)) return false; int[] initAttrValueList = GetInitAttrValueList(type, id); int[] AttrPerStarAddList = GetAttrPerStarAddList(type, id); if (initAttrValueList.IsNullOrEmpty() || AttrPerStarAddList.IsNullOrEmpty() || initAttrValueList.Length != AttrPerStarAddList.Length) return false; return true; } public bool IsUsing(PhantasmPavilionType type, int id) { if (!Has(type, id)) return false; if (!TryGetNowShowID(type, out int result)) return false; return result == id; } public List ShowItemList(PhantasmPavilionType type, int tabType = 0) { var resList = new List(); switch (type) { case PhantasmPavilionType.Model: resList = ModelConfig.GetTabTypeTitles(tabType); break; case PhantasmPavilionType.Title: resList = TitleConfig.GetTabTypeTitles(tabType); break; default: resList = GetTableKeys(type); break; } resList.Sort((int a, int b) => Cmp(a, b, type)); return resList; } public int Cmp(int a, int b, PhantasmPavilionType type) { // 获取 a 和 b 的解锁状态 int stateA = (int)GetUnLockState(type, a); int stateB = (int)GetUnLockState(type, b); // 将状态重新定义为优先级排序数值:已激活(2) > 可激活(1) > 未激活(0) int priorityA = stateA == 2 ? 0 : (stateA == 1 ? 1 : 2); int priorityB = stateB == 2 ? 0 : (stateB == 1 ? 1 : 2); if (priorityA != priorityB) { return priorityA.CompareTo(priorityB); } return a.CompareTo(b); } // 除道具解锁外,其他方式暂默认永久 // 是否有时效 true 有时间限制 false 永久(无时间限制) public bool IsLimitTime(PhantasmPavilionType type, int id) { if (!Has(type, id)) return false; // 如果不是“道具解锁”方式,也视为永久 if (GetUnlockWay(type, id) != (int)PhantasmPavilionUnlockWay.Item) return false; // 物品存在且是“道具解锁”,取决于有效期 int expireMinutes = GetExpireMinutes(type, id); return expireMinutes > 0; } //物品是否已过期 private bool IsExpired(PhantasmPavilionData info, PhantasmPavilionUnlockWay unlockWay) { // 只有“道具”方式才需要检查时效,武将解锁(Hero) 或 默认(Activate) 视为永久 if (unlockWay != PhantasmPavilionUnlockWay.Item) return false; // EndTime == 0 表示永久 bool isLimitedTime = info.EndTime > 0; if (!isLimitedTime) return false; // 是限时道具,检查当前时间是否已经超过了截止时间 bool timeHasPassed = info.EndTime < TimeUtility.AllSeconds; return timeHasPassed; } // 除道具解锁外,其他方式暂默认永久 // 1 - 默认解锁,即创角就可用的 // 2 - 道具解锁,支持时效、升级, Value配物品ID // 3 - 关联武将解锁,Value配武将ID public bool IsUnlock(PhantasmPavilionType type, int id) { // 配置表中不存在,视为未解锁 if (!Has(type, id)) return false; int unlockWayValue = GetUnlockWay(type, id); int unlockValue = GetUnlockValue(type, id); // 解锁方式无效 if (!Enum.IsDefined(typeof(PhantasmPavilionUnlockWay), unlockWayValue)) return false; var unlockWay = (PhantasmPavilionUnlockWay)unlockWayValue; switch (unlockWay) { case PhantasmPavilionUnlockWay.Activate: return true; case PhantasmPavilionUnlockWay.Hero: bool hasHero = HeroManager.Instance.HasHero(unlockValue); return hasHero; case PhantasmPavilionUnlockWay.Item: // 封包里没有 if (!TryGetInfo(type, id, out var info)) return false; // 玩家数据中的状态是“未激活” if (!info.State) return false; // 是否为“已过期的道具” if (IsExpired(info, unlockWay)) return false; return true; default: return false; } } /// /// 获得当前状态 /// /// 0 - 未激活, 1 - 可激活, 2 - 已激活 public PhantasmPavilionState GetUnLockState(PhantasmPavilionType type, int id) { // 配置表中不存在,视为“未激活” if (!Has(type, id)) return PhantasmPavilionState.Locked; // 已经解锁 if (IsUnlock(type, id)) return PhantasmPavilionState.Activated; // 运行到这里,说明物品是“未激活”或“已过期”状态 (IsUnlock 返回 false) // 无效的解锁方式 int unlockWayValue = GetUnlockWay(type, id); if (!Enum.IsDefined(typeof(PhantasmPavilionUnlockWay), unlockWayValue)) return PhantasmPavilionState.Locked; var unlockWay = (PhantasmPavilionUnlockWay)unlockWayValue; int unlockValue = GetUnlockValue(type, id); switch (unlockWay) { // 检查道具激活条件 case PhantasmPavilionUnlockWay.Item: return CheckCanActivateByItem(type, id, unlockValue) ? PhantasmPavilionState.CanActivate : PhantasmPavilionState.Locked; // 检查武将激活条件 case PhantasmPavilionUnlockWay.Hero: int heroID = unlockValue; return HeroManager.Instance.HasHero(heroID) ? PhantasmPavilionState.Activated : PhantasmPavilionState.Locked; default: return PhantasmPavilionState.Locked; } } // 检查是否满足“通过道具激活”的条件 private bool CheckCanActivateByItem(PhantasmPavilionType type, int id, int itemId) { // 道具配置不存在 if (!ItemConfig.HasKey(itemId)) return false; ItemConfig itemConfig = ItemConfig.Get(itemId); // 玩家等级不足 if (itemConfig.UseLV > PlayerDatas.Instance.baseData.LV) return false; // 道具数量不足 var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, itemId); int unlockNeedCnt = GetUnlockNeedCnt(type, id); if (hasCnt < unlockNeedCnt) return false; return true; } public void CheckTimeOut() { bool isTimeOut = false; var expiredItems = new Dictionary>(); if (dataDict.IsNullOrEmpty()) return; // 单次遍历:检查限时物品并收集过期项目 foreach (var kv in dataDict) { var type = kv.Key; var dict = kv.Value; foreach (var kv2 in dict) { var id = kv2.Key; var data = kv2.Value; // 只检查限时物品 if (!IsLimitTime(type, id)) continue; int unlockWay = GetUnlockWay(type, id); bool isExpired = IsExpired(data, (PhantasmPavilionUnlockWay)unlockWay); if (isExpired) { isTimeOut = true; if (!expiredItems.ContainsKey(type)) { expiredItems[type] = new List(); } if (!expiredItems[type].Contains(id)) { expiredItems[type].Add(id); } } } } // 如果没有过期物品,直接返回 if (!isTimeOut) return; // 从dataDict中移除过期的项目 if (!expiredItems.IsNullOrEmpty()) { foreach (var kv in expiredItems) { var type = kv.Key; var list = kv.Value; if (dataDict.ContainsKey(type)) { foreach (var id in list) { dataDict[type].Remove(id); } } } } RefreshAttr(); UpdateRedPoint(); OnTimeOut?.Invoke(); } #region 收封包 public event Action OnUpdateModelStarAdd; public void UpdateModelInfo(HB119_tagSCModelInfo vNetData) { if (vNetData == null) return; PhantasmPavilionType type = PhantasmPavilionType.Model; if (!dataDict.ContainsKey(type)) { dataDict.Add(type, new Dictionary()); } // 判断当前封包是否有任何一项的星级大于之前的星级 bool hasStarIncreased = false; foreach (var item in vNetData.ModelList) { if (dataDict[type].ContainsKey((int)item.ModelID)) { var oldData = dataDict[type][(int)item.ModelID]; if (item.Star > oldData.Star) { hasStarIncreased = true; break; } } } foreach (var item in vNetData.ModelList) { if (!dataDict[type].ContainsKey((int)item.ModelID)) { dataDict[type][(int)item.ModelID] = new PhantasmPavilionData(); } var data = dataDict[type][(int)item.ModelID]; data.ID = item.ModelID; data.State = item.State == 1; data.EndTime = item.EndTime; data.Star = item.Star; } RefreshAttr(); UpdateRedPoint(); if (hasStarIncreased) { OnUpdateModelStarAdd?.Invoke(); } OnUpdateModelInfoEvent?.Invoke(); } public void UpdateTitleInfo(HB126_tagSCTitleInfo vNetData) { if (vNetData == null) return; PhantasmPavilionType type = PhantasmPavilionType.Title; if (!dataDict.ContainsKey(type)) { dataDict.Add(type, new Dictionary()); } foreach (var item in vNetData.TitleList) { if (!dataDict[type].ContainsKey((int)item.TitleID)) { dataDict[type][(int)item.TitleID] = new PhantasmPavilionData(); } var data = dataDict[type][(int)item.TitleID]; data.ID = item.TitleID; data.State = item.State == 1; data.EndTime = item.EndTime; data.Star = item.Star; } RefreshAttr(); UpdateRedPoint(); OnUpdateTitleInfoEvent?.Invoke(); } public void UpdateChatBoxInfo(HB127_tagSCChatBoxInfo vNetData) { if (vNetData == null) return; PhantasmPavilionType type = PhantasmPavilionType.ChatBox; if (!dataDict.ContainsKey(type)) { dataDict.Add(type, new Dictionary()); } foreach (var item in vNetData.BoxList) { if (!dataDict[type].ContainsKey((int)item.BoxID)) { dataDict[type][(int)item.BoxID] = new PhantasmPavilionData(); } var data = dataDict[type][(int)item.BoxID]; data.ID = item.BoxID; data.State = item.State == 1; data.EndTime = item.EndTime; data.Star = item.Star; } RefreshAttr(); UpdateRedPoint(); OnUpdateChatBoxInfoEvent?.Invoke(); } public void UpdateFaceInfo(HB117_tagMCFaceInfo vNetData) { if (vNetData == null) return; PhantasmPavilionType type = PhantasmPavilionType.Face; if (!dataDict.ContainsKey(type)) { dataDict.Add(type, new Dictionary()); } foreach (var item in vNetData.FaceList) { if (!dataDict[type].ContainsKey((int)item.FaceID)) { dataDict[type][(int)item.FaceID] = new PhantasmPavilionData(); } var data = dataDict[type][(int)item.FaceID]; data.ID = item.FaceID; data.State = item.State == 1; data.EndTime = item.EndTime; data.Star = item.Star; } RefreshAttr(); UpdateRedPoint(); OnUpdateFaceInfoEvent?.Invoke(); } public void UpdateFacePicInfo(HB118_tagMCFacePicInfo vNetData) { if (vNetData == null) return; PhantasmPavilionType type = PhantasmPavilionType.FacePic; if (!dataDict.ContainsKey(type)) { dataDict.Add(type, new Dictionary()); } foreach (var item in vNetData.FacePicList) { if (!dataDict[type].ContainsKey((int)item.FacePicID)) { dataDict[type][(int)item.FacePicID] = new PhantasmPavilionData(); } var data = dataDict[type][(int)item.FacePicID]; data.ID = item.FacePicID; data.State = item.State == 1; data.EndTime = item.EndTime; data.Star = item.Star; } RefreshAttr(); UpdateRedPoint(); OnUpdateFacePicInfo?.Invoke(); } #endregion public void SendOPPack(PhantasmPavilionType type, PhantasmPavilionOperation op, uint opID) { SendB225Pack((byte)type, (byte)op, opID); } public void SendB225Pack(byte type, byte opType, uint opID) { var pack = new CB225_tagCSHJGOP(); pack.Type = type; // 类型 1-形象;2-头像;3-头像框;4-气泡;5-称号 pack.OPType = opType; // 操作 1-激活;2-佩戴;3-卸下;4-升星 pack.OPID = opID; // 操作对应的ID,如形象ID等 GameNetSystem.Instance.SendInfo(pack); } } public class PhantasmPavilionData { public uint ID; //ID public bool State; //是否已激活 public uint EndTime; //到期时间戳,0为永久 public byte Star; //星级 } //对应发包 1-形象;2-头像;3-头像框;4-气泡;5-称号 public enum PhantasmPavilionType { Model = 1, // 形象 Face, // 头像 FacePic, // 头像框 ChatBox, // 聊天气泡 Title, //称号 } //对应发包 1-激活;2-佩戴;3-卸下;4-升星 public enum PhantasmPavilionOperation { Activate = 1, // 激活 Wear, // 佩戴 Remove, // 卸下 UpgradeStar, // 升星 } public enum PhantasmPavilionUnlockWay { Activate = 1, // 默认(创角色就可以用的) Item, // 道具 Hero, // 武将 } /// 幻境阁物品的状态 public enum PhantasmPavilionState { // 未激活 (0) Locked = 0, // 可激活 (1) - 满足激活条件,但尚未激活 CanActivate = 1, //已激活 (2) - 已激活且未过期 Activated = 2 }