DESKTOP-5RP3AKU\Jisol ced7fdce74 完美
2024-09-13 04:06:25 +08:00

249 lines
6.6 KiB
C#

using System.Collections.Generic;
using DotRecast.Core.Collections;
using UnityEngine;
using NotImplementedException = System.NotImplementedException;
namespace JNGame.Sync.System.Data
{
public enum SStateDataEnum
{
Server,
Client,
ServerClient,
}
public abstract class ISStateData : ISData
{
/// <summary>
/// 返回Byte数组
/// </summary>
/// <returns></returns>
public abstract byte[] GetByte();
/// <summary>
/// 返回差值Byte
/// </summary>
/// <param name="diffValue"></param>
/// <returns></returns>
public abstract byte[] GetByteDifference(ISData diffValue = null);
/// <summary>
/// 更新字节
/// </summary>
/// <param name="bytes"></param>
public abstract void UByte(byte[] bytes);
}
public interface ISStateDataSystem
{
//网络Id (用于确定网络通讯时找到这个数据系统)
public int NetID { get; }
/// <summary>
/// 插入字节
/// </summary>
public void OnInsertUBytes(Dictionary<ulong, byte[]> bytes);
/// <summary>
/// 获取全部字节
/// </summary>
public Dictionary<ulong, byte[]> GetDataBytes();
}
/// <summary>
/// 状态同步的数据系统 (支持网络数据)
/// 注意:帧同步也可以使用不过不建议 因为会有额外开销 除非你的游戏 经常在帧同步或者状态同步之间切换
/// </summary>
public abstract class SStateDataSystem<T> : SDataSystem<T>,ISStateDataSystem where T : ISStateData,new()
{
public abstract int NetID { get; }
//网络通讯的更新字节数据
protected Dictionary<ulong, byte[]> UBytes = new();
public SStateDataEnum Type;
public bool isServer => Type is SStateDataEnum.ServerClient or SStateDataEnum.Server;
public bool isClient => Type is SStateDataEnum.ServerClient or SStateDataEnum.Client;
//待插入的数据
protected Queue<Dictionary<ulong, byte[]>> WaitUBytes = new ();
protected SStateDataSystem(SStateDataEnum type)
{
Type = type;
}
public override void OnSyncUpdate(int dt)
{
while (WaitUBytes.Count > 0)
{
OnUByteUpdate(WaitUBytes.Dequeue());
}
//服务器: 发送最近数据
if (isServer)
{
var latest = GetLatest();
latest.Keys.ForEach(key =>
{
if (Data.ContainsKey(key))
{
//更新数据
Update(latest[key]);
}
else
{
//如果之前没有则添加
Add(latest[key]);
}
});
Data.ForEach(child =>
{
//没有则删除
if (!(latest.ContainsKey(child.Key))) Delete(child.Key);
});
if (UBytes.Count > 0)
{
OnUByteUpdate(UBytes);
OnSendUBytes(UBytes);
UBytes.Clear();
}
}
}
/// <summary>
/// 发送字节数据
/// </summary>
/// <param name="bytes"></param>
/// <returns>是否清空UBytes</returns>
public abstract void OnSendUBytes(Dictionary<ulong, byte[]> bytes);
/// <summary>
/// 插入字节
/// </summary>
/// <returns></returns>
public void OnInsertUBytes(Dictionary<ulong, byte[]> bytes)
{
if (bytes is not null)
{
WaitUBytes.Enqueue(bytes);
}
else
{
Debug.Log("有数据是空");
}
}
/// <summary>
/// 获取全部字节
/// </summary>
public Dictionary<ulong, byte[]> GetDataBytes()
{
var data = new Dictionary<ulong, byte[]>();
lock (Data)
{
Data.ForEach(child =>
{
data[child.Key] = child.Value.GetByte();
});
}
return data;
}
/// <summary>
/// 将UByte提交更新
/// </summary>
public virtual void OnUByteUpdate(Dictionary<ulong, byte[]> bytes)
{
if (bytes is null) return;
lock (Data)
{
foreach (var info in bytes)
{
if (SDByteOperate.IsDelete(info.Value))
{
Data.Remove(info.Key);
}
else
{
if (Data.TryGetValue(info.Key, out var value))
{
value.UByte(info.Value);
}
else
{
Data[info.Key] = NewObject(info.Key,info.Value);
}
}
}
}
}
/// <summary>
/// Byte解析新对象
/// </summary>
/// <param name="id"></param>
/// <param name="bytes"></param>
/// <returns></returns>
public T NewObject(ulong id,byte[] bytes)
{
var data = new T();
data.Id = id;
data.UByte(bytes);
return data;
}
/// <summary>
/// 刷新数据
/// </summary>
public virtual void Update(T data)
{
if (Data.TryGetValue(data.Id, out var value))
{
var diff = value.GetByteDifference(data);
if (diff.Length > 0)
{
UBytes[data.Id] = diff;
}
}
else
{
UBytes[data.Id] = data.GetByte();
}
}
/// <summary>
/// 添加数据
/// </summary>
public virtual void Add(T data)
{
UBytes[data.Id] = data.GetByte();
}
/// <summary>
/// 删除数据
/// </summary>
public virtual void Delete(ulong id)
{
UBytes[id] = SDByteOperate.DELETE;
}
}
}