using asap.core; using game; using GameCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using UniRx; using UnityEngine; public struct RodStateEvent { public int RoleID; } public partial class FishingDuelManager { public IRTService rts { get; private set; } public const string QueueName = "DuelPVP"; const string GruopKey = "PVPGroup"; public int seed; public int WeatherType { get; private set; } = 0;//0晴天 1雨天 bool hasRedFish;//0无红鱼 1有红鱼 public bool IsRobot { get; private set; } public int MachingState = 0;// 1一方准备好 2双方准备好 public int SceneState = 0;// 1一方准备好 2双方准备好 public int RodState = 0;// 1一方准备好 2双方准备好 public int GameOverState = 0;//1一方钓完 2双方钓完 public string MatchId; public List mapIDs; int InitState = 0; bool InitComplete = false; public string userIDPlayer { get; private set; } public int carAllLevelPlayer { get; private set; } //分组数据 int MaxGroup; public async Task StartMaching() { lastFish = 3; //随机地图 //等待匹配成功,或者匹配失败(机器人),开始对战 mapIDs = await GetRandmMap(); seed = new System.Random().Next(); InitState = 0; InitComplete = false; MachingState = 0; SceneState = 0; RodState = 0; GameOverState = 0; StartRT(); } public List GetGroups() { var groups = new List(); int curGroup = PlayerPrefs.GetInt(GruopKey, 0); Debug.Log("Group Cur Get :" + curGroup); if (curGroup > MaxGroup) { curGroup = 0; } if (curGroup == 0) { for (int i = 0; i <= curGroup; i++) { groups.Add(i.ToString()); } } else { groups.Add("0"); groups.Add(curGroup.ToString()); } return groups; } void SetGroup(bool isWin) { int curGroup = PlayerPrefs.GetInt(GruopKey, 0); curGroup *= 2; if (curGroup >= MaxGroup) { curGroup = 0; } else if (isWin) { curGroup += 1; } else { curGroup += 2; } PlayerPrefs.SetInt(GruopKey, curGroup); Debug.Log("Group Cur Set :" + curGroup); } public void MachingEnd(string matchId, MatchDetails matchDetails = null, int[] mapArray = null) { if (MachingState > 0) return; if (!string.IsNullOrEmpty(matchId) && matchDetails != null) { IsRobot = false; MatchId = matchId; var map = mapIDs.Intersect(mapArray).ToList(); seed = matchId.GetHashCode(); if (map.Count == 1) { duelData.mapId = map[0]; } else { duelData.mapId = map[new System.Random(seed).Next(0, map.Count)]; } enemySolomain = GetEventSolomain(matchDetails.RandScore); enemyModel = new DuelPlayerModel(); enemyModel.Init(matchDetails.ID, matchDetails.Name, matchDetails.Avatar, matchDetails.RandScore, matchDetails.Mag, eventSoloConfig.MaxFailCount); enemyChatModel = new DuelChatModel();//真人 } else { StopRT(); IsRobot = true; if (mapIDs.Count == 1) { duelData.mapId = mapIDs[0]; } else { duelData.mapId = mapIDs[UnityEngine.Random.Range(0, mapIDs.Count)]; } //============匹配失败=============== int robotTier = eventSolomain.MatchTierList[UnityEngine.Random.Range(0, eventSolomain.MatchTierList.Count)]; enemySolomain = _tables.TbEventSolomain.DataMap[robotTier]; //============匹配失败=============== } WeatherType = new System.Random(seed).Next(0, 2); GetFishItemID(new System.Random(seed)); SetTraitID(); List carLevels = SetSelfModel(); if (IsRobot) { MachRobot();//匹配机器人 } SendFishCardLevel(carLevels); } #region 匹配成功 //选鱼杆之后再传鱼杆ID、鱼杆等级、鱼杆星级等数据 //=========同步鱼卡信息========== void SendFishCardLevel(List carLevels) { selfModel.Init(carLevels); MachingState++; ////往服务器同步鱼卡等级作为 ready if (!IsRobot) { CS_DuelRT(DuelRTType.None, ""); OnInState(); } } //获得对手鱼卡等级 void ReceiveEnemyFishCardLevel(List carLevels) { enemyModel.Init(carLevels); //默认鱼杆信息 DuelRodData duelRod = new DuelRodData { rodId = _tables.TbRodData.DataList[0].ID, rodLevel = 0, rodStar = 0 }; enemyModel.SetRodData(duelRod); MachingState++; } //=========同步鱼卡信息========== //=========同步场景完成信息========== long timestamp; public void SendChangeScene() { timestamp = ZZTimeHelper.UtcNow().AddSeconds(2).Ticks; if (!IsRobot) { //秒级时间戳当前时间延时2秒,最后对比双方双方时间取最晚的时间 SceneState++ CS_DuelRT(DuelRTType.ChangeScene, timestamp.ToString()); } SceneState++; AddSceneState(); } /// /// 容错 5秒后 没有收到对方信息自动加场景状态 /// async void AddSceneState() { await Awaiters.Seconds(5); if (SceneState < 2) { SceneState++; } } public async void ReceiveEnemyChangeScene(long Ticks) { //收到对手时间戳,与timestamp 对比取最大值 if (Ticks < timestamp) Ticks = timestamp; //时间戳转时间 System.DateTime dt = new System.DateTime(Ticks, System.DateTimeKind.Utc); //等待几秒 System.TimeSpan waitTime = dt - ZZTimeHelper.UtcNow(); if (waitTime.TotalSeconds > 0) await Task.Delay(waitTime); SceneState++; } //=========同步场景完成信息========== //=========同步鱼竿信息========== public void SendRodData(DuelRodData duelRod) { selfModel.SetRodData(duelRod); if (!IsRobot) { CS_DuelRT(DuelRTType.RodData, $"{duelRod.rodId},{duelRod.rodLevel},{duelRod.rodStar}"); } RodState++; GContext.Publish(new RodStateEvent() { RoleID = 0 }); } //获得对手鱼竿等级 public void ReceiveEnemyRodData(DuelRodData duelRod) { enemyModel.SetRodData(duelRod); RodState++; GContext.Publish(new RodStateEvent() { RoleID = 1 }); } //=========同步鱼竿信息========== #endregion #region 聊天处理 public void SendQuickMessage(int id) { //本地转发 selfChatModel.SendMessage(id); //远端转发 if (!IsRobot) { CS_DuelRT(DuelRTType.QuickMessage, id.ToString()); } } List myFishingStateList = new List(); List fishingStateList = new List(); #endregion public void OnFishingChangeStateEvent(FishingChangeState fishState, int fishID, int point = 0, float fishCardAdd = 0, float fishRodAdd = 0) { bool gameOver; switch (fishState) { case FishingChangeState.Cast: selfModel.CastRod(fishID); myFishingStateList.Add($"{(int)fishState}:{fishID}"); break; case FishingChangeState.FishingSuccess: isSettle = false; FishInfoData data = enemyModel.GetDuelFishingData(selfModel.index, point, fishCardAdd, fishRodAdd); gameOver = selfModel.StopFishing(data); ReceiveRobotQuickMessage((int)RobotDuelChatType.OpponetFishingSuccess); if (gameOver) { PlayerFishingOver(); } //刷新view AwaitSettle(); myFishingStateList.Add($"{(int)fishState}:{point}:{fishCardAdd}:{fishRodAdd}"); break; case FishingChangeState.FishingFail: gameOver = selfModel.StopFishing(new FishInfoData()); ReceiveRobotQuickMessage((int)RobotDuelChatType.OpponetFishingFail); if (gameOver) { PlayerFishingOver(); } myFishingStateList.Add($"{(int)fishState}"); break; } //往服务器同步对手操作 //远端转发 if (!IsRobot) { CS_DuelRT(DuelRTType.FishingStateList, string.Join(",", myFishingStateList)); } } #region 接受对手操作 #region 机器人 /// /// 接受对手消息,机器人 /// /// public void ReceiveRobotQuickMessage(int id) { if (IsRobot) ReceiveQuickMessage(id); } public void ReceiveRobotFishingStateList(List stateList) { if (IsRobot) ReceiveFishingStateList(stateList); } #endregion 机器人 public void ReceiveQuickMessage(int id) { enemyChatModel.ReceiveMessage(id); } public void ReceiveFishingStateList(List stateList) { if (stateList.Count > fishingStateList.Count) { for (int i = fishingStateList.Count; i < stateList.Count; i++) { var parts = stateList[i].Split(':'); FishingChangeState fishState = (FishingChangeState)int.Parse(parts[0]); int point = 0; int fishID = 0; float fishCardAdd = 0; float fishRodAdd = 0; if (fishState == FishingChangeState.FishingSuccess) { point = int.Parse(parts[1]); fishCardAdd = float.Parse(parts[2]); fishRodAdd = float.Parse(parts[3]); } else if (fishState == FishingChangeState.Cast) { fishID = int.Parse(parts[1]); } ReceiveFishingQueue(fishState, fishID, point, fishCardAdd, fishRodAdd); fishingStateList.Add(stateList[i]); } } } /// /// 对手操作 /// void ReceiveFishingQueue(FishingChangeState fishState, int fishID, int point = 0, float fishCardAdd = 0, float fishRodAdd = 0) { bool gameOver; switch (fishState) { case FishingChangeState.Cast: enemyModel.CastRod(fishID); if (enemyModel.IsLastFish() && !selfModel.IsLastFish()) { ReceiveRobotQuickMessage((int)RobotDuelChatType.FirstLastFishStart); ReceiveFishingEvent receiveFishingEvent = new ReceiveFishingEvent(); receiveFishingEvent.value = LocalizationMgr.GetFormatTextValue("UI_EventFishingDuelPanel_38", enemyModel.PlayerName); GContext.Publish(receiveFishingEvent); } break; case FishingChangeState.FishingSuccess: FishInfoData data = selfModel.GetDuelFishingData(enemyModel.index, point, fishCardAdd, fishRodAdd); gameOver = enemyModel.StopFishing(data); if (gameOver) { EnemyFishingOver(); ReceiveRobotQuickMessage((int)RobotDuelChatType.FirstLastFishSuccess); } else { ReceiveRobotQuickMessage((int)RobotDuelChatType.FishingSuccess); } break; case FishingChangeState.FishingFail: gameOver = enemyModel.StopFishing(new FishInfoData()); if (gameOver) { EnemyFishingOver(); } break; default: break; } } #endregion #region 网络通讯 private IDisposable disposableRT; /// /// 匹配开始前 注入 RT /// public void StartRT() { //RT开始 if (rts == null) { rts = GContext.container.Resolve(); disposableRT?.Dispose(); if (rts.IsConnected) { disposableRT = rts.OnEvent(SC_DuelRT); } else { Debug.LogError("RT未连接成功"); rts = null; } } } /// /// Dispose RT /// public void StopRT() { //RT结束 disposableRT?.Dispose(); disposableRT = null; rts = null; } void OnInState() { InitState++; if (InitState == 2) { //初始化成功,同步鱼卡等级 int fishCardAllLevel = GContext.container.Resolve().GetFishLevelByMap(MapId); string userid = GContext.container.Resolve().CustomId; string carLevels = string.Join(",", selfModel.CarLevels); string fishCardLevel = $"{userid}|{fishCardAllLevel}|{carLevels}"; CS_DuelRT(DuelRTType.FishCardLevel, fishCardLevel); } } async void SC_DuelRT(SC_DuelRTEvent data) { await Awaiters.NextFrame; Debug.Log($"SC_DuelRT Type:{data.type} Value:{data.value} PlayerID:{data.playerId}"); if (IsRobot) { Debug.LogError("机器人不接收RT消息"); return; } if (data == null || (data.type != DuelRTType.None && data.playerId != enemyModel.PlayerID)) { Debug.LogError($"接收RT消息错误 EnemyID:{enemyModel.PlayerID} SC PlayerID:{data?.playerId}"); return; } //RT接收 switch (data.type) { case DuelRTType.None: //心跳包 if (!InitComplete) { OnInState(); } InitComplete = true; break; case DuelRTType.FishCardLevel: string[] strings = data.value.Split('|'); userIDPlayer = strings[0]; carAllLevelPlayer = int.Parse(strings[1]); string carLevel = strings[2]; List carLevels = carLevel.Split(',').Select(int.Parse).ToList(); ReceiveEnemyFishCardLevel(carLevels); break; case DuelRTType.RodData: var parts = data.value.Split(','); DuelRodData duelRod = new DuelRodData { rodId = int.Parse(parts[0]), rodLevel = int.Parse(parts[1]), rodStar = int.Parse(parts[2]) }; ReceiveEnemyRodData(duelRod); break; case DuelRTType.ChangeScene: long ticks = long.Parse(data.value); ReceiveEnemyChangeScene(ticks); break; case DuelRTType.QuickMessage: int id = int.Parse(data.value); ReceiveQuickMessage(id); break; case DuelRTType.FishingStateList: List stateList = data.value.Split(',').ToList(); ReceiveFishingStateList(stateList); break; default: break; } //RT接收 刷新心跳时间 } void CS_DuelRT(DuelRTType type, string value) { //RT发送 CS_DuelRTEvent data = new CS_DuelRTEvent(); data.type = type; data.value = value; data.playerId = selfModel.PlayerID; data.enemyId = enemyModel.PlayerID; customServerMgr.DuelRequest("DuelRT", data); Debug.Log($"CS_DuelRT Type:{type} Value:{value}"); } #endregion 网络通讯 } public enum DuelRTType : byte { None = 0, FishCardLevel = 1, RodData = 2, ChangeScene = 3, QuickMessage = 4, FishingStateList = 5, } public class SC_DuelRTEvent { public DuelRTType type; public string value; //发送方ID public string playerId; } public class CS_DuelRTEvent { public DuelRTType type; public string value; //发送方ID public string playerId; //接收方ID public string enemyId; } public class ReceiveFishingEvent { public string value; } public class MatchDetails { public string ID; public string Name; public string Avatar; public int RandScore; public int Mag; }