| using System; | 
| using System.Collections.Generic; | 
| using UnityEngine; | 
|   | 
| public class FirstChargeManager : GameSystemManager<FirstChargeManager> | 
| { | 
|     public const int FuncID = 21; | 
|     public int mainItemId { get { return GetMainItemId(); } } | 
|     public int heroItemID; | 
|     public int maxGiftCount | 
|     { | 
|         get | 
|         { | 
|             var list = FirstChargeConfig.GetKeys(); | 
|             return list.IsNullOrEmpty() ? 0 : list.Count; | 
|         } | 
|     } | 
|     public int maxDay = 3; | 
|     public Redpoint parentRedpoint = new Redpoint(MainRedDot.FirstChargeRepoint); | 
|   | 
|     public Dictionary<int, Redpoint> tabRedpointDict = new Dictionary<int, Redpoint>(); | 
|     public Dictionary<int, bool> clickTabDict = new Dictionary<int, bool>(); | 
|     public Dictionary<int, FirstChargeData> firstChargeInfoDict = new Dictionary<int, FirstChargeData>(); | 
|     public event Action OnUpdateFirstChargeInfo; | 
|     public override void Init() | 
|     { | 
|         DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent += OnBeforePlayerDataInitializeEvent; | 
|         DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent += OnPlayerLoginOk; | 
|         RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent; | 
|         FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent; | 
|         InitClickTabDict(); | 
|         InitRedPoint(); | 
|     } | 
|   | 
|     public override void Release() | 
|     { | 
|         DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent -= OnBeforePlayerDataInitializeEvent; | 
|         DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent -= OnPlayerLoginOk; | 
|         RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent; | 
|         FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent; | 
|     } | 
|   | 
|     private void OnFuncStateChangeEvent(int obj) | 
|     { | 
|         if (FuncID == obj) | 
|         { | 
|             string key = $"FirstCharge_FirstTime_{FuncID}_{PlayerDatas.Instance.baseData.PlayerID}"; | 
|             if (!LocalSave.HasKey(key)) | 
|             { | 
|                 // 第一次开启功能 | 
|                 LocalSave.SetBool(key, true); | 
|                 PopupWindowsProcessor.Instance.Add("FirstChargeWin"); | 
|             } | 
|         } | 
|     } | 
|   | 
|     public void InitClickTabDict() | 
|     { | 
|         var list = FirstChargeConfig.GetKeys(); | 
|         if (!list.IsNullOrEmpty()) | 
|         { | 
|             for (int i = 0; i < list.Count; i++) | 
|             { | 
|                 int firstId = list[i]; | 
|                 clickTabDict[firstId] = false; | 
|             } | 
|         } | 
|     } | 
|     public bool GetClickTabState(int fristId) | 
|     { | 
|         return clickTabDict.ContainsKey(fristId) && clickTabDict[fristId]; | 
|     } | 
|     public void SetClickTabState(int fristId) | 
|     { | 
|         clickTabDict[fristId] = true; | 
|         UpdateRedPoint(); | 
|     } | 
|   | 
|     public void InitRedPoint() | 
|     { | 
|         var list = FirstChargeConfig.GetKeys(); | 
|         if (!list.IsNullOrEmpty()) | 
|         { | 
|             for (int i = 0; i < list.Count; i++) | 
|             { | 
|                 int firstId = list[i]; | 
|                 int redpointId = GetRedpointIdByFirstId(firstId); | 
|                 tabRedpointDict[firstId] = new Redpoint(MainRedDot.FirstChargeRepoint, redpointId); | 
|             } | 
|         } | 
|   | 
|     } | 
|   | 
|     public int GetRedpointIdByFirstId(int firstId) | 
|     { | 
|         return MainRedDot.FirstChargeRepoint * 10000 + firstId; | 
|     } | 
|   | 
|     private void OnRechargeCountEvent(int obj) | 
|     { | 
|         var list = FirstChargeConfig.GetCtgIDList(); | 
|         if (!list.IsNullOrEmpty() && list.Contains(obj)) | 
|         { | 
|             UpdateRedPoint(); | 
|         } | 
|     } | 
|   | 
|     public void OnBeforePlayerDataInitializeEvent() | 
|     { | 
|         firstChargeInfoDict.Clear(); | 
|     } | 
|   | 
|     public void OnPlayerLoginOk() | 
|     { | 
|         if (FuncOpen.Instance.IsFuncOpen(FuncID) && TryGetUnBuyFirstId(out int firstId)) | 
|         { | 
|             PopupWindowsProcessor.Instance.Add("FirstChargeWin"); | 
|         } | 
|     } | 
|   | 
|     public bool TryGetFirstChargeDataByFirstId(int firstId, out FirstChargeData firstChargeData) | 
|     { | 
|         return firstChargeInfoDict.TryGetValue(firstId, out firstChargeData); | 
|     } | 
|   | 
|     public bool TryGetUnBuyFirstId(out int firstId) | 
|     { | 
|         firstId = 0; | 
|         var firstChargeList = FirstChargeConfig.GetKeys(); | 
|         if (firstChargeList != null) | 
|         { | 
|             firstChargeList.Sort(); | 
|             foreach (int item in firstChargeList) | 
|             { | 
|                 if (TryGetFirstChargeDataByFirstId(item, out FirstChargeData data)) | 
|                 { | 
|                     if (data.IsUnlock() && !data.IsBuy()) | 
|                     { | 
|                         firstId = item; | 
|                         return true; | 
|                     } | 
|                 } | 
|   | 
|             } | 
|         } | 
|         return false; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 根据标签页索引获取对应的首充ID | 
|     /// </summary> | 
|     /// <param name="tabIndex">标签页索引,从0开始</param> | 
|     /// <returns>对应的首充ID,从1开始</returns> | 
|     public int GetFirstIDByTabIndex(int tabIndex) | 
|     { | 
|         return tabIndex + 1; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 根据首充ID获取对应的标签页索引 | 
|     /// </summary> | 
|     /// <param name="firstId">首充ID,从1开始</param> | 
|     /// <returns>对应的标签页索引,从0开始</returns> | 
|     public int GetTabIndexByFirstID(int firstId) | 
|     { | 
|         return Math.Max(firstId - 1, 0); | 
|     } | 
|   | 
|     public int GetLastFirstIDByTabIndex(int tabIndex) | 
|     { | 
|         return GetFirstIDByTabIndex(tabIndex == 0 ? tabIndex : tabIndex - 1); | 
|     } | 
|     public int GetNextFirstIDByTabIndex(int tabIndex) | 
|     { | 
|         return GetFirstIDByTabIndex(tabIndex >= maxGiftCount - 1 ? maxGiftCount - 1 : tabIndex + 1); | 
|     } | 
|     public int GetLastFirstIDByFirstID(int firstId) | 
|     { | 
|         int tabIndex = GetTabIndexByFirstID(firstId); | 
|         return GetLastFirstIDByTabIndex(tabIndex); | 
|     } | 
|     public int GetNextFirstIDByFirstID(int firstId) | 
|     { | 
|         int tabIndex = GetTabIndexByFirstID(firstId); | 
|         return GetNextFirstIDByTabIndex(tabIndex); | 
|     } | 
|   | 
|     public bool TryGetFirstChargeConfigByFirstID(int firstId, out FirstChargeConfig firstChargeConfig) | 
|     { | 
|         firstChargeConfig = null; | 
|         if (!FirstChargeConfig.HasKey(firstId)) | 
|             return false; | 
|         firstChargeConfig = FirstChargeConfig.Get(firstId); | 
|         return true; | 
|     } | 
|   | 
|     public bool TryGetOrderInfoConfigByFirstID(int firstId, out OrderInfoConfig orderInfoConfig) | 
|     { | 
|         orderInfoConfig = null; | 
|         if (!TryGetFirstChargeConfigByFirstID(firstId, out FirstChargeConfig firstChargeConfig)) | 
|             return false; | 
|         int ctgId = firstChargeConfig.CTGID; | 
|         return RechargeManager.Instance.TryGetOrderInfo(ctgId, out orderInfoConfig); | 
|     } | 
|   | 
|     public bool TryGetCTGConfigByFirstID(int firstId, out CTGConfig ctgConfig) | 
|     { | 
|         ctgConfig = null; | 
|         if (!TryGetFirstChargeConfigByFirstID(firstId, out FirstChargeConfig firstChargeConfig)) | 
|             return false; | 
|         int ctgId = firstChargeConfig.CTGID; | 
|         if (!CTGConfig.HasKey(ctgId)) | 
|             return false; | 
|         ctgConfig = CTGConfig.Get(ctgId); | 
|         return true; | 
|     } | 
|     public int GetMainItemId() | 
|     { | 
|         var list = FirstChargeConfig.GetKeys(); | 
|         list.Sort(); | 
|         var config = FirstChargeConfig.Get(list[0]); | 
|         for (int i = 0; i < config.AwardListDay1.Length; i++) | 
|         { | 
|             int itemId = config.AwardListDay1[i][0]; | 
|             if (!ItemConfig.HasKey(itemId)) | 
|                 continue; | 
|             if (ItemConfig.Get(itemId).Type == 150) | 
|             { | 
|                 return itemId; | 
|             } | 
|         } | 
|         return 0; | 
|     } | 
|   | 
|     public void UpdateFirstChargeInfo(HAA02_tagSCFirstChargeInfo vNetData) | 
|     { | 
|         if (vNetData.FirstChargeList.IsNullOrEmpty()) | 
|             return; | 
|         foreach (var chargeInfo in vNetData.FirstChargeList) | 
|         { | 
|             int firstID = chargeInfo.FirstID; | 
|             if (!firstChargeInfoDict.TryGetValue(firstID, out var firstChargeData)) | 
|             { | 
|                 firstChargeData = new FirstChargeData(); | 
|                 firstChargeInfoDict[firstID] = firstChargeData; | 
|             } | 
|             firstChargeData.FirstID = firstID; | 
|             firstChargeData.ChargeTime = chargeInfo.ChargeTime; | 
|             firstChargeData.AwardRecord = chargeInfo.AwardRecord; | 
|         } | 
|         // 检查是否所有奖励都已领取,如果是,则记录当前服务器时间到本地 | 
|         CheckAndSaveAllRewardsClaimedTime(); | 
|         UpdateRedPoint(); | 
|         OnUpdateFirstChargeInfo?.Invoke(); | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 检查是否所有首充奖励都已领取,如果是,则将当前服务器时间保存到本地 | 
|     /// </summary> | 
|     private void CheckAndSaveAllRewardsClaimedTime() | 
|     { | 
|         // 检查是否所有奖励都已领取 | 
|         if (IsAllFirstChargeRewardsClaimed()) | 
|         { | 
|             // 生成一个唯一的键来存储时间 | 
|             string key = $"FirstCharge_AllRewardsClaimed_Time_{PlayerDatas.Instance.baseData.PlayerID}"; | 
|             // 将当前服务器时间保存到本地 | 
|             LocalSave.SetString(key, TimeUtility.ServerNow.Ticks.ToString()); | 
|         } | 
|     } | 
|     public void UpdateRedPoint() | 
|     { | 
|         // 重置所有红点状态 | 
|         parentRedpoint.state = RedPointState.None; | 
|         foreach (var redpoint in tabRedpointDict.Values) | 
|         { | 
|             redpoint.state = RedPointState.None; | 
|         } | 
|   | 
|         var firstChargeList = FirstChargeConfig.GetKeys(); | 
|         if (firstChargeList.IsNullOrEmpty()) | 
|             return; | 
|         firstChargeList.Sort(); | 
|         foreach (int firstId in firstChargeList) | 
|         { | 
|             if (!tabRedpointDict.ContainsKey(firstId)) | 
|                 continue; | 
|             var redpoint = tabRedpointDict[firstId]; | 
|   | 
|             if (TryGetFirstChargeDataByFirstId(firstId, out var firstChargeData)) | 
|             { | 
|                 if (firstChargeData.IsBuy()) | 
|                 { | 
|                     for (int day = 1; day <= maxDay; day++) | 
|                     { | 
|                         int awardState = firstChargeData.GetHaveState(day); | 
|                         // 2: 可领取 | 
|                         if (awardState == 2) | 
|                         { | 
|                             redpoint.state = RedPointState.Simple; | 
|                             break; | 
|                         } | 
|                     } | 
|                 } | 
|                 else | 
|                 { | 
|                     bool clickTabState = GetClickTabState(firstId); | 
|                     if (firstChargeData.IsUnlock() && !clickTabState) | 
|                     { | 
|                         redpoint.state = RedPointState.Simple; | 
|                     } | 
|                 } | 
|             } | 
|   | 
|   | 
|         } | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 发送领取首充奖励请求 | 
|     /// </summary> | 
|     /// <param name="day">要领取的奖励是第x天的, 从1开始</param> | 
|     /// <param name="firstID">首充表的ID</param> | 
|     public void SendGetReward(int day, int firstID) | 
|     { | 
|         var pack = new CA504_tagCMPlayerGetReward(); | 
|         pack.RewardType = 8; | 
|         pack.DataEx = (uint)day;//第x天,1代表第1天 | 
|         string firstIdStr = firstID.ToString();//领取哪个首充ID,对应首充表的ID | 
|         pack.DataExStr = firstIdStr; | 
|         pack.DataExStrLen = (byte)firstIdStr.Length; | 
|         GameNetSystem.Instance.SendInfo(pack); | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 自动领取玩家可以领取的所有首充奖励 | 
|     /// </summary> | 
|     /// <param name="firstID">首充表的ID</param> | 
|     public void AutoClaimAllRewards(int firstID) | 
|     { | 
|         if (!TryGetFirstChargeDataByFirstId(firstID, out var firstChargeData)) | 
|             return; | 
|         if (!firstChargeData.IsBuy()) | 
|             return; | 
|         // 获取当前是购买后的第几天 | 
|         int currentDay = firstChargeData.GetNowBuyDay(); | 
|         // 遍历从第1天到当前天数的所有奖励 | 
|         for (int day = 1; day <= maxDay; day++) | 
|         { | 
|             // 检查奖励状态,只有状态为已购买没领取才发送领取请求 | 
|             if (day <= currentDay && firstChargeData.GetHaveState(day) == 2)//0: 已领取 1: 不可领取 2: 可领取  | 
|             { | 
|                 SendGetReward(day, firstID); | 
|             } | 
|         } | 
|     } | 
|   | 
|     // 检查是否所有首充奖励都已经领取 | 
|     public bool IsAllFirstChargeRewardsClaimed() | 
|     { | 
|         // 获取所有首充配置ID | 
|         var firstChargeIds = FirstChargeConfig.GetKeys(); | 
|         if (firstChargeIds == null || firstChargeIds.Count == 0) | 
|             return false; | 
|   | 
|         foreach (var firstId in firstChargeIds) | 
|         { | 
|             // 尝试获取首充数据 | 
|             if (!TryGetFirstChargeDataByFirstId(firstId, out var firstChargeData)) | 
|                 return false; | 
|   | 
|             // 检查是否购买 | 
|             if (!firstChargeData.IsBuy()) | 
|                 return false; | 
|   | 
|             // 检查是否所有奖励都已领取 | 
|             if (!firstChargeData.IsAllHave()) | 
|                 return false; | 
|         } | 
|   | 
|         // 所有首充档位都已购买且所有奖励都已领取 | 
|         // 检查是否已经过了第二天0点 | 
|         return true; | 
|     } | 
|   | 
|     // 检查是否已经过了所有奖励领取完毕后的第二天0点 | 
|     public bool IsNextDayAfterAllClaimed() | 
|     { | 
|         // 生成一个唯一的键来获取时间 | 
|         string key = $"FirstCharge_AllRewardsClaimed_Time_{PlayerDatas.Instance.baseData.PlayerID}"; | 
|   | 
|         // 检查是否存在记录的时间戳 | 
|         if (!LocalSave.HasKey(key)) | 
|             return false; | 
|   | 
|         // 获取记录的时间戳 | 
|         string timeString = LocalSave.GetString(key); | 
|         if (string.IsNullOrEmpty(timeString)) | 
|             return false; | 
|   | 
|         // 解析时间戳 | 
|         if (!long.TryParse(timeString, out long ticks)) | 
|             return false; | 
|   | 
|         // 将时间戳转换为DateTime | 
|         DateTime allRewardsClaimedTime = new DateTime(ticks); | 
|   | 
|         // 计算第二天0点的时间 | 
|         DateTime nextDayStart = allRewardsClaimedTime.Date.AddDays(1); | 
|   | 
|         // 判断当前服务器时间是否已经过了第二天0点 | 
|         DateTime serverNow = TimeUtility.ServerNow; | 
|         return serverNow >= nextDayStart; | 
|     } | 
|   | 
| } | 
| public class FirstChargeData | 
| { | 
|     public int FirstID;        //首充ID | 
|     public uint ChargeTime;        //充值该首充的时间戳 | 
|     public ushort AwardRecord;        //首充奖励领奖记录,按二进制位记录首充第X天是否已领取(第1天对应第1位) | 
|   | 
|     public bool IsUnlock() | 
|     { | 
|         int tabIndex = FirstChargeManager.Instance.GetTabIndexByFirstID(FirstID); | 
|         if (tabIndex == 0) | 
|             return true; | 
|         int lastFirstID = FirstChargeManager.Instance.GetLastFirstIDByTabIndex(tabIndex); | 
|         FirstChargeData firstChargeDataNow; | 
|         if (!FirstChargeManager.Instance.TryGetFirstChargeDataByFirstId(lastFirstID, out firstChargeDataNow)) | 
|             return false; | 
|         return firstChargeDataNow.IsBuy(); | 
|     } | 
|   | 
|     public bool IsBuy() | 
|     { | 
|         return ChargeTime > 0; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 检查指定天的奖励是否已领取 | 
|     /// </summary> | 
|     /// <param name="day">天数,从1开始</param> | 
|     public bool IsHave(int day) | 
|     { | 
|         bool res = (AwardRecord & (1 << day)) != 0; | 
|         return res; | 
|     } | 
|   | 
|     public bool IsAllHave() | 
|     { | 
|         int maxGiftCount = FirstChargeManager.Instance.maxGiftCount; | 
|         for (int i = 1; i <= maxGiftCount; i++) | 
|         { | 
|             if (!IsHave(i)) | 
|                 return false; | 
|         } | 
|         return true; | 
|     } | 
|   | 
|     // ... existing code ... | 
|     /// <summary> | 
|     /// 获取当前时间是购买这档充值礼包的第几天 | 
|     /// 购买的当天算作第一天,第二天0点后算第二天,以此类推 | 
|     /// </summary> | 
|     /// <returns>第几天</returns> | 
|     public int GetNowBuyDay() | 
|     { | 
|         DateTime serverNow = TimeUtility.ServerNow; | 
|         DateTime chargeTime = TimeUtility.GetTime(ChargeTime); | 
|   | 
|         DateTime chargeDate = chargeTime.Date; | 
|         DateTime serverDate = serverNow.Date; | 
|   | 
|         // 计算从充值日期到当前日期的完整天数 | 
|         // 购买的当天算第一天,第二天0点后算第二天 | 
|         TimeSpan timeSpan = serverDate - chargeDate; | 
|         int days = (int)timeSpan.TotalDays + 1; // +1 因为当天算第一天 | 
|   | 
|         int maxDay = FirstChargeManager.Instance.maxDay; | 
|   | 
|         return Mathf.Min(maxDay, Mathf.Max(1, days)); | 
|     } | 
|   | 
|     public bool HasNextDay() | 
|     { | 
|         int currentDay = GetNowBuyDay(); | 
|         int maxDay = FirstChargeManager.Instance.maxDay; | 
|         return currentDay < maxDay; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 获得指定天的领取详细状态 | 
|     /// </summary> | 
|     /// <param name="day">天数,从1开始</param> | 
|     //0: 已领取 1: 不可领取 2: 可领取  | 
|     public int GetHaveState(int day) | 
|     { | 
|         if (IsHave(day)) | 
|             return 0; | 
|         int currentDay = GetNowBuyDay(); | 
|         // 检查是否可以领取(购买这档充值礼包的第一天后才可领取) | 
|         return day <= currentDay ? 2 : 1; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 返回显示距离第二天0点解锁奖励剩余时间 | 
|     /// </summary> | 
|     /// <returns>剩余时间字符串,格式:小时:分钟:秒钟</returns> | 
|     public string GetNextDayUnlockRemainingTime() | 
|     { | 
|         if (!IsBuy()) | 
|             return string.Empty; | 
|         DateTime serverNow = TimeUtility.ServerNow; | 
|         DateTime nextDayStart = serverNow.Date.AddDays(1); | 
|         TimeSpan remainingTime = nextDayStart - serverNow; | 
|         int remainingSeconds = (int)remainingTime.TotalSeconds; | 
|         return TimeUtility.SecondsToHMS(remainingSeconds); | 
|     } | 
|   | 
| } |