Files
ft/Client/Assets/Scripts/Duel/FishingDuelManager_Network.cs
2026-06-29 21:18:33 +08:00

556 lines
17 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<int> 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<string> GetGroups()
{
var groups = new List<string>();
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<int> carLevels = SetSelfModel();
if (IsRobot)
{
MachRobot();//匹配机器人
}
SendFishCardLevel(carLevels);
}
#region
//选鱼杆之后再传鱼杆ID、鱼杆等级、鱼杆星级等数据
//=========同步鱼卡信息==========
void SendFishCardLevel(List<int> carLevels)
{
selfModel.Init(carLevels);
MachingState++;
////往服务器同步鱼卡等级作为 ready
if (!IsRobot)
{
CS_DuelRT(DuelRTType.None, "");
OnInState();
}
}
//获得对手鱼卡等级
void ReceiveEnemyFishCardLevel(List<int> 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();
}
/// <summary>
/// 容错 5秒后 没有收到对方信息自动加场景状态
/// </summary>
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<string> myFishingStateList = new List<string>();
List<string> fishingStateList = new List<string>();
#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
/// <summary>
/// 接受对手消息,机器人
/// </summary>
/// <param name="id"></param>
public void ReceiveRobotQuickMessage(int id)
{
if (IsRobot)
ReceiveQuickMessage(id);
}
public void ReceiveRobotFishingStateList(List<string> stateList)
{
if (IsRobot)
ReceiveFishingStateList(stateList);
}
#endregion
public void ReceiveQuickMessage(int id)
{
enemyChatModel.ReceiveMessage(id);
}
public void ReceiveFishingStateList(List<string> 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]);
}
}
}
/// <summary>
/// 对手操作
/// </summary>
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;
/// <summary>
/// 匹配开始前 注入 RT
/// </summary>
public void StartRT()
{
//RT开始
if (rts == null)
{
rts = GContext.container.Resolve<IRTService>();
disposableRT?.Dispose();
if (rts.IsConnected)
{
disposableRT = rts.OnEvent<SC_DuelRTEvent>(SC_DuelRT);
}
else
{
Debug.LogError("RT未连接成功");
rts = null;
}
}
}
/// <summary>
/// Dispose RT
/// </summary>
public void StopRT()
{
//RT结束
disposableRT?.Dispose();
disposableRT = null;
rts = null;
}
void OnInState()
{
InitState++;
if (InitState == 2)
{
//初始化成功,同步鱼卡等级
int fishCardAllLevel = GContext.container.Resolve<PlayerFishData>().GetFishLevelByMap(MapId);
string userid = GContext.container.Resolve<IUserService>().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<int> 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<string> 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;
}