556 lines
17 KiB
C#
556 lines
17 KiB
C#
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;
|
||
}
|
||
|
||
|