TH1/Unity/Assets/Scripts/TH1_Logic/Steam/GameNetReceiver.cs
2025-11-07 15:23:36 +08:00

390 lines
17 KiB
C#
Raw 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 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();
}
}
}