192 lines
6.2 KiB
C#
192 lines
6.2 KiB
C#
/*
|
||
* @Author: 白哉
|
||
* @Description:
|
||
* @Date: 2025年04月03日 星期四 11:04:31
|
||
* @Modify:
|
||
*/
|
||
|
||
|
||
using System.Collections.Generic;
|
||
using Logic.AI;
|
||
using Logic.CrashSight;
|
||
using MemoryPack;
|
||
using TH1_Logic.Net;
|
||
using UnityEngine;
|
||
|
||
|
||
namespace RuntimeData
|
||
{
|
||
public enum NetMode
|
||
{
|
||
None,
|
||
Single,
|
||
Multi,
|
||
}
|
||
|
||
public class PlayerConfirmData
|
||
{
|
||
public ulong MemberId;
|
||
public float ConfirmTime;
|
||
public float GameConfirmTime;
|
||
public bool NeedForceUpdate;
|
||
|
||
|
||
public PlayerConfirmData(ulong id)
|
||
{
|
||
MemberId = id;
|
||
ConfirmTime = Time.time;
|
||
GameConfirmTime = Time.time;
|
||
NeedForceUpdate = false;
|
||
}
|
||
}
|
||
|
||
|
||
// 网络信息
|
||
[MemoryPackable]
|
||
public partial class NetData
|
||
{
|
||
// 网络模式
|
||
public NetMode Mode;
|
||
// 当前操作的玩家
|
||
public uint CurPlayerId;
|
||
// 地图哈希
|
||
[MemoryPackIgnore]
|
||
public string MapHash;
|
||
// SteamId => PlayerId 的索引
|
||
public Dictionary<ulong, uint> Players;
|
||
// 所有玩家行为的序列
|
||
public List<ActionNetData> Actions;
|
||
|
||
// 随机数种子 开始游戏时由房主进行初始化,整局游戏不可变
|
||
public int RandomSeed;
|
||
private System.Random _random;
|
||
|
||
// 玩家开始时间记录
|
||
[MemoryPackIgnore]
|
||
public float PlayerStartTime;
|
||
[MemoryPackIgnore]
|
||
public Dictionary<ulong, PlayerConfirmData> PlayerConfirm;
|
||
|
||
|
||
[MemoryPackConstructor]
|
||
public NetData()
|
||
{
|
||
Mode = NetMode.None;
|
||
CurPlayerId = 0;
|
||
Players = new Dictionary<ulong, uint>();
|
||
Actions = new List<ActionNetData>();
|
||
// 生成确定性种子(由房主生成并广播)
|
||
RandomSeed = System.Environment.TickCount;
|
||
PlayerConfirm = new Dictionary<ulong, PlayerConfirmData>();
|
||
}
|
||
|
||
// 这里单纯是因为深拷贝目前只用于 AI 演算,故不对 Players 和 Actions 赋值
|
||
public NetData(NetData copyData)
|
||
{
|
||
Mode = copyData.Mode;
|
||
CurPlayerId = copyData.CurPlayerId;
|
||
MapHash = copyData.MapHash;
|
||
RandomSeed = copyData.RandomSeed;
|
||
Players = new Dictionary<ulong, uint>();
|
||
Actions = new List<ActionNetData>();
|
||
PlayerConfirm = new Dictionary<ulong, PlayerConfirmData>();
|
||
}
|
||
|
||
// 这里单纯是因为深拷贝目前只用于 AI 演算,故不对 Players 和 Actions 赋值
|
||
public void DeepCopy(NetData copyData)
|
||
{
|
||
Mode = copyData.Mode;
|
||
CurPlayerId = copyData.CurPlayerId;
|
||
MapHash = copyData.MapHash;
|
||
RandomSeed = copyData.RandomSeed;
|
||
Players = new Dictionary<ulong, uint>();
|
||
Actions = new List<ActionNetData>();
|
||
PlayerConfirm = new Dictionary<ulong, PlayerConfirmData>();
|
||
}
|
||
|
||
// 只有 Action 的逻辑可以使用这个 Random, 因为要保证计数一致
|
||
public System.Random GetRandom()
|
||
{
|
||
if (_random == null) _random = new System.Random(RandomSeed);
|
||
return _random;
|
||
}
|
||
|
||
public void RefreshPlayerNet(MapData mapData)
|
||
{
|
||
if (Mode != NetMode.Multi) return;
|
||
if (LobbyManager.Instance.Lobby.IsLobbyOwner())
|
||
{
|
||
// 创建 Player 的时候会分配一次 PlayerId,这里直接使用
|
||
foreach (var memberCiv in mapData.MapConfig.MultiCivs)
|
||
{
|
||
if (memberCiv.PlayerId == 0) continue;
|
||
if (Players.ContainsKey(memberCiv.MemberId)) continue;
|
||
Players[memberCiv.MemberId] = memberCiv.PlayerId;
|
||
}
|
||
|
||
// 添加其他人
|
||
foreach (var memberId in LobbyManager.Instance.Lobby.GetAllMemberIds())
|
||
{
|
||
if (Players.ContainsKey(memberId)) continue;
|
||
foreach (var player in mapData.PlayerMap.PlayerDataList)
|
||
{
|
||
if (Players.ContainsValue(player.Id)) continue;
|
||
Players[memberId] = player.Id;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
var selfMemberId = LobbyManager.Instance.Lobby.GetSelfMemberId();
|
||
if (Players.TryGetValue(selfMemberId, out var id))
|
||
mapData.PlayerMap.SelfPlayerId = id;
|
||
|
||
PlayerConfirm.Clear();
|
||
foreach (var kv in Players) PlayerConfirm[kv.Key] = new PlayerConfirmData(kv.Key);
|
||
}
|
||
|
||
public void RefreshMapNet(MapData mapData)
|
||
{
|
||
// 地图哈希
|
||
MapHash = GetMapDataHash(mapData);
|
||
}
|
||
|
||
public uint GetActionVersion()
|
||
{
|
||
if (Actions.Count == 0) return 0;
|
||
return Actions[^1].Version + 1;
|
||
}
|
||
|
||
public ulong GetmemberIdId(uint playerId)
|
||
{
|
||
foreach (var kv in Players)
|
||
{
|
||
if (kv.Value == playerId) return kv.Key;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
public void CompareEqual(NetData net)
|
||
{
|
||
var differences = new List<string>();
|
||
|
||
// 使用序列化比较各个组件
|
||
MapData.CompareComponent(Mode, net.Mode, "Mode", differences);
|
||
MapData.CompareComponent(CurPlayerId, net.CurPlayerId, "CurPlayerId", differences);
|
||
MapData.CompareComponent(Players, net.Players, "Players", differences);
|
||
MapData.CompareComponent(Actions, net.Actions, "Actions", differences);
|
||
|
||
// 输出结果
|
||
foreach (var diff in differences) LogSystem.LogWarning($" - {diff}");
|
||
}
|
||
|
||
public static string GetMapDataHash(MapData mapData)
|
||
{
|
||
byte[] bytes = MemoryPackSerializer.Serialize(mapData);
|
||
// 使用 Unity 的 Hash128(性能很好且稳定)
|
||
var hash128 = new Hash128();
|
||
hash128.Append(bytes);
|
||
return hash128.ToString();
|
||
}
|
||
}
|
||
} |