390 lines
17 KiB
C#
390 lines
17 KiB
C#
using Animancer;
|
||
using Logic;
|
||
using Logic.Action;
|
||
using Logic.CrashSight;
|
||
using RuntimeData;
|
||
using Steamworks;
|
||
using TH1_Core.Events;
|
||
using TH1_Core.Managers;
|
||
using TH1_Logic.Core;
|
||
using TH1_Logic.Net;
|
||
using UnityEngine;
|
||
|
||
namespace TH1_Logic.Steam
|
||
{
|
||
public class GameNetReceiver
|
||
{
|
||
public static GameNetReceiver Instance { get; } = new GameNetReceiver();
|
||
|
||
|
||
public void OnMessageReceived(byte[] data)
|
||
{
|
||
var message = MemoryPack.MemoryPackSerializer.Deserialize<BaseMessage>(data);
|
||
if (message == null) return;
|
||
|
||
if (message.MessageType == P2PMsgType.String) OnReceivedString((StringMessage)message);
|
||
if (message.MessageType == P2PMsgType.GameStart) OnReceivedGameStart((GameStartMessage)message);
|
||
if (message.MessageType == P2PMsgType.ActionConfirm) OnReceivedActionConfirm((ActionConfirmMessage)message);
|
||
if (message.MessageType == P2PMsgType.ActionExcute) OnReceivedActionExcute((ActionExcuteMessage)message);
|
||
if (message.MessageType == P2PMsgType.TurnEnd) OnReceivedTurnEnd((TurnEndMessage)message);
|
||
if (message.MessageType == P2PMsgType.MapConfirm) OnReceivedMapConfirm((MapConfirmMessage)message);
|
||
if (message.MessageType == P2PMsgType.ForceUpdate) OnReceivedForceUpdate((ForceUpdateMessage)message);
|
||
if (message.MessageType == P2PMsgType.ChangeCiv) OnReceivedChangeCiv((ChangeCivMessage)message);
|
||
if (message.MessageType == P2PMsgType.UpdateLobbyData) OnReceivedUpdateLobbyData((UpdateLobbyDataMessage)message);
|
||
if (message.MessageType == P2PMsgType.RequestLobbyData) OnReceivedRequestLobbyData((RequestLobbyDataMessage)message);
|
||
if (message.MessageType == P2PMsgType.Heartbeat) OnReceivedHeartbeat((HeartbeatMessage)message);
|
||
if (message.MessageType == P2PMsgType.MemberStateSync) OnReceivedMemberStateSync((MemberStateSyncMessage)message);
|
||
if (message.MessageType == P2PMsgType.RequestForceUpdate) OnReceivedRequestForceUpdate((RequestForceUpdateMessage)message);
|
||
if (message.MessageType == P2PMsgType.HeartbeatReply) OnReceivedHeartbeatReply((HeartbeatReplyMessage)message);
|
||
}
|
||
|
||
// 基础字符串消息
|
||
private void OnReceivedString(StringMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedString");
|
||
return;
|
||
}
|
||
|
||
if (string.IsNullOrEmpty(message.Content)) return;
|
||
LogSystem.LogInfo($"收到消息 : {message.Content}");
|
||
}
|
||
|
||
// 只有玩家会收到
|
||
private void OnReceivedGameStart(GameStartMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedGameStart");
|
||
return;
|
||
}
|
||
|
||
if (message.MapData == null) return;
|
||
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
LogSystem.LogWarning($"OnReceivedGameStart : {NetData.GetMapDataHash(message.MapData)}");
|
||
|
||
|
||
//客户端开启游戏
|
||
//如果loading失败 直接开始游戏并关闭当前页面
|
||
UIManager.Instance.ShowLoading();
|
||
Main.Instance.NetStartGame(message.MapData);
|
||
|
||
EventManager.Publish(new HideUIOutsideMultiplay(){});
|
||
}
|
||
|
||
// 只有房主会收到
|
||
private void OnReceivedActionConfirm(ActionConfirmMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedActionConfirm");
|
||
return;
|
||
}
|
||
|
||
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
if (message.ActionData == null) return;
|
||
// if (message.ActionData.MapHash != Main.MapData.Net.MapHash)
|
||
// {
|
||
// LogSystem.LogError($"OnReceivedActionConfirm MapHash不一致");
|
||
// return;
|
||
// }
|
||
if (message.ActionData.Version != Main.MapData.Net.GetActionVersion())
|
||
{
|
||
LogSystem.LogError($"OnReceivedActionConfirm Version 不一致");
|
||
return;
|
||
}
|
||
|
||
message.ActionData.Param.MapData = Main.MapData;
|
||
message.ActionData.Param.RefreshParams();
|
||
|
||
if (message.ActionData.ActionId.ActionType != CommonActionType.TurnStart &&
|
||
Main.MapData.CurPlayer != null && Main.MapData.CurPlayer.Id != message.ActionData.Param.PlayerId)
|
||
{
|
||
LogSystem.LogError($"OnReceivedActionConfirm Player 不一致");
|
||
return;
|
||
}
|
||
|
||
var action = ActionLogicFactory.GetActionLogic(message.ActionData.ActionId);
|
||
if (action == null)
|
||
{
|
||
LogSystem.LogError($"OnReceivedActionConfirm 找不到对应 Action");
|
||
return;
|
||
}
|
||
action.CompleteExecute(message.ActionData.Param);
|
||
}
|
||
|
||
// 只有玩家会收到
|
||
private void OnReceivedActionExcute(ActionExcuteMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedActionExcute");
|
||
return;
|
||
}
|
||
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
if (message.ActionData == null) return;
|
||
// if (message.ActionData.MapHash != Main.MapData.Net.MapHash)
|
||
// {
|
||
// LogSystem.LogError($"OnReceivedActionConfirm MapHash不一致");
|
||
// return;
|
||
// }
|
||
|
||
if (Main.MapData == null) return;
|
||
if (message.ActionData.Version != Main.MapData.Net.GetActionVersion()) return;
|
||
|
||
if (NetData.GetMapDataHash(Main.MapData) != message.ActionData.MapHash)
|
||
{
|
||
// TODO 这里来校验不同之处
|
||
if (message.Map != null)
|
||
{
|
||
Main.MapData.CompareEqual(message.Map);
|
||
var diff = MapData.FindDifferences(Main.MapData, message.Map);
|
||
var allStr = "";
|
||
foreach (var str in diff) allStr+= str + "\n";
|
||
LogSystem.LogError($"{allStr}");
|
||
}
|
||
// MapData.CompareWithDetails(Main.MapData, message.Map);
|
||
}
|
||
|
||
message.ActionData.Param.MapData = Main.MapData;
|
||
message.ActionData.Param.RefreshParams();
|
||
if (message.ActionData.ActionId.ActionType != CommonActionType.TurnStart &&
|
||
Main.MapData.CurPlayer != null && Main.MapData.CurPlayer.Id != message.ActionData.Param.PlayerId)
|
||
{
|
||
LogSystem.LogError($"OnReceivedActionExcute Player 不一致");
|
||
return;
|
||
}
|
||
var action = ActionLogicFactory.GetActionLogic(message.ActionData.ActionId);
|
||
if (action == null)
|
||
{
|
||
LogSystem.LogError($"OnReceivedActionConfirm 找不到对应 Action");
|
||
return;
|
||
}
|
||
action.NetCompleteExecute(message.ActionData.Param);
|
||
}
|
||
|
||
// 只有房主会收到
|
||
private void OnReceivedTurnEnd(TurnEndMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedTurnEnd");
|
||
return;
|
||
}
|
||
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
Main.PlayerLogic.EndPlayerTurn(Main.MapData, message.PlayerId);
|
||
}
|
||
|
||
// 只有房主会收到心跳校验
|
||
private void OnReceivedMapConfirm(MapConfirmMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedMapConfirm");
|
||
return;
|
||
}
|
||
|
||
if (Main.MapData == null) return;
|
||
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
if (Main.MapData.Net.Actions.Count == 0 || message.Index == 0) return;
|
||
var confirm = Main.Instance.ConfirmMap.GetPlayerConfirm(message.MemberId);
|
||
|
||
if (message.Index > Main.MapData.Net.Actions.Count)
|
||
{
|
||
LogSystem.LogError($"action index error message.Index : {message.Index}, Main.MapData.Net.Actions.Count : {Main.MapData.Net.Actions.Count}");
|
||
confirm.State = MemberNetState.Error;
|
||
return;
|
||
}
|
||
else if (!Main.MapData.Net.Actions[message.Index - 1].IsEqual(message.ActionData))
|
||
{
|
||
LogSystem.LogError($"self action hash : {Main.MapData.Net.Actions[message.Index - 1].MapHash}, message map hash : {message.ActionData.MapHash}");
|
||
confirm.State = MemberNetState.Error;
|
||
}
|
||
else
|
||
{
|
||
confirm.State = MemberNetState.OK;
|
||
LogSystem.LogInfo($"self action hash : {Main.MapData.Net.Actions[message.Index - 1].MapHash}, message map hash : {message.ActionData.MapHash}");
|
||
}
|
||
}
|
||
|
||
// 只有玩家会收到
|
||
private void OnReceivedForceUpdate(ForceUpdateMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedForceUpdate");
|
||
return;
|
||
}
|
||
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
var confirm = Main.Instance.ConfirmMap.GetPlayerConfirm(LobbyManager.Instance.Lobby.GetSelfMemberId());
|
||
LogSystem.LogError($"触发断线重连, 触发原因: {confirm?.State}");
|
||
|
||
if (Main.MapData != null)
|
||
{
|
||
Main.MapData.CompareEqual(message.MapData);
|
||
var diff = MapData.FindDifferences(Main.MapData, message.MapData);
|
||
var allStr = "";
|
||
foreach (var str in diff) allStr+= str + "\n";
|
||
LogSystem.LogError($"{allStr}");
|
||
// Main.Instance.NetContinueGame(message.MapData);
|
||
for (int i = 0; i < Main.MapData.Net.Actions.Count; i++)
|
||
{
|
||
if (i >= message.MapData.Net.Actions.Count) continue;
|
||
if (Main.MapData.Net.Actions[i].MapHash == message.MapData.Net.Actions[i].MapHash) continue;
|
||
if (i == 0) LogSystem.LogError($"初始 Map 校验失败!!!");
|
||
else
|
||
{
|
||
LogSystem.LogError($"Map不一致前后Action : {Main.MapData.Net.Actions[i - 1].ActionId.GetStringLog()}" +
|
||
$"{Main.MapData.Net.Actions[i].ActionId.GetStringLog()}");
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// TODO 强制断线重连在这里实现
|
||
// Step #1 强制结束当前游戏对局
|
||
Main.Instance.GameLogic.ChangeState(GameState.Menu);
|
||
// Step #2 强制关闭当前所有UI
|
||
UIManager.Instance.GameUI.CloseAllGameUI();
|
||
EventManager.Publish(new HideUIOutsideMultiplay());
|
||
UIManager.Instance.GameUI.NetHint.SetActive(true);
|
||
Timer.Instance.TimerRegister(this, () =>
|
||
{
|
||
UIManager.Instance.GameUI.NetHint.SetActive(false);
|
||
},2f,"NetHint Wrong");
|
||
// Step #3 强制继续联机对局
|
||
Main.Instance.NetContinueGame(message.MapData);
|
||
|
||
|
||
// Main.MapData = message.MapData;
|
||
}
|
||
|
||
// 只有房主会收到
|
||
private void OnReceivedChangeCiv(ChangeCivMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedChangeCiv");
|
||
return;
|
||
}
|
||
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
if (message.Civ == null) return;
|
||
Main.Instance.MapConfig.UpdateMemberCiv(message.Civ);
|
||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||
}
|
||
|
||
// 只有玩家会收到
|
||
private void OnReceivedUpdateLobbyData(UpdateLobbyDataMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedUpdateLobbyData");
|
||
return;
|
||
}
|
||
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
if (message.Config == null) return;
|
||
Main.Instance.MapConfig = message.Config;
|
||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||
}
|
||
|
||
// 收到请求更新房间配置 只有房主会收到
|
||
private void OnReceivedRequestLobbyData(RequestLobbyDataMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedRequestLobbyData");
|
||
return;
|
||
}
|
||
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
GameNetSender.Instance.SendLobbyData(Main.Instance.MapConfig, message.MemberId);
|
||
}
|
||
|
||
// 成员发过来的心跳包 只有房主会收到
|
||
private void OnReceivedHeartbeat(HeartbeatMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedHeartbeat");
|
||
return;
|
||
}
|
||
|
||
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
|
||
// 心跳回复
|
||
GameNetSender.Instance.SendHeartbeatReply(message.MemberId);
|
||
|
||
// 常规记录
|
||
var confirm = Main.Instance.ConfirmMap.GetPlayerConfirm(message.MemberId);
|
||
confirm.OnReceiveHeartbeat();
|
||
|
||
// 做一次状态错误判断
|
||
if (Main.MapData == null) return;
|
||
if (Main.MapData.Net.GameStartTime == 0 || Time.time - Main.MapData.Net.GameStartTime < 5f) return;
|
||
if (message.State != GameState.Finished && message.State != GameState.Menu) return;
|
||
|
||
var playerID = Main.MapData.Net.GetPlayerId(message.MemberId);
|
||
var player = Main.MapData.PlayerMap.GetPlayerData(playerID);
|
||
if (player == null) return;
|
||
if (!player.Alive) return;
|
||
if (Main.MapData.CheckIfGameEnd(out _)) return;
|
||
confirm.State = MemberNetState.Disconnected;
|
||
GameNetSender.Instance.SendMemberStateSync();
|
||
}
|
||
|
||
// 房主心跳包 只有成员会收到 每 2s 收到一次
|
||
private void OnReceivedMemberStateSync(MemberStateSyncMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedMemberStateSync");
|
||
return;
|
||
}
|
||
|
||
// 心跳回复
|
||
GameNetSender.Instance.SendHeartbeatReply(message.MemberId);
|
||
|
||
// 判断是否需要重连
|
||
if (Main.MapData != null && Main.MapData.CheckIfGameEnd(out _)) return;
|
||
if (message.State == GameState.Finished || message.State == GameState.Menu) return;
|
||
if(!LobbyManager.Instance.Lobby.IsInLobby()) return;
|
||
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
Main.Instance.ConfirmMap.UpdatePlayerConfirm(message.PlayerConfirm);
|
||
var confirm = Main.Instance.ConfirmMap.GetPlayerConfirm(LobbyManager.Instance.Lobby.GetSelfMemberId());
|
||
if (confirm.State != MemberNetState.OK)
|
||
{
|
||
// TODO 此时说明房主端我的状态有误,可选申请重连
|
||
LogSystem.LogWarning($"OnReceivedMemberStateSync 检测状态错误");
|
||
GameNetSender.Instance.SendRequestForceUpdate();
|
||
}
|
||
|
||
}
|
||
|
||
// 只有房主会收到
|
||
private void OnReceivedRequestForceUpdate(RequestForceUpdateMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedRequestForceUpdate");
|
||
return;
|
||
}
|
||
|
||
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
|
||
if (Main.MapData == null) return;
|
||
GameNetSender.Instance.ForceUpdate(message.MemberId);
|
||
}
|
||
|
||
// 心跳回复包,所有成员都能收到
|
||
private void OnReceivedHeartbeatReply(HeartbeatReplyMessage message)
|
||
{
|
||
if (message == null)
|
||
{
|
||
LogSystem.LogError($"消息解析失败: OnReceivedHeartbeatReply");
|
||
return;
|
||
}
|
||
|
||
var confirm = Main.Instance.ConfirmMap.GetPlayerConfirm(message.MemberId);
|
||
confirm.OnReceiveHeartbeatReply();
|
||
}
|
||
}
|
||
} |