| using System.Collections.Generic; | 
| using UnityEngine; | 
| using LitJson; | 
| using System; | 
|   | 
| public class ArenaManager : GameSystemManager<ArenaManager> | 
| { | 
|     public readonly int rankType = 1;    // 榜单类型 | 
|     public readonly int funcId = 27;    // 功能Id | 
|     public readonly int DeployTroopsFuncId = 31;    // 布阵功能ID | 
|     public readonly int BattleChangeTabFuncId = 32; // 战斗能切换页签功能ID | 
|     public readonly int recType = 308;  // 演武场玩家挑战记录类型 308 | 
|     public readonly int ChallengeMoneyType = 53; | 
|     public readonly int NeedChallengeMoneyCnt = 1; | 
|     public readonly int RecordType = 308;   // 演武场玩家挑战记录 | 
|     public int initialPoints;   // 玩家初始积分 | 
|     public int challengeRecordCount;    // 被挑战记录条数(不超过50) | 
|     public int challengeTicketLimit;    // 挑战券基础存储上限 | 
|     public int[][] fixedChallengeRewards;   // 固定挑战奖励 [[物品ID,个数], ...] | 
|     public int[][] matchVictoryPoints;  // 匹配位置挑战胜利对应增减积分 [[挑战方增加积分, 防守方扣除积分], ...],长度即为匹配的人数,从最高分开始配置 | 
|     public int lowerRankStart;  // 从比自己低几个段的名次开始匹配 | 
|     public int rankStep;    // 每个匹配段跨x名,如配置 2|10,即代表从自己名次向后20名开始匹配,每跨10名匹配1人 | 
|     public Dictionary<int, int[]> robotMatchCounts; // 玩家所在小于等于该名次对应匹配机器人数 {名次:[匹配机器人数下限, 上限], ...} | 
|     public int currencyType;    // 刷新匹配固定消耗货币类型 | 
|     public int currencyValue;   // 刷新匹配固定消耗货币值 | 
|     public Dictionary<int, int[][]> dailyRankRewards; // 每日排行奖励 {"名次":[[物品ID, 个数,是否拍品], ...], ...} 配置的名次key,自动按小于等于对应名次给奖励 | 
|     public Dictionary<int, int[][]> seasonRankRewards;  // 赛季排行奖励 {"名次":[[物品ID, 个数,是否拍品], ...], ...} | 
|   | 
|     public uint score;    // 当前积分 | 
|   | 
|     public List<ArenaMatchInfo> matchInfoList = new List<ArenaMatchInfo>(); | 
|     //用于用来拿战斗胜利失败的头像信息 | 
|     public Dictionary<uint, ArenaMatchInfo> allFaceInfoDict = new Dictionary<uint, ArenaMatchInfo>(); | 
|     public Dictionary<uint, List<ArenaGameRec>> gameRecDict = new Dictionary<uint, List<ArenaGameRec>>(); // <RecID,ArenaGameRec> | 
|     public uint atkPlayerId; | 
|     public Redpoint parentRedpoint = new Redpoint(MainRedDot.MainChallengeRedpoint, MainRedDot.ArenaRepoint); | 
|     public Redpoint challengeButtonRedpoint; | 
|     public int nowAwardTabIndex = 0; | 
|     public event Action OnArenaMatchListEvent; | 
|     public event Action OnUpdateArenaPlayerInfo; | 
|     public event Action OnUpdateGameRecInfo; | 
|     public override void Init() | 
|     { | 
|         DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent += OnBeforePlayerDataInitializeEvent; | 
|         PlayerDatas.Instance.playerDataRefreshEvent += PlayerDataRefresh; | 
|         InitTable(); | 
|         InitRedpoint(); | 
|     } | 
|   | 
|     public override void Release() | 
|     { | 
|         DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent -= OnBeforePlayerDataInitializeEvent; | 
|         PlayerDatas.Instance.playerDataRefreshEvent -= PlayerDataRefresh; | 
|     } | 
|   | 
|     public void OnBeforePlayerDataInitializeEvent() | 
|     { | 
|         matchInfoList.Clear(); | 
|         gameRecDict.Clear(); | 
|         allFaceInfoDict.Clear(); | 
|     } | 
|   | 
|     void InitRedpoint() | 
|     { | 
|         challengeButtonRedpoint = new Redpoint(MainRedDot.ArenaRepoint, GetRedPonitId(1)); | 
|     } | 
|   | 
|     void InitTable() | 
|     { | 
|         FuncConfigConfig config = FuncConfigConfig.Get("ArenaSet"); | 
|         initialPoints = int.Parse(config.Numerical1); | 
|         challengeRecordCount = int.Parse(config.Numerical2); | 
|         challengeTicketLimit = int.Parse(config.Numerical3); | 
|         fixedChallengeRewards = JsonMapper.ToObject<int[][]>(config.Numerical4); | 
|   | 
|         config = FuncConfigConfig.Get("ArenaMatch"); | 
|         matchVictoryPoints = JsonMapper.ToObject<int[][]>(config.Numerical1); | 
|         string[] matchParams = config.Numerical2.Split('|'); | 
|         lowerRankStart = int.Parse(matchParams[0]); | 
|         rankStep = int.Parse(matchParams[1]); | 
|         robotMatchCounts = ConfigParse.GetDic<int, int[]>(config.Numerical3); | 
|         string[] costParams = config.Numerical4.Split('|'); | 
|         currencyType = int.Parse(costParams[0]); | 
|         currencyValue = int.Parse(costParams[1]); | 
|   | 
|         config = FuncConfigConfig.Get("ArenaBillboradAward"); | 
|         dailyRankRewards = ConfigParse.ParseIntArray2Dict(config.Numerical1); | 
|         seasonRankRewards = ConfigParse.ParseIntArray2Dict(config.Numerical2); | 
|     } | 
|     public void UpdateRedPonit() | 
|     { | 
|         parentRedpoint.state = RedPointState.None; | 
|         challengeButtonRedpoint.state = RedPointState.None; | 
|   | 
|         if (!FuncOpen.Instance.IsFuncOpen(funcId)) | 
|             return; | 
|   | 
|         if (UIHelper.GetMoneyCnt(ChallengeMoneyType) > 0) | 
|         { | 
|             challengeButtonRedpoint.state = RedPointState.Simple; | 
|         } | 
|     } | 
|   | 
|     public bool TryGetPlayerInfo(uint playerID, out ArenaMatchInfo info) | 
|     { | 
|         return allFaceInfoDict.TryGetValue(playerID, out info); | 
|     } | 
|   | 
|     // 1 挑战按钮 | 
|     public int GetRedPonitId(int num) | 
|     { | 
|         return MainRedDot.ArenaRepoint * 10 + num; | 
|     } | 
|   | 
|     private void PlayerDataRefresh(PlayerDataType type) | 
|     { | 
|         if (type != PlayerDataType.ChallengeVoucher) | 
|             return; | 
|         UpdateRedPonit(); | 
|     } | 
|   | 
|     public int GetMaxChallengeCount() | 
|     { | 
|         return challengeTicketLimit; | 
|     } | 
|   | 
|     public void OnArenaMatchList(HA922_tagSCArenaMatchList vNetData) | 
|     { | 
|         if (vNetData == null || vNetData.MatchList.IsNullOrEmpty()) | 
|             return; | 
|   | 
|         matchInfoList.Clear(); | 
|   | 
|         foreach (var item in vNetData.MatchList) | 
|         { | 
|             var matchInfo = new ArenaMatchInfo | 
|             { | 
|                 PlayerID = item.PlayerID, | 
|                 PlayerName = item.PlayerName, | 
|                 Lv = item.LV, | 
|                 RealmLV = item.RealmLV, | 
|                 FightPower = (ulong)item.FightPowerEx * 100000000 + (ulong)item.FightPower, | 
|                 Face = item.Face, | 
|                 FacePic = item.FacePic | 
|             }; | 
|             matchInfoList.Add(matchInfo); | 
|             allFaceInfoDict[item.PlayerID] = matchInfo; | 
|         } | 
|         matchInfoList.Reverse(); | 
|         OnArenaMatchListEvent?.Invoke(); | 
|     } | 
|   | 
|   | 
|     public void UpdateArenaPlayerInfo(HA923_tagSCArenaPlayerInfo vNetData) | 
|     { | 
|         if (vNetData == null) | 
|             return; | 
|         this.score = vNetData.Score; | 
|         OnUpdateArenaPlayerInfo?.Invoke(); | 
|     } | 
|     public void UpdateGameRecInfo(HA009_tagSCGameRecInfo vNetData) | 
|     { | 
|         if (vNetData == null || vNetData.RecType != recType) | 
|             return; | 
|         gameRecDict.Clear(); | 
|         uint recID = vNetData.RecID; | 
|         if (!gameRecDict.ContainsKey(recID)) | 
|             gameRecDict[recID] = new List<ArenaGameRec>(); | 
|         foreach (var rec in vNetData.RecList) | 
|         { | 
|             try | 
|             { | 
|                 var userData = JsonMapper.ToObject(rec.UserData); | 
|                 string name = userData["Name"].ToString(); | 
|                 int addScore = int.Parse(userData["AddScore"].ToString()); | 
|                 ulong fightPower = ulong.Parse(userData["FightPower"].ToString()); | 
|   | 
|                 var arenaGameRec = new ArenaGameRec | 
|                 { | 
|                     Time = rec.Time, | 
|                     Value1 = rec.Value1, | 
|                     Value2 = rec.Value2, | 
|                     Value3 = rec.Value3, | 
|                     Value4 = rec.Value4, | 
|                     Value5 = rec.Value5, | 
|                     Value6 = rec.Value6, | 
|                     Value7 = rec.Value7, | 
|                     Value8 = rec.Value8, | 
|                     Name = name, | 
|                     AddScore = addScore, | 
|                     FightPower = fightPower | 
|                 }; | 
|   | 
|                 gameRecDict[recID].Add(arenaGameRec); | 
|   | 
|                 if (recID == PlayerDatas.Instance.baseData.PlayerID) | 
|                 { | 
|                     allFaceInfoDict[rec.Value3] = new ArenaMatchInfo | 
|                     { | 
|                         Face = rec.Value5, | 
|                         FacePic = rec.Value6, | 
|                         RealmLV = (ushort)rec.Value7, | 
|                         Lv = (ushort)rec.Value8, | 
|                         PlayerName = name, | 
|                         FightPower = fightPower, | 
|                     }; | 
|                 } | 
|   | 
|             } | 
|             catch (Exception ex) | 
|             { | 
|                 Debug.LogError($"JSON解析错误: {ex.Message}, UserData: {rec.UserData}"); | 
|                 continue; | 
|             } | 
|         } | 
|         OnUpdateGameRecInfo?.Invoke(); | 
|     } | 
|   | 
|   | 
|     public Dictionary<int, int[][]> GetArenaAwardDict(int functionOrder) | 
|     { | 
|         return functionOrder == 0 ? dailyRankRewards : seasonRankRewards; | 
|     } | 
|   | 
|     public void SendViewGameRecPack() | 
|     { | 
|         CA008_tagCSViewGameRec pack = new CA008_tagCSViewGameRec(); | 
|         pack.RecType = (ushort)RecordType; | 
|         GameNetSystem.Instance.SendInfo(pack); | 
|     } | 
|   | 
|     public void SendArenaMatch(bool isRefresh = false) | 
|     { | 
|         CB209_tagCSArenaMatch pack = new CB209_tagCSArenaMatch(); | 
|         pack.IsRefresh = isRefresh ? (byte)1 : (byte)0; | 
|         GameNetSystem.Instance.SendInfo(pack); | 
|     } | 
|   | 
|     public void SendTurnFight(uint playerID) | 
|     { | 
|         CB410_tagCMTurnFight pack = new CB410_tagCMTurnFight(); | 
|         pack.MapID = 3; | 
|         pack.TagType = 1; | 
|         pack.TagID = playerID; | 
|         GameNetSystem.Instance.SendInfo(pack); | 
|     } | 
|   | 
|     public bool IsTimeInvalid(uint time) | 
|     { | 
|         DateTime dateTime = TimeUtility.GetTime(time); | 
|         GetCurrentSeasonDates(out DateTime seasonStartDate, out DateTime seasonEndDate); | 
|         return dateTime < seasonStartDate || dateTime > seasonEndDate; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 根据索引和排序方向获取积分 | 
|     /// </summary> | 
|     /// <param name="index">索引位置(从0开始)</param> | 
|     /// <param name="isAscending">true-正序,false-倒序</param> | 
|     /// <param name="isChallenger">true-挑战方增加积分,false-防守方扣除积分</param> | 
|     /// <returns>对应的积分值</returns> | 
|     public int GetChallengePoints(int index, bool isAscending = false, bool isChallenger = true) | 
|     { | 
|         // 检查索引是否在有效范围内 | 
|         if (matchVictoryPoints.IsNullOrEmpty() || index < 0 || index >= matchVictoryPoints.Length) | 
|             return 0; | 
|         int targetIndex = isAscending ? index : matchVictoryPoints.Length - 1 - index; | 
|         return matchVictoryPoints[targetIndex][isChallenger ? 0 : 1]; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 获得当前赛季的起止日期。赛季从周一 00:00:00 开始,到周日 23:59:59 结束。 | 
|     /// 服务端定义周一为每周的第一天。 | 
|     /// </summary> | 
|     /// <param name="seasonStartDate">输出参数:赛季的起始日期(本周一 00:00:00)</param> | 
|     /// <param name="seasonEndDate">输出参数:赛季的结束日期(本周日 23:59:59)</param> | 
|     public void GetCurrentSeasonDates(out DateTime seasonStartDate, out DateTime seasonEndDate) | 
|     { | 
|         DateTime now = TimeUtility.ServerNow; | 
|         // 在 .NET 中,DayOfWeek 枚举 Sunday = 0, Monday = 1, ..., Saturday = 6。 | 
|         // 为了符合周一是一周第一天的计算标准,我们将周日视为一周的第7天。 | 
|         int currentDayOfWeek = (int)now.DayOfWeek; | 
|         if (currentDayOfWeek == 0) // 如果是周日 (Sunday = 0) | 
|         { | 
|             currentDayOfWeek = 7; | 
|         } | 
|   | 
|         // 从当前日期减去相应的天数,得到周一的日期。 | 
|         // 例如,如果是周三(3),则需要减去 3-1=2 天。 | 
|         // 如果是周日(7),则需要减去 7-1=6 天。 | 
|         DateTime monday = now.AddDays(-(currentDayOfWeek - 1)); | 
|         // 设置赛季的起始时间为周一的 0点0分0秒 | 
|         seasonStartDate = new DateTime(monday.Year, monday.Month, monday.Day, 0, 0, 0); | 
|         // 赛季的结束日期是开始日期(周一)加上6天,即周日 | 
|         DateTime sunday = seasonStartDate.AddDays(6); | 
|         // 设置赛季的结束时间为周日的 23点59分59秒 | 
|         seasonEndDate = new DateTime(sunday.Year, sunday.Month, sunday.Day, 23, 59, 59); | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 根据recID获取按时间从大到小排序的List<ArenaGameRec> | 
|     /// </summary> | 
|     /// <param name="recID">记录ID</param> | 
|     /// <param name="sortedList">输出参数:按时间从大到小排序的ArenaGameRec列表</param> | 
|     /// <returns>如果recID存在且成功获取列表返回true,否则返回false</returns> | 
|     public bool TryGetSortedArenaGameRecList(uint recID, out List<ArenaGameRec> sortedList) | 
|     { | 
|         sortedList = null; | 
|         if (!gameRecDict.ContainsKey(recID)) | 
|             return false; | 
|         sortedList = new List<ArenaGameRec>(gameRecDict[recID]); | 
|         sortedList.Sort((a, b) => b.Time.CompareTo(a.Time)); // 按时间从大到小排序 | 
|         return true; | 
|     } | 
| } | 
|   | 
|   | 
|   | 
|   | 
| public class ArenaMatchInfo | 
| { | 
|     public uint PlayerID;        //目标玩家ID | 
|     public string PlayerName; | 
|     public ushort Lv;             //等级 | 
|     public ushort RealmLV;        //境界,机器人读境界表取等级对应境界 | 
|     public uint TitleID; | 
|     public ulong FightPower;        //战力 | 
|     public uint Face;        //基本脸型 | 
|     public uint FacePic;        //头像框 | 
|   | 
| } | 
|   | 
| public class ArenaGameRec | 
| { | 
|     public uint Time;        //战斗时间戳 | 
|     public uint Value1;        //更新积分,战斗后的最终积分 | 
|     public uint Value2;        //攻击类型 1-发起攻击的,2-被攻击的 | 
|     public uint Value3;        //相对攻击类型的目标玩家ID | 
|     public uint Value4;        //是否获胜 1-获胜;2-失败 | 
|     public uint Value5;        //目标头像 | 
|     public uint Value6;        //目标头像框 | 
|     public uint Value7;        //目标官职 | 
|     public uint Value8;        //目标等级 | 
|     public string Name;         //目标名称 | 
|     public int AddScore;        //本次自己变更的积分,有正负 | 
|     public ulong FightPower;    //目标战力 | 
|     public int TitileId; //未来接入 | 
|   | 
| } |