using System.Collections.Generic; using UnityEngine; using LitJson; using System; public class ArenaManager : GameSystemManager { public readonly int rankType = 1; // 榜单类型 public readonly int funcId = 27; // 功能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 robotMatchCounts; // 玩家所在小于等于该名次对应匹配机器人数 {名次:[匹配机器人数下限, 上限], ...} public int currencyType; // 刷新匹配固定消耗货币类型 public int currencyValue; // 刷新匹配固定消耗货币值 public Dictionary dailyRankRewards; // 每日排行奖励 {"名次":[[物品ID, 个数,是否拍品], ...], ...} 配置的名次key,自动按小于等于对应名次给奖励 public Dictionary seasonRankRewards; // 赛季排行奖励 {"名次":[[物品ID, 个数,是否拍品], ...], ...} public uint score; // 当前积分 public List matchInfoList = new List(); //用于用来拿战斗胜利失败的头像信息 public Dictionary allFaceInfoDict = new Dictionary(); public Dictionary> gameRecDict = new Dictionary>(); // 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(config.Numerical4); config = FuncConfigConfig.Get("ArenaMatch"); matchVictoryPoints = JsonMapper.ToObject(config.Numerical1); string[] matchParams = config.Numerical2.Split('|'); lowerRankStart = int.Parse(matchParams[0]); rankStep = int.Parse(matchParams[1]); robotMatchCounts = ConfigParse.GetDic(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(); 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 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; } /// /// 根据索引和排序方向获取积分 /// /// 索引位置(从0开始) /// true-正序,false-倒序 /// true-挑战方增加积分,false-防守方扣除积分 /// 对应的积分值 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]; } /// /// 获得当前赛季的起止日期。赛季从周一 00:00:00 开始,到周日 23:59:59 结束。 /// 服务端定义周一为每周的第一天。 /// /// 输出参数:赛季的起始日期(本周一 00:00:00) /// 输出参数:赛季的结束日期(本周日 23:59:59) 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); } /// /// 根据recID获取按时间从大到小排序的List /// /// 记录ID /// 输出参数:按时间从大到小排序的ArenaGameRec列表 /// 如果recID存在且成功获取列表返回true,否则返回false public bool TryGetSortedArenaGameRecList(uint recID, out List sortedList) { sortedList = null; if (!gameRecDict.ContainsKey(recID)) return false; sortedList = new List(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; //未来接入 }