190 lines
6.1 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.

/*
* @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 bool NeedForceUpdate;
public PlayerConfirmData(ulong id)
{
MemberId = id;
ConfirmTime = 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();
}
}
}