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

368 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using AppGame.Sync;
using DotRecast.Core.Collections;
using JNGame.Math;
using JNGame.Sync.Entity;
using JNGame.Sync.Frame.Entity.Components;
using JNGame.Sync.State.Tile;
using JNGame.Sync.State.Tile.Entity;
using NotImplementedException = System.NotImplementedException;
namespace JNGame.Sync.System.Data
{
public interface ISTileDataSystem
{
/// <summary>
/// 清除指定区域数据
/// </summary>
public void ClearTileData(int index);
/// <summary>
/// 获取有权限的全部字节
/// </summary>
public Dictionary<ulong, byte[]> GetHostDataBytes(Func<JNTileEntity,bool> filter = null);
/// <summary>
/// 获取有权限的全部字节 (过滤条件 : 需同步从服务器)
/// </summary>
public Dictionary<ulong, byte[]> GetHostDataBytesFilterSlave(Func<JNTileEntity,bool> filter = null);
/// <summary>
/// 获取指定区块的全部字节
/// </summary>
public Dictionary<ulong, byte[]> GetTileDataBytes(int index,Func<JNTileEntity,bool> filter = null);
}
public abstract class ISTileData : ISStateData
{
public JNTileEntity Entity;
//是否需要主动推送一次[一般用在从服务器获得主服务器消息后主动给客户端推送] 为什么不会自动推送因为这个实体自己没有权限
public bool IsActiveSyncOnce = false;
/// <summary>
/// 绑定实体到数据
/// </summary>
/// <param name="entity"></param>
public virtual void BindEntity(JNTileEntity entity)
{
Entity = entity;
Id = entity.Id;
}
/// <summary>
/// 获取数据位置(用于区块清除)
/// </summary>
public abstract LVector3 GetDataPosition();
}
/// <summary>
/// 支持区块的数据类
/// </summary>
public abstract class STileDataSystem<T,E> : SStateDataSystem<T>,ISTileDataSystem where T : ISTileData,new() where E : JNTileEntity, new()
{
public abstract JNTileContext<E> NodeContext { get; }
public JNSSTileServerService TileSync => Sync as JNSSTileServerService;
public bool IsMaster => TileSync is not null && TileSync.IsMaster;
public bool IsSlave => TileSync is not null && TileSync.IsSlave;
protected STileDataSystem(SStateDataEnum type) : base(type)
{
}
public override Dictionary<ulong, T> GetLatest()
{
var nodes = new Dictionary<ulong, T>();
E[] entities = null;
if (IsMaster)
{
entities = NodeContext.GetHostEntities();
}else if (IsSlave)
{
entities = NodeContext.GetEntities();
}
entities.ForEach(child =>
{
var entity = new T();
entity.BindEntity(child);
nodes.Add(child.Id,entity);
});
return nodes;
}
public override void OnUByteUpdate(Dictionary<ulong, byte[]> bytes)
{
base.OnUByteUpdate(bytes);
if (isServer)
{
OnDataSyncContext();
}
}
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);
return;
}
//主动更新
if (child.Value.IsActiveSyncOnce)
{
UBytes[child.Key] = child.Value.GetByte();
}
});
if (UBytes.Count > 0)
{
OnUByteUpdate(UBytes);
OnSendUBytes(UBytes);
UBytes.Clear();
}
}
}
public override void OnSendUBytes(Dictionary<ulong, byte[]> bytes)
{
Dictionary<ulong, byte[]> all = bytes;
Dictionary<ulong, byte[]> master = new Dictionary<ulong, byte[]>();
Dictionary<ulong, byte[]> slave = new Dictionary<ulong, byte[]>();
all.ForEach(keyValue =>
{
var entity = NodeContext.Query(keyValue.Key);
//给从服务器发送数据
if (IsMaster && entity is not null && entity.IsSyncSlave)
{
slave[keyValue.Key] = keyValue.Value;
}
});
OnSendAllData(all);
OnSendMasterData(master);
OnSendSlaveData(slave);
}
/// <summary>
/// 发送玩家数据
/// </summary>
public abstract void OnSendAllData(Dictionary<ulong, byte[]> bytes);
/// <summary>
/// 发送主服务器数据
/// </summary>
public virtual void OnSendMasterData(Dictionary<ulong, byte[]> bytes){}
/// <summary>
/// 发送从服务器数据
/// </summary>
public virtual void OnSendSlaveData(Dictionary<ulong, byte[]> bytes){}
/// <summary>
/// 将数据Data同步到Context
/// </summary>
protected virtual void OnDataSyncContext()
{
Dictionary<ulong, T> lIsTileData;
lock (Data)
{
lIsTileData = new Dictionary<ulong, T>(Data);
}
NodeContext.GetEntities().ForEach(child =>
{
//如果有则删除
if (lIsTileData.Remove(child.Id,out var data))
{
//同步不属于自己的实体
if (!child.IsHost)
{
//并且同步属性到实体中
child.TileSyncData(data);
//如果是从服务器则主动推送数据
if (IsSlave) data.IsActiveSyncOnce = true;
}
}
});
//将数据同步到实体中
foreach (var keyValue in lIsTileData)
{
var entity = NodeContext.TileSyncCreate(keyValue.Key);
if (entity is null) continue;
//如果当前是从服务器则同步的实体都是 从 主服务器 同步给 从服务器
if (IsSlave) entity.IsSyncSlave = true;
entity?.TileSyncData(keyValue.Value);
//将实体绑定到数据中
keyValue.Value.BindEntity(entity);
//如果是从服务器则主动推送数据
if (IsSlave) keyValue.Value.IsActiveSyncOnce = true;
}
}
//只更新有权限的实体
public override void Update(T data)
{
var entity = NodeContext.Query(data.Id);
if (IsMaster)
{
if (entity is null || !entity.IsHost) return;
}
base.Update(data);
}
public override void Add(T data)
{
var entity = NodeContext.Query(data.Id);
if (IsMaster)
{
if (entity is null || !entity.IsHost) return;
}
base.Add(data);
}
/// <summary>
/// 判断数据是否在区块内
/// </summary>
public bool IsTileInside(int tileId,T data)
{
var index = -1;
if (Sync is JNSSTileClientService clientService)
{
index = clientService.GetTileIndex(data.GetDataPosition());
}
if (Sync is JNSSTileServerService serverService)
{
index = serverService.GetTileIndex(data.GetDataPosition());
}
return index == tileId;
}
public void ClearTileData(int index)
{
lock (Data)
{
//需要删除的数据Id
var ids = new List<ulong>();
Data.ForEach(child =>
{
if (IsTileInside(index,child.Value)) ids.Add(child.Key);
});
//删除数据和实体
ids.ForEach(child =>
{
//销毁实体
Data[child].Entity?.Destroy();
//销毁数据
Data.Remove(child);
});
}
}
public Dictionary<ulong, byte[]> GetHostDataBytesFilterSlave(Func<JNTileEntity,bool> filter = null)
{
if (filter is null) filter = entity => true;
return GetHostDataBytes(entity => entity.IsSyncSlave && filter(entity) );
}
public Dictionary<ulong, byte[]> GetHostDataBytes(Func<JNTileEntity,bool> filter = null)
{
if (filter is null) filter = entity => true;
var data = new Dictionary<ulong, byte[]>();
lock (Data)
{
Data.ForEach(child =>
{
var entity = NodeContext.Query(child.Key);
if (entity is not null && entity.IsHost && filter(entity))
{
data[child.Key] = child.Value.GetByte();
}
});
}
return data;
}
public Dictionary<ulong, byte[]> GetTileDataBytes(int index,Func<JNTileEntity,bool> filter = null)
{
if (filter is null) filter = entity => true;
var data = new Dictionary<ulong, byte[]>();
lock (Data)
{
Data.ForEach(child =>
{
var entity = NodeContext.Query(child.Key);
if (IsTileInside(index,child.Value) && filter(entity))
{
data[child.Key] = child.Value.GetByte();
}
});
}
return data;
}
}
}