mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-11-11 00:36:00 +00:00
提交Unity 联机Pro
This commit is contained in:
3
JNFrame2/Assets/JNGame/Sync/App.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/App.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0abad4f8a6de4a98abac6955f9affe5c
|
||||
timeCreated: 1722325740
|
||||
3
JNFrame2/Assets/JNGame/Sync/App/Frame.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/App/Frame.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 320bee55a3ef4b708e8f5bd2387cfb4b
|
||||
timeCreated: 1721620349
|
||||
268
JNFrame2/Assets/JNGame/Sync/App/Frame/JNSyncFrameService.cs
Normal file
268
JNFrame2/Assets/JNGame/Sync/App/Frame/JNSyncFrameService.cs
Normal file
@@ -0,0 +1,268 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using JNGame.Sync.Frame.Service;
|
||||
using JNGame.Sync.System.View;
|
||||
using UnityEngine;
|
||||
|
||||
namespace JNGame.Sync.Frame
|
||||
{
|
||||
public abstract class JNSyncFrameService : JNSyncDefaultService
|
||||
{
|
||||
|
||||
public override int DeltaTime => _nSyncTime / _nDivideFrame;
|
||||
|
||||
//同步时间 (和服务器保持一致)
|
||||
private int _nSyncTime = 67;
|
||||
public int NSyncTime => _nSyncTime;
|
||||
//大于多少帧进行追帧
|
||||
private int _nMaxFrameBan = 4;
|
||||
public int NMaxFrameBan => _nMaxFrameBan;
|
||||
//大于多少帧进行快速追帧
|
||||
private int _nMaxFrameLoopBan = 20;
|
||||
public int NMaxFrameLoopBan => _nMaxFrameLoopBan;
|
||||
//将服务器帧数进行平分
|
||||
private int _nDivideFrame = 2;
|
||||
public int NDivideFrame => _nDivideFrame;
|
||||
|
||||
//本地帧数
|
||||
private int _nLocalFrame = -1;
|
||||
public int NLocalFrame => _nLocalFrame;
|
||||
|
||||
|
||||
//帧队列
|
||||
private Queue<JNFrameInfo> _nFrameQueue = new();
|
||||
public Queue<JNFrameInfo> NFrameQueue => _nFrameQueue;
|
||||
//暂存帧列表
|
||||
private Dictionary<int,JNFrameInfo> _nFrameTempQueue = new();
|
||||
|
||||
//是否请求后台数据
|
||||
private bool _isRequestServerData = false;
|
||||
|
||||
//帧更新
|
||||
int dtTotal = 0;
|
||||
//输入更新
|
||||
int dtInputTotal = 0;
|
||||
|
||||
//是否开始同步
|
||||
private bool _isStart = false;
|
||||
public bool IsStart => _isStart;
|
||||
|
||||
//是否在追帧
|
||||
private bool _isLoop = false;
|
||||
public bool IsLoop => _isLoop;
|
||||
|
||||
protected JNSyncFrameService() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_isStart = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 视图帧更新
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
#if (!ENTITAS_DISABLE_VISUAL_DEBUGGING && UNITY_EDITOR)
|
||||
if (paused) return;
|
||||
#endif
|
||||
if (!IsStart) return;
|
||||
base.Execute();
|
||||
int deltaTime = (int)(Time.deltaTime * 1000f);
|
||||
dtTotal += deltaTime;
|
||||
dtInputTotal += deltaTime;
|
||||
|
||||
try
|
||||
{
|
||||
int nSyncTime = this.DyTime();
|
||||
|
||||
|
||||
if (nSyncTime > 0)
|
||||
{
|
||||
|
||||
this._isLoop = false;
|
||||
|
||||
if (dtTotal > nSyncTime && _nFrameQueue.Count > 0)
|
||||
{
|
||||
this.OnRunSimulate();
|
||||
dtTotal -= nSyncTime;
|
||||
}
|
||||
|
||||
if (_nFrameQueue.Count <= 0)
|
||||
{
|
||||
dtTotal = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this._isLoop = true;
|
||||
//追帧运行 保持前端 15 帧 刷新
|
||||
long endTime = (new DateTimeOffset(DateTime.UtcNow)).ToUnixTimeMilliseconds() + 100;
|
||||
while (this.DyTime() == 0 && ((new DateTimeOffset(DateTime.UtcNow)).ToUnixTimeMilliseconds()) < endTime)
|
||||
{
|
||||
this.OnRunSimulate();
|
||||
}
|
||||
dtTotal = 0;
|
||||
}
|
||||
|
||||
|
||||
//更新输入
|
||||
if (dtInputTotal > (_nSyncTime / _nDivideFrame))
|
||||
{
|
||||
dtInputTotal = 0;
|
||||
OnRunInput();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e.Message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行输入
|
||||
/// </summary>
|
||||
public void OnRunInput()
|
||||
{
|
||||
var inputs = GetInputs();
|
||||
if (inputs.Inputs.Count > 0)
|
||||
{
|
||||
OnSendInput(inputs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自适应间隔时间
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int DyTime(){
|
||||
int dt = this._nSyncTime / this._nDivideFrame;
|
||||
int loop = dt;
|
||||
// return dt;
|
||||
|
||||
//大于nMaxFrameBan 进行 追帧
|
||||
if(this._nFrameQueue.Count > this._nMaxFrameBan) {
|
||||
|
||||
//计算超过的帧数
|
||||
int exceed = this._nFrameQueue.Count - this._nMaxFrameBan;
|
||||
int most = this._nMaxFrameLoopBan - this._nMaxFrameBan;
|
||||
int ldt = ((most - exceed) / most) * dt;
|
||||
|
||||
//自适应追帧算法
|
||||
if(exceed <= this._nMaxFrameLoopBan){
|
||||
loop = ldt;
|
||||
}else{
|
||||
loop = 0;
|
||||
}
|
||||
}else{
|
||||
loop = dt;
|
||||
}
|
||||
|
||||
return loop;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接受帧数
|
||||
/// </summary>
|
||||
public void AddFrame(JNFrameInfo frame,bool isLatestData = true)
|
||||
{
|
||||
|
||||
//我需要的下一帧
|
||||
int index = _nLocalFrame + 1;
|
||||
|
||||
//判断接受的帧是否下一帧 如果不是则加入未列入
|
||||
if (frame.Index != index){
|
||||
|
||||
_nFrameTempQueue.TryAdd(frame.Index,frame);
|
||||
|
||||
//在未列入中拿到需要的帧
|
||||
JNFrameInfo tamp = null;
|
||||
|
||||
if ((tamp = _nFrameTempQueue.GetValueOrDefault(index,null)) == null)
|
||||
{
|
||||
|
||||
var that = this;
|
||||
|
||||
//如果没有则向服务器请求我需要的帧数
|
||||
if (!that._isRequestServerData)
|
||||
{
|
||||
|
||||
that._isRequestServerData = true;
|
||||
|
||||
//请求
|
||||
that.OnServerData(this._nLocalFrame, 0).ContinueWith(infos =>
|
||||
{
|
||||
foreach (var frameInfo in infos.Frames)
|
||||
{
|
||||
if(frameInfo.Index >= this._nLocalFrame)
|
||||
that.AddFrame(frameInfo,false);
|
||||
}
|
||||
that._isRequestServerData = false;
|
||||
}).Forget();
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//如果有则覆盖
|
||||
frame = tamp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//删除临时帧
|
||||
_nFrameTempQueue.Remove(frame.Index);
|
||||
|
||||
_nLocalFrame = index;
|
||||
|
||||
//分帧插入
|
||||
_nFrameQueue.Enqueue(frame);
|
||||
for (var i = 0; i < _nDivideFrame - 1; i++) {
|
||||
_nFrameQueue.Enqueue(new JNFrameInfo());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取输入
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected abstract JNFrameInputs GetInputs();
|
||||
|
||||
/// <summary>
|
||||
/// 运行帧
|
||||
/// </summary>
|
||||
protected virtual void OnRunSimulate()
|
||||
{
|
||||
Debug.Log("Run OnRunSimulate");
|
||||
if (!(NFrameQueue.TryDequeue(out var frame))) return;
|
||||
Simulate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送帧数据
|
||||
/// </summary>
|
||||
/// <param name="inputs"></param>
|
||||
protected abstract void OnSendInput(JNFrameInputs inputs);
|
||||
|
||||
/// <summary>
|
||||
/// 获取帧数据
|
||||
/// </summary>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="end"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract UniTask<JNFrameInfos> OnServerData(int start,int end);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d71e08d3cee3430f9d66f639dde67f0e
|
||||
timeCreated: 1721613418
|
||||
3
JNFrame2/Assets/JNGame/Sync/App/State.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/App/State.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2a4a93fcc834d3d85c39f33416f5bed
|
||||
timeCreated: 1721807044
|
||||
@@ -0,0 +1,66 @@
|
||||
using JNGame.Sync.Entity;
|
||||
using JNGame.Sync.Frame;
|
||||
using UnityEngine;
|
||||
|
||||
namespace JNGame.Sync.State
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态同步 [客户端]
|
||||
/// 客户端负责视图层拿数据层数据渲染
|
||||
/// 注:客户端无论如何不能有逻辑层
|
||||
/// </summary>
|
||||
public class JNSStateClientService : JNSyncDefaultService
|
||||
{
|
||||
//是否开始
|
||||
private bool _isStart = false;
|
||||
public bool IsStart => _isStart;
|
||||
public override bool IsStartGame => IsStart;
|
||||
public override int DeltaTime => 1000 / 15;
|
||||
|
||||
//累计待处理时间
|
||||
protected int dtTime;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_isStart = true;
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
|
||||
#if (!ENTITAS_DISABLE_VISUAL_DEBUGGING && UNITY_EDITOR)
|
||||
if (paused) return;
|
||||
#endif
|
||||
if (!IsStart) return;
|
||||
base.Execute();
|
||||
dtTime += (int)(Time.deltaTime * 1000);
|
||||
if (DeltaTime <= dtTime)
|
||||
{
|
||||
dtTime -= DeltaTime;
|
||||
//执行逻辑
|
||||
OnRunSimulate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 客户端没有逻辑实体
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public sealed override JNContexts CreateContexts()
|
||||
{
|
||||
return base.CreateContexts();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行逻辑
|
||||
/// </summary>
|
||||
protected virtual void OnRunSimulate()
|
||||
{
|
||||
Simulate();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43ab652bc3574b6e99d3db5a4828f56e
|
||||
timeCreated: 1721810431
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using JNGame.Sync.Frame;
|
||||
using UnityEngine;
|
||||
|
||||
namespace JNGame.Sync.State
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态同步 [服务器]
|
||||
/// 服务器负责逻辑层执行并且推送信息到数据层
|
||||
/// 注:服务器可以有视图层 一般用于debug 发布后没必要有视图层
|
||||
/// </summary>
|
||||
public class JNSStateServerService : JNSyncDefaultService
|
||||
{
|
||||
|
||||
//累计待处理时间
|
||||
protected int dtTime;
|
||||
|
||||
//服务器每帧时间
|
||||
public override int DeltaTime => 1000 / 15;
|
||||
|
||||
//是否开始
|
||||
private bool _isStart = false;
|
||||
public bool IsStart => _isStart;
|
||||
|
||||
public override bool IsStartGame => _isStart;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_isStart = true;
|
||||
}
|
||||
public override void Execute()
|
||||
{
|
||||
|
||||
#if (!ENTITAS_DISABLE_VISUAL_DEBUGGING && UNITY_EDITOR)
|
||||
if (paused) return;
|
||||
#endif
|
||||
if (!IsStart) return;
|
||||
base.Execute();
|
||||
dtTime += (int)(Time.deltaTime * 1000);
|
||||
if (DeltaTime <= dtTime)
|
||||
{
|
||||
dtTime -= DeltaTime;
|
||||
//执行逻辑
|
||||
OnRunSimulate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行逻辑
|
||||
/// </summary>
|
||||
protected virtual void OnRunSimulate()
|
||||
{
|
||||
Simulate();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f339d578d3d4c4d9b060962aa7acd60
|
||||
timeCreated: 1721810407
|
||||
3
JNFrame2/Assets/JNGame/Sync/App/Tile.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/App/Tile.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92a6717274b3454080f312f12c622062
|
||||
timeCreated: 1722239864
|
||||
3
JNFrame2/Assets/JNGame/Sync/App/Tile/Entity.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/App/Tile/Entity.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea749c86d5e64d3d95b47485fb1e93b8
|
||||
timeCreated: 1722324674
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 248fceb6707f455e85a5c9e3994518af
|
||||
timeCreated: 1722334056
|
||||
@@ -0,0 +1,29 @@
|
||||
using JNGame.Sync.Entity.Component;
|
||||
using NotImplementedException = System.NotImplementedException;
|
||||
|
||||
namespace JNGame.Sync.State.Tile.Entity.Component
|
||||
{
|
||||
/// <summary>
|
||||
/// 拥有区块的组件
|
||||
/// </summary>
|
||||
public class JNTileComponent : JNComponent,IJNTileCycle
|
||||
{
|
||||
|
||||
public bool IsHost {
|
||||
get
|
||||
{
|
||||
if (Entity is IJNTileEntity entity)
|
||||
{
|
||||
return entity.IsHost;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnTileEnter(){}
|
||||
|
||||
public virtual void OnTileExit(){}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca6de04e46e04e6ebb4f4bb7de345e66
|
||||
timeCreated: 1722334062
|
||||
79
JNFrame2/Assets/JNGame/Sync/App/Tile/Entity/JNTileContext.cs
Normal file
79
JNFrame2/Assets/JNGame/Sync/App/Tile/Entity/JNTileContext.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Sync.Entity;
|
||||
using JNGame.Sync.Frame.Entity;
|
||||
using JNGame.Sync.Frame.Entity.Components;
|
||||
|
||||
namespace JNGame.Sync.State.Tile.Entity
|
||||
{
|
||||
|
||||
public class JNTileContext<T> : JNContext<T> where T : JNTileEntity, new()
|
||||
{
|
||||
|
||||
private JNSSTileServerService SyncTile => base.Sync as JNSSTileServerService;
|
||||
|
||||
public override void OnSyncUpdate()
|
||||
{
|
||||
foreach (var entity in base.GetEntities())
|
||||
{
|
||||
|
||||
//生命周期
|
||||
bool isContains = SyncTile.IsContains(entity.Position);
|
||||
bool isHost = entity.IsHost;
|
||||
entity.IsHost = isContains;
|
||||
|
||||
//区块进入生命周期
|
||||
if (!isHost && isContains)
|
||||
{
|
||||
entity.OnTileEnter();
|
||||
}
|
||||
//区块移出生命周期
|
||||
if (isHost && !isContains)
|
||||
{
|
||||
entity.OnTileExit();
|
||||
}
|
||||
|
||||
//判断实体是否在所属区块 在则 更新
|
||||
if (entity.IsHost)
|
||||
{
|
||||
entity.OnSyncUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public T TileSyncCreate(long id)
|
||||
{
|
||||
var entity = NewEntity();
|
||||
entity.OnInit(this,id);
|
||||
entity.IsHost = false;
|
||||
BindComponent(entity);
|
||||
BindLifeCycle(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 有权限的实体
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T[] GetHostEntities()
|
||||
{
|
||||
if (_entitiesCache is null) return Array.Empty<T>();
|
||||
var items = new List<T>();
|
||||
foreach (var item in _entitiesCache)
|
||||
{
|
||||
if (item.IsHost)
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
return items.ToArray();
|
||||
}
|
||||
|
||||
protected override T BindInitialize(T entity)
|
||||
{
|
||||
entity.IsHost = true;
|
||||
return base.BindInitialize(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a7efa2f5ec14741bf38d07ca72008fc
|
||||
timeCreated: 1722325979
|
||||
@@ -0,0 +1,15 @@
|
||||
using Entitas;
|
||||
using JNGame.Sync.Entity;
|
||||
|
||||
namespace JNGame.Sync.State.Tile.Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 区块实体容器集合
|
||||
/// </summary>
|
||||
public class JNTileContexts : JNContexts
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 469128164a4343638bbf231f78a97ea0
|
||||
timeCreated: 1722325937
|
||||
55
JNFrame2/Assets/JNGame/Sync/App/Tile/Entity/JNTileEntity.cs
Normal file
55
JNFrame2/Assets/JNGame/Sync/App/Tile/Entity/JNTileEntity.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using JNGame.Sync.Entity;
|
||||
using JNGame.Sync.Frame.Entity.Components;
|
||||
using JNGame.Sync.State.Tile.Entity.Component;
|
||||
using JNGame.Sync.System.Data;
|
||||
using NotImplementedException = System.NotImplementedException;
|
||||
|
||||
namespace JNGame.Sync.State.Tile.Entity
|
||||
{
|
||||
|
||||
public interface IJNTileEntity
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 是否所属当前区块
|
||||
/// </summary>
|
||||
public bool IsHost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 区块同步属性(通过网络同步过来的实体数据)
|
||||
/// </summary>
|
||||
public void TileSyncData(ISTileData data);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 支持区块的实体类 拥有区块生命周期
|
||||
/// </summary>
|
||||
public abstract class JNTileEntity : JNEntity,IJNTileCycle,IJNTileEntity
|
||||
{
|
||||
|
||||
public bool IsHost { get; set; } = false;
|
||||
|
||||
public abstract void TileSyncData(ISTileData data);
|
||||
|
||||
//区块生命周期
|
||||
public virtual void OnTileEnter()
|
||||
{
|
||||
//给组件生命周期
|
||||
foreach (var component in GetComponents())
|
||||
{
|
||||
(component as JNTileComponent)?.OnTileEnter();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnTileExit()
|
||||
{
|
||||
//给组件生命周期
|
||||
foreach (var component in GetComponents())
|
||||
{
|
||||
(component as JNTileComponent)?.OnTileExit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18ef2e720b964a5a89d45a4ee27ef234
|
||||
timeCreated: 1722324716
|
||||
17
JNFrame2/Assets/JNGame/Sync/App/Tile/IJNTileCycle.cs
Normal file
17
JNFrame2/Assets/JNGame/Sync/App/Tile/IJNTileCycle.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace JNGame.Sync.State.Tile
|
||||
{
|
||||
public interface IJNTileCycle
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 进入当前区块
|
||||
/// </summary>
|
||||
public void OnTileEnter();
|
||||
|
||||
/// <summary>
|
||||
/// 退出当前区块
|
||||
/// </summary>
|
||||
public void OnTileExit();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ffa11c9e0cfd4fd18a10a15e1a52e282
|
||||
timeCreated: 1722325335
|
||||
122
JNFrame2/Assets/JNGame/Sync/App/Tile/JNSSTileClientService.cs
Normal file
122
JNFrame2/Assets/JNGame/Sync/App/Tile/JNSSTileClientService.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace JNGame.Sync.State.Tile
|
||||
{
|
||||
/// <summary>
|
||||
/// 瓦片状态同步客户端
|
||||
/// </summary>
|
||||
public abstract class JNSSTileClientService : JNSStateClientService
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 当前显示的Tile
|
||||
/// </summary>
|
||||
protected List<int> TileShow = new ();
|
||||
|
||||
/// <summary>
|
||||
/// 区块索引组
|
||||
/// </summary>
|
||||
protected abstract int[][] Tiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 区块大小
|
||||
/// </summary>
|
||||
protected abstract int TileSize { get; }
|
||||
|
||||
public bool IsTileIndex((int X, int Y) xTuple)
|
||||
{
|
||||
if (xTuple.X >= 0 && xTuple.Y >= 0)
|
||||
{
|
||||
return xTuple.Y <= Tiles.Length && xTuple.X <= Tiles[0].Length;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public int GetTileIndex(LVector3 pos)
|
||||
{
|
||||
(int x, int y) = GetXYIndex(pos);
|
||||
return Tiles[y][x];
|
||||
}
|
||||
|
||||
public (int X, int Y) GetXYIndex(LVector3 pos)
|
||||
{
|
||||
// 遍历数组
|
||||
for (int y = 0; y < Tiles.Length; y++)
|
||||
{
|
||||
for (int x = 0; x < Tiles[y].Length; x++)
|
||||
{
|
||||
// 检查当前元素是否非零
|
||||
if (Tiles[y][x] != 0)
|
||||
{
|
||||
|
||||
//判断是否所在区块
|
||||
var min = new LVector2(x.ToLFloat() * TileSize,y.ToLFloat() * TileSize);
|
||||
var max = new LVector2((x + 1).ToLFloat() * TileSize,(y + 1).ToLFloat() * TileSize);
|
||||
|
||||
// 假设LVector2是一个包含X和Y属性的结构体或类
|
||||
// 检查X坐标是否在范围内
|
||||
if (pos.x < min.x || pos.x >= max.x)
|
||||
{
|
||||
continue; // X坐标不在范围内
|
||||
}
|
||||
// 检查Y坐标是否在范围内
|
||||
if (pos.z < min.y || pos.z >= max.y)
|
||||
{
|
||||
continue; // Y坐标不在范围内
|
||||
}
|
||||
|
||||
return (x,y);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0,0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取九宫格Index
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<int> GetTileGridIndex(LVector3 pos)
|
||||
{
|
||||
|
||||
(int x, int y) = GetXYIndex(pos);
|
||||
List<int> grid = new List<int>();
|
||||
|
||||
// 填充九宫格
|
||||
for (int i = -1; i <= 1; i++)
|
||||
{
|
||||
for (int j = -1; j <= 1; j++)
|
||||
{
|
||||
int tempX = x + i;
|
||||
int tempY = y + j; // 注意这里j+1+1是因为数组第二维存储的是y坐标
|
||||
if (IsTileIndex((tempX,tempY))) grid.Add(Tiles[tempY][tempX]);
|
||||
}
|
||||
}
|
||||
|
||||
return grid;
|
||||
|
||||
}
|
||||
|
||||
public void AddTileShow(int index)
|
||||
{
|
||||
if (!(TileShow.Contains(index)))
|
||||
{
|
||||
TileShow.Add(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveTileShow(int index)
|
||||
{
|
||||
if (TileShow.Contains(index))
|
||||
{
|
||||
TileShow.Remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a0304ca48534abb92b8e6537ae8397d
|
||||
timeCreated: 1722493209
|
||||
215
JNFrame2/Assets/JNGame/Sync/App/Tile/JNSSTileServerService.cs
Normal file
215
JNFrame2/Assets/JNGame/Sync/App/Tile/JNSSTileServerService.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using JNGame.Math;
|
||||
using JNGame.Sync.Entity;
|
||||
using JNGame.Sync.Frame.Service;
|
||||
using JNGame.Sync.State.Tile.Entity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace JNGame.Sync.State.Tile
|
||||
{
|
||||
/// <summary>
|
||||
/// 瓦片状态同步 : 用于开放世界类型的游戏 将 世界分多个Tile 不同的Service管理
|
||||
/// </summary>
|
||||
public abstract partial class JNSSTileServerService : JNSStateServerService
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 区块索引组
|
||||
/// </summary>
|
||||
protected abstract int[][] Tiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 区块大小
|
||||
/// </summary>
|
||||
protected abstract int TileSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 区块ID
|
||||
/// 用于管理当前 Service 负责的区块ID
|
||||
/// </summary>
|
||||
public int TID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 区块最大最小位置
|
||||
/// </summary>
|
||||
public LVector2 MinContains{ get; private set; }
|
||||
public LVector2 MaxContains{ get; private set; }
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
OnInit();
|
||||
}
|
||||
|
||||
protected virtual async Task OnInit()
|
||||
{
|
||||
try
|
||||
{
|
||||
//获取权限
|
||||
this.TID = await FetchTileId();
|
||||
|
||||
//更新范围
|
||||
UpdateContains();
|
||||
base.Initialize();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed override JNContexts CreateContexts()
|
||||
{
|
||||
return CreateTileContexts();
|
||||
}
|
||||
|
||||
public sealed override JNRandomSystem CreateRandom()
|
||||
{
|
||||
//根据区块设置Id 起始值
|
||||
var random = base.CreateRandom();
|
||||
random.SetIdValue(100000000000L * TID);
|
||||
return random;
|
||||
}
|
||||
|
||||
protected virtual JNTileContexts CreateTileContexts()
|
||||
{
|
||||
return new JNTileContexts();
|
||||
}
|
||||
|
||||
public bool IsTileIndex((int X, int Y) xTuple)
|
||||
{
|
||||
if (xTuple.X >= 0 && xTuple.Y >= 0)
|
||||
{
|
||||
return xTuple.Y <= Tiles.Length && xTuple.X <= Tiles[0].Length;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新区块范围
|
||||
/// </summary>
|
||||
public void UpdateContains()
|
||||
{
|
||||
MinContains = new LVector2();
|
||||
MaxContains = new LVector2();
|
||||
|
||||
try
|
||||
{
|
||||
//更新区块最大最小位置
|
||||
(LVector2 max, LVector2 min) = GetTileContains(TID);
|
||||
MinContains = min;
|
||||
MaxContains = max;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// ignored
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断位置是否在区块内
|
||||
/// </summary>
|
||||
/// <param name="pos"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsContains(LVector3 position)
|
||||
{
|
||||
// 假设LVector2是一个包含X和Y属性的结构体或类
|
||||
// 检查X坐标是否在范围内
|
||||
if (position.x < MinContains.x || position.x >= MaxContains.x)
|
||||
{
|
||||
return false; // X坐标不在范围内
|
||||
}
|
||||
|
||||
// 检查Y坐标是否在范围内
|
||||
if (position.z < MinContains.y || position.z >= MaxContains.y)
|
||||
{
|
||||
return false; // Y坐标不在范围内
|
||||
}
|
||||
|
||||
// 如果X和Y坐标都在范围内,则返回true
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据TileId 获取最大最小范围
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public (LVector2 Max,LVector2 Min) GetTileContains(int index)
|
||||
{
|
||||
(int X, int Y) = GetTileIDXY(index);
|
||||
var min = new LVector2(X.ToLFloat() * TileSize,Y.ToLFloat() * TileSize);
|
||||
var max = new LVector2((X + 1).ToLFloat() * TileSize,(Y + 1).ToLFloat() * TileSize);
|
||||
return (max,min);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取TileID X Y
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public (int X, int Y) GetTileIDXY(int index)
|
||||
{
|
||||
|
||||
// 遍历数组
|
||||
for (int y = 0; y < Tiles.Length; y++)
|
||||
{
|
||||
for (int x = 0; x < Tiles[y].Length; x++)
|
||||
{
|
||||
// 检查当前元素是否非零
|
||||
if (Tiles[y][x] != 0 && Tiles[y][x] == index)
|
||||
{
|
||||
// 返回找到的坐标
|
||||
return (x,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取九宫格Index
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<int> GetTileGridIndex(int index)
|
||||
{
|
||||
|
||||
List<int> grid = new List<int>();
|
||||
(int X, int Y) = GetTileIDXY(index);
|
||||
// 填充九宫格
|
||||
for (int i = -1; i <= 1; i++)
|
||||
{
|
||||
for (int j = -1; j <= 1; j++)
|
||||
{
|
||||
int tempX = X + i;
|
||||
int tempY = Y + j; // 注意这里j+1+1是因为数组第二维存储的是y坐标
|
||||
if (IsTileIndex((tempX,tempY))) grid.Add(Tiles[tempY][tempX]);
|
||||
}
|
||||
}
|
||||
|
||||
return grid;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 TileId 权限 (返回多少 Service 则管理所属Tile)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected abstract UniTask<int> FetchTileId();
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前连接的区块
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual int[] GetLinkTiles()
|
||||
{
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3489829ddd184475a96364d243ea97b8
|
||||
timeCreated: 1722240437
|
||||
3
JNFrame2/Assets/JNGame/Sync/Debuger.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/Debuger.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f2e7564f99f4ca39f6c361b079050f1
|
||||
timeCreated: 1723694093
|
||||
76
JNFrame2/Assets/JNGame/Sync/Debuger/JNTileServerDebuger.cs
Normal file
76
JNFrame2/Assets/JNGame/Sync/Debuger/JNTileServerDebuger.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Collections;
|
||||
using JNGame.Math;
|
||||
using JNGame.Sync.State.Tile;
|
||||
using UnityEngine;
|
||||
|
||||
namespace JNGame.Sync.Debuger
|
||||
{
|
||||
public class JNTileServerDebuger : SingletonScene<JNTileServerDebuger>
|
||||
{
|
||||
|
||||
private List<JNSSTileServerService> _services = new List<JNSSTileServerService>();
|
||||
|
||||
public void Add(JNSSTileServerService service)
|
||||
{
|
||||
_services.Add(service);
|
||||
}
|
||||
|
||||
public void Remove(JNSSTileServerService service)
|
||||
{
|
||||
_services.Remove(service);
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
|
||||
_services.ForEach(DebugService);
|
||||
|
||||
}
|
||||
|
||||
private void DebugService(JNSSTileServerService service)
|
||||
{
|
||||
|
||||
if (!(service.IsStart)) return;
|
||||
|
||||
//绘制权限区块
|
||||
DrawContains(service.MaxContains,service.MinContains,Color.red);
|
||||
|
||||
//绘制连接区域
|
||||
service.GetLinkTiles().ForEach(index =>
|
||||
{
|
||||
(LVector2 max, LVector2 min) = service.GetTileContains(index);
|
||||
DrawContains(max,min,Color.cyan);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制区域
|
||||
/// </summary>
|
||||
/// <param name="MaxContains"></param>
|
||||
/// <param name="MinContains"></param>
|
||||
private void DrawContains(LVector2 MaxContains,LVector2 MinContains,Color color)
|
||||
{
|
||||
// 绘制正方形
|
||||
// 计算正方形的四个角点
|
||||
Vector3 topLeft = new Vector3(MaxContains.x,0, MaxContains.y);
|
||||
Vector3 topRight = new Vector3(MinContains.x,0, MaxContains.y);
|
||||
Vector3 bottomLeft = new Vector3(MaxContains.x,0, MinContains.y);
|
||||
Vector3 bottomRight = new Vector3(MinContains.x,0, MinContains.y);
|
||||
|
||||
// 使用Gizmos.DrawLine来绘制正方形的四条边
|
||||
Gizmos.color = color; // 设置Gizmos的颜色
|
||||
|
||||
// 顶部边
|
||||
Gizmos.DrawLine(topLeft, topRight);
|
||||
// 底部边
|
||||
Gizmos.DrawLine(bottomLeft, bottomRight);
|
||||
// 左侧边
|
||||
Gizmos.DrawLine(topLeft, bottomLeft);
|
||||
// 右侧边
|
||||
Gizmos.DrawLine(topRight, bottomRight);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3af567e286384e418dc55e261f8e31c8
|
||||
timeCreated: 1723694204
|
||||
0
JNFrame2/Assets/JNGame/Sync/Entity.meta
Normal file
0
JNFrame2/Assets/JNGame/Sync/Entity.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/Entity/Component.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/Entity/Component.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35611e159b144494beb3985bb0aa884a
|
||||
timeCreated: 1720700493
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cc4a62c9f984472a75d9dcce3e117bb
|
||||
timeCreated: 1720864778
|
||||
@@ -0,0 +1,12 @@
|
||||
using Entitas;
|
||||
using JNGame.Math;
|
||||
using JNGame.Sync.Entity.Component;
|
||||
using JNGame.Sync.Frame.Entity.Components;
|
||||
|
||||
namespace JNGame.Sync.Frame.Entity.Component.Components
|
||||
{
|
||||
public class JNTransformComponent : JNComponent
|
||||
{
|
||||
public LVector3 Position = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de8c1bdf52c14049b969b7d4ec7052cd
|
||||
timeCreated: 1720700573
|
||||
30
JNFrame2/Assets/JNGame/Sync/Entity/Component/JNComponent.cs
Normal file
30
JNFrame2/Assets/JNGame/Sync/Entity/Component/JNComponent.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Entitas;
|
||||
using JNGame.Sync.System;
|
||||
using NotImplementedException = System.NotImplementedException;
|
||||
|
||||
namespace JNGame.Sync.Entity.Component
|
||||
{
|
||||
/// <summary>
|
||||
/// 组件
|
||||
/// </summary>
|
||||
public class JNComponent : IComponent,IJNSyncCycle
|
||||
{
|
||||
|
||||
public IJNEntity Entity;
|
||||
|
||||
public void OnInit(IJNEntity entity)
|
||||
{
|
||||
this.Entity = entity;
|
||||
}
|
||||
|
||||
public T GetSystem<T>() where T : SLogicSystem
|
||||
{
|
||||
return Entity.GetContext().GetSync().GetSystem<T>();
|
||||
}
|
||||
|
||||
//生命周期
|
||||
public virtual void OnSyncStart(){}
|
||||
public virtual void OnSyncUpdate(){}
|
||||
public virtual void OnSyncDestroy(){}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d7ede39ee1a4ac6a40ea7e0b5334765
|
||||
timeCreated: 1720864842
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Entitas;
|
||||
using JNGame.EntitasExtend;
|
||||
using JNGame.Sync.Frame.Entity.Component.Components;
|
||||
using JNGame.Util.Types;
|
||||
|
||||
namespace JNGame.Sync.Frame.Entity.Components
|
||||
{
|
||||
public class JNEntityLookup : EntitasExtend.JNLookup
|
||||
{
|
||||
|
||||
//位置组件
|
||||
public int Transform { get; set; }
|
||||
|
||||
//绑定索引
|
||||
protected override void BindIndex()
|
||||
{
|
||||
Transform = Next();
|
||||
}
|
||||
|
||||
//绑定类型
|
||||
protected override void BindType(KeyValue<int, Type> types)
|
||||
{
|
||||
types.Add(Transform,typeof(JNTransformComponent));
|
||||
}
|
||||
|
||||
//查询组件
|
||||
public T Query<T>(Entitas.Entity entity) where T : class, IComponent
|
||||
{
|
||||
return entity.GetComponent(GetIndex<T>()) as T;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76bb4b74188d47beb992777c9fc19d8c
|
||||
timeCreated: 1720749419
|
||||
106
JNFrame2/Assets/JNGame/Sync/Entity/JNContext.cs
Normal file
106
JNFrame2/Assets/JNGame/Sync/Entity/JNContext.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using Entitas;
|
||||
using JNGame.Sync.Entity;
|
||||
using JNGame.Sync.Frame.Entity.Component.Components;
|
||||
using JNGame.Sync.Frame.Entity.Components;
|
||||
using JNGame.Sync.System;
|
||||
|
||||
namespace JNGame.Sync.Frame.Entity
|
||||
{
|
||||
public abstract class JNContext<T> : Entitas.Context<T>,IJNContext where T : JNEntity, new()
|
||||
{
|
||||
|
||||
public JNSyncService Sync { get; private set; }
|
||||
|
||||
public JNEntityLookup CLookup;
|
||||
|
||||
public JNContext(): base((new T()).NewCLookup().Count, () => new T())
|
||||
{
|
||||
CLookup = (new T()).NewCLookup();
|
||||
}
|
||||
|
||||
public JNContext(int totalComponents, Func<T> entityFactory) : base(totalComponents, entityFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public JNContext(int totalComponents, int startCreationIndex, ContextInfo contextInfo, Func<IEntity, IAERC> aercFactory, Func<T> entityFactory) : base(totalComponents, startCreationIndex, contextInfo, aercFactory, entityFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public JNSyncService GetSync()
|
||||
{
|
||||
return Sync;
|
||||
}
|
||||
|
||||
public void InitReference(JNSyncService data)
|
||||
{
|
||||
Sync = data;
|
||||
}
|
||||
|
||||
public T GetService<T>() where T : SLogicSystem
|
||||
{
|
||||
return Sync.GetSystem<T>();
|
||||
}
|
||||
|
||||
protected T NewEntity()
|
||||
{
|
||||
|
||||
T entity = base.CreateEntity();
|
||||
//绑定组件查询器
|
||||
entity.CLookup = CLookup;
|
||||
return entity;
|
||||
|
||||
}
|
||||
|
||||
protected virtual T BindInitialize(T entity)
|
||||
{
|
||||
entity.OnInit(this);
|
||||
return entity;
|
||||
}
|
||||
protected virtual T BindComponent(T entity)
|
||||
{
|
||||
entity.AddComponent<JNTransformComponent>();
|
||||
return entity;
|
||||
}
|
||||
protected virtual T BindLifeCycle(T entity)
|
||||
{
|
||||
entity.OnSyncStart();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public sealed override T CreateEntity()
|
||||
{
|
||||
var entity = NewEntity();
|
||||
BindInitialize(entity);
|
||||
BindComponent(entity);
|
||||
BindLifeCycle(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
//帧同步 生命周期
|
||||
public virtual void OnSyncStart(){}
|
||||
|
||||
public virtual void OnSyncUpdate()
|
||||
{
|
||||
//给实体推帧
|
||||
foreach (var entity in GetEntities())
|
||||
{
|
||||
if (entity.isEnabled)
|
||||
{
|
||||
entity.OnSyncUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnSyncDestroy()
|
||||
{}
|
||||
}
|
||||
|
||||
public interface IJNContext : IJNSyncCycle
|
||||
{
|
||||
public abstract JNSyncService GetSync();
|
||||
public abstract void InitReference(JNSyncService data);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/Entity/JNContext.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/Entity/JNContext.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3ea713c89fe42fd98c9b84f2ec623f8
|
||||
timeCreated: 1721187670
|
||||
53
JNFrame2/Assets/JNGame/Sync/Entity/JNContexts.cs
Normal file
53
JNFrame2/Assets/JNGame/Sync/Entity/JNContexts.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using Entitas;
|
||||
using JNGame.Sync.Frame.Entity;
|
||||
|
||||
namespace JNGame.Sync.Entity
|
||||
{
|
||||
public class JNContexts : Entitas.IContexts
|
||||
{
|
||||
public virtual IContext[] allContexts => Array.Empty<IContext>();
|
||||
|
||||
public JNSyncService Sync;
|
||||
|
||||
public JNContexts()
|
||||
{
|
||||
for (var i = 0; i < allContexts.Length; i++)
|
||||
{
|
||||
(allContexts[i] as IJNContext)?.OnSyncStart();
|
||||
}
|
||||
}
|
||||
|
||||
//给所有实体推帧
|
||||
public void Simulate()
|
||||
{
|
||||
for (var i = 0; i < allContexts.Length; i++)
|
||||
{
|
||||
(allContexts[i] as IJNContext)?.OnSyncUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public T GetContext<T>() where T : IContext
|
||||
{
|
||||
|
||||
for (int i = 0; i < allContexts.Length; i++)
|
||||
{
|
||||
if (allContexts[i] is T) return (T)allContexts[i];
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"No context of type {typeof(T).Name} was found.");
|
||||
|
||||
}
|
||||
|
||||
//注入 JNSyncFrameService
|
||||
public void InitReference(JNSyncService data)
|
||||
{
|
||||
Sync = data;
|
||||
foreach (var context in allContexts)
|
||||
{
|
||||
(context as IJNContext)?.InitReference(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/Entity/JNContexts.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/Entity/JNContexts.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f17062daa45a431a9ff4377391dfa708
|
||||
timeCreated: 1721187474
|
||||
150
JNFrame2/Assets/JNGame/Sync/Entity/JNEntity.cs
Normal file
150
JNFrame2/Assets/JNGame/Sync/Entity/JNEntity.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using DotRecast.Core.Collections;
|
||||
using JNGame.Math;
|
||||
using JNGame.Sync.Entity.Component;
|
||||
using JNGame.Sync.Frame.Entity;
|
||||
using JNGame.Sync.Frame.Entity.Component.Components;
|
||||
using JNGame.Sync.Frame.Entity.Components;
|
||||
using JNGame.Sync.Frame.Service;
|
||||
using JNGame.Sync.System;
|
||||
|
||||
namespace JNGame.Sync.Entity
|
||||
{
|
||||
|
||||
public interface IJNEntity : IJNSyncCycle,IJNSyncId
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 坐标
|
||||
/// </summary>
|
||||
public JNTransformComponent Transform { get; }
|
||||
/// <summary>
|
||||
/// 位置
|
||||
/// </summary>
|
||||
public LVector3 Position { get; }
|
||||
|
||||
public IJNContext GetContext();
|
||||
|
||||
public T GetComponent<T>() where T : JNComponent;
|
||||
|
||||
}
|
||||
|
||||
public abstract class JNEntity : Entitas.Entity,IJNEntity,IComparable
|
||||
{
|
||||
|
||||
private long _id;
|
||||
public long Id => _id;
|
||||
|
||||
public IJNContext Context { get; private set; }
|
||||
|
||||
//组件Lookup
|
||||
public JNEntityLookup CLookup{ get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 坐标
|
||||
/// </summary>
|
||||
public JNTransformComponent Transform => CLookup.Query<JNTransformComponent>(this);
|
||||
/// <summary>
|
||||
/// 位置
|
||||
/// </summary>
|
||||
public LVector3 Position => Transform.Position;
|
||||
|
||||
public void OnInit(IJNContext context,long id = 0)
|
||||
{
|
||||
Context = context;
|
||||
_id = id;
|
||||
if (_id <= 0)
|
||||
{
|
||||
_id = GetSystem<JNRandomSystem>().NextId();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract JNEntityLookup NewCLookup();
|
||||
|
||||
public T GetSystem<T>() where T : SLogicSystem
|
||||
{
|
||||
return Context.GetSync().GetSystem<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取组件
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public T GetComponent<T>() where T : JNComponent
|
||||
{
|
||||
return CLookup.Query<T>(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加组件
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public JNComponent AddComponent<T>() where T : JNComponent,new()
|
||||
{
|
||||
int index = CLookup.GetIndex<T>();
|
||||
var temp = CreateComponent<T>(index);
|
||||
temp.OnInit(this);
|
||||
base.AddComponent(index,temp);
|
||||
temp.OnSyncStart();
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
public void RemoveComponent<T>() where T : JNComponent,new()
|
||||
{
|
||||
int index = CLookup.GetIndex<T>();
|
||||
var component = CLookup.Query<T>(this);
|
||||
component.OnSyncDestroy();
|
||||
base.RemoveComponent(index);
|
||||
}
|
||||
|
||||
|
||||
public override void RemoveAllComponents()
|
||||
{
|
||||
GetComponents().ForEach(child => (child as JNComponent)?.OnSyncDestroy());
|
||||
base.RemoveAllComponents();
|
||||
}
|
||||
|
||||
|
||||
//实现排序实现
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj is IJNEntity entity)
|
||||
{
|
||||
return Id.CompareTo(entity.Id);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public IJNContext GetContext()
|
||||
{
|
||||
return Context;
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
OnSyncDestroy();
|
||||
RemoveAllComponents();
|
||||
base.Destroy();
|
||||
}
|
||||
|
||||
//生命周期
|
||||
public virtual void OnSyncStart(){}
|
||||
|
||||
public virtual void OnSyncUpdate()
|
||||
{
|
||||
//给组件推帧
|
||||
foreach (var component in GetComponents())
|
||||
{
|
||||
(component as JNComponent)?.OnSyncUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnSyncDestroy()
|
||||
{}
|
||||
}
|
||||
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/Entity/JNEntity.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/Entity/JNEntity.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8180ef801954d1e90f4d203c632063e
|
||||
timeCreated: 1721187721
|
||||
25
JNFrame2/Assets/JNGame/Sync/IJNSyncCycle.cs
Normal file
25
JNFrame2/Assets/JNGame/Sync/IJNSyncCycle.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace JNGame.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// 生命周期
|
||||
/// </summary>
|
||||
public interface IJNSyncCycle
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 实体初始化
|
||||
/// </summary>
|
||||
public void OnSyncStart();
|
||||
|
||||
/// <summary>
|
||||
/// 实体每帧刷新
|
||||
/// </summary>
|
||||
public void OnSyncUpdate();
|
||||
|
||||
/// <summary>
|
||||
/// 实体销毁
|
||||
/// </summary>
|
||||
public void OnSyncDestroy();
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/IJNSyncCycle.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/IJNSyncCycle.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9b0d4a3407247b29958bad069628936
|
||||
timeCreated: 1720865355
|
||||
9
JNFrame2/Assets/JNGame/Sync/IJNSyncId.cs
Normal file
9
JNFrame2/Assets/JNGame/Sync/IJNSyncId.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace JNGame.Sync
|
||||
{
|
||||
public interface IJNSyncId
|
||||
{
|
||||
|
||||
public long Id { get; }
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/IJNSyncId.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/IJNSyncId.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9c014d698a843c7b1e17ee103eb5a8c
|
||||
timeCreated: 1721634659
|
||||
16
JNFrame2/Assets/JNGame/Sync/JNBaseSystem.cs
Normal file
16
JNFrame2/Assets/JNGame/Sync/JNBaseSystem.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Entitas;
|
||||
|
||||
namespace JNGame.Sync
|
||||
{
|
||||
public abstract class JNBaseSystem : ISystem
|
||||
{
|
||||
|
||||
public JNSyncService Sync;
|
||||
|
||||
public T GetSystem<T>() where T : JNBaseSystem
|
||||
{
|
||||
return Sync.GetSystem<T>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/JNBaseSystem.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/JNBaseSystem.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 878e4f4a669d40e99284aa285508aae2
|
||||
timeCreated: 1720690204
|
||||
140
JNFrame2/Assets/JNGame/Sync/JNSyncDefaultService.cs
Normal file
140
JNFrame2/Assets/JNGame/Sync/JNSyncDefaultService.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Entitas;
|
||||
using JNGame.Sync.Entity;
|
||||
using JNGame.Sync.Frame.Entity;
|
||||
using JNGame.Sync.Frame.Service;
|
||||
using JNGame.Sync.System;
|
||||
using JNGame.Sync.System.View;
|
||||
using UnityEngine;
|
||||
|
||||
namespace JNGame.Sync.Frame
|
||||
{
|
||||
public abstract class JNSyncDefaultService : JNSyncService
|
||||
{
|
||||
|
||||
private SBaseSystem[] _allSystems;
|
||||
protected override JNBaseSystem[] AllSystems => _allSystems;
|
||||
|
||||
public JNContexts Contexts;
|
||||
|
||||
public abstract bool IsStartGame { get; }
|
||||
|
||||
|
||||
public JNSyncDefaultService() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Contexts = CreateContexts();
|
||||
Contexts.Sync = this;
|
||||
Contexts.InitReference(this);
|
||||
var systems = new List<SBaseSystem>();
|
||||
systems.Add(CreateRandom());
|
||||
systems.AddRange(NewLogicSystems());
|
||||
systems.AddRange(NewDataSystems());
|
||||
systems.AddRange(NewViewSystems());
|
||||
_allSystems = systems.ToArray();
|
||||
|
||||
foreach (var system in _allSystems)
|
||||
{
|
||||
system.Sync = this;
|
||||
system.Contexts = Contexts;
|
||||
Add(system);
|
||||
}
|
||||
|
||||
Debug.Log("Initialize");
|
||||
|
||||
}
|
||||
|
||||
public override Systems Add(ISystem system)
|
||||
{
|
||||
(system as SLogicSystem)?.OnSyncStart();
|
||||
return base.Add(system);
|
||||
}
|
||||
|
||||
public virtual JNContexts CreateContexts()
|
||||
{
|
||||
return new JNContexts();
|
||||
}
|
||||
|
||||
//随机数系统
|
||||
public virtual JNRandomSystem CreateRandom()
|
||||
{
|
||||
return new JNRandomSystem(1000);
|
||||
}
|
||||
|
||||
public virtual SLogicSystem[] NewLogicSystems()
|
||||
{
|
||||
return Array.Empty<SLogicSystem>();
|
||||
}
|
||||
|
||||
public virtual SDataSystemBase[] NewDataSystems()
|
||||
{
|
||||
return Array.Empty<SDataSystemBase>();
|
||||
}
|
||||
|
||||
public virtual SViewSystem[] NewViewSystems()
|
||||
{
|
||||
return Array.Empty<SViewSystem>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动更新视图帧
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
|
||||
#if (!ENTITAS_DISABLE_VISUAL_DEBUGGING && UNITY_EDITOR)
|
||||
if (paused) return;
|
||||
#endif
|
||||
base.Execute();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 推逻辑帧
|
||||
/// </summary>
|
||||
public void Simulate()
|
||||
{
|
||||
|
||||
#if (!ENTITAS_DISABLE_VISUAL_DEBUGGING && UNITY_EDITOR)
|
||||
SyncDuration = 0;
|
||||
var timeSimulate = DateTime.Now.Ticks;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < _syncSystems.Count; i++)
|
||||
{
|
||||
|
||||
|
||||
#if (!ENTITAS_DISABLE_VISUAL_DEBUGGING && UNITY_EDITOR)
|
||||
if (syncSystemInfos[i].isActive){
|
||||
|
||||
var time = DateTime.Now.Ticks;
|
||||
_syncSystems[i].OnSyncUpdate();
|
||||
double time1 = (DateTime.Now.Ticks - time) / 10000f;
|
||||
syncSystemInfos[i].AddSyncUpdateDuration(time1);
|
||||
|
||||
}
|
||||
#else
|
||||
_syncSystems[i].OnSyncUpdate();
|
||||
#endif
|
||||
}
|
||||
|
||||
//给实体推帧
|
||||
Contexts.Simulate();
|
||||
|
||||
#if (!ENTITAS_DISABLE_VISUAL_DEBUGGING && UNITY_EDITOR)
|
||||
SyncDuration = (DateTime.Now.Ticks - timeSimulate) / 10000f;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/JNSyncDefaultService.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/JNSyncDefaultService.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5f5cb3f31884885bcacc09066f34bd9
|
||||
timeCreated: 1721188215
|
||||
41
JNFrame2/Assets/JNGame/Sync/JNSyncService.cs
Normal file
41
JNFrame2/Assets/JNGame/Sync/JNSyncService.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace JNGame.Sync
|
||||
{
|
||||
public abstract class JNSyncService : Feature
|
||||
{
|
||||
|
||||
//系统列表
|
||||
protected abstract JNBaseSystem[] AllSystems { get; }
|
||||
|
||||
//获取当前逻辑帧
|
||||
public abstract int DeltaTime { get; }
|
||||
|
||||
|
||||
//获取系统
|
||||
public T GetSystem<T>() where T : JNBaseSystem
|
||||
{
|
||||
foreach (var service in AllSystems)
|
||||
{
|
||||
if (service is T system) return system;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"No Service of type {typeof(T).Name} was found.");
|
||||
}
|
||||
|
||||
public List<T> GetSystems<T>()
|
||||
{
|
||||
var list = new List<T>();
|
||||
foreach (var service in AllSystems)
|
||||
{
|
||||
if (service is T system)
|
||||
{
|
||||
list.Add(system);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/JNSyncService.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/JNSyncService.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9801e1d3c01241e29bdfc7d0e30f87ae
|
||||
timeCreated: 1720690119
|
||||
3
JNFrame2/Assets/JNGame/Sync/System.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/System.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47021598e0964e72833115831984bd90
|
||||
timeCreated: 1721039163
|
||||
3
JNFrame2/Assets/JNGame/Sync/System/Data.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/System/Data.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a35faa1bd10344b8bbd360443c77d455
|
||||
timeCreated: 1721722812
|
||||
16
JNFrame2/Assets/JNGame/Sync/System/Data/SFrameDataSystem.cs
Normal file
16
JNFrame2/Assets/JNGame/Sync/System/Data/SFrameDataSystem.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace JNGame.Sync.System.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// 帧同步的数据系统 (不支持网络数据)
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class SFrameDataSystem<T> : SDataSystem<T> where T : ISData,new()
|
||||
{
|
||||
|
||||
public override void OnSyncUpdate()
|
||||
{
|
||||
Data = GetLatest();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6607845a00924069953887b35ecfa68a
|
||||
timeCreated: 1721722862
|
||||
201
JNFrame2/Assets/JNGame/Sync/System/Data/SStateDataSystem.cs
Normal file
201
JNFrame2/Assets/JNGame/Sync/System/Data/SStateDataSystem.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Collections;
|
||||
|
||||
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; }
|
||||
|
||||
public void OnInsertUBytes(Dictionary<long, byte[]> bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 状态同步的数据系统 (支持网络数据)
|
||||
/// 注意:帧同步也可以使用不过不建议 因为会有额外开销 除非你的游戏 经常在帧同步或者状态同步之间切换
|
||||
/// </summary>
|
||||
public abstract class SStateDataSystem<T> : SDataSystem<T>,ISStateDataSystem where T : ISStateData,new()
|
||||
{
|
||||
|
||||
public abstract int NetID { get; }
|
||||
|
||||
//网络通讯的更新字节数据
|
||||
protected Dictionary<long, 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 SStateDataSystem(SStateDataEnum type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
||||
|
||||
public override void OnSyncUpdate()
|
||||
{
|
||||
|
||||
//服务器: 发送最近数据
|
||||
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)
|
||||
{
|
||||
OnInsertUBytes(UBytes);
|
||||
OnSendUBytes(UBytes);
|
||||
UBytes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字节数据
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
/// <returns>是否清空UBytes</returns>
|
||||
public abstract void OnSendUBytes(Dictionary<long, byte[]> bytes);
|
||||
|
||||
/// <summary>
|
||||
/// 插入字节
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void OnInsertUBytes(Dictionary<long, byte[]> bytes)
|
||||
{
|
||||
//提交数据更新
|
||||
OnUByteUpdate(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将UByte提交更新
|
||||
/// </summary>
|
||||
public virtual void OnUByteUpdate(Dictionary<long, byte[]> bytes)
|
||||
{
|
||||
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(long 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(long id)
|
||||
{
|
||||
UBytes[id] = SDByteOperate.DELETE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f86e0dbea9824eceb7de44e113c3f29b
|
||||
timeCreated: 1721722979
|
||||
77
JNFrame2/Assets/JNGame/Sync/System/Data/STileDataSystem.cs
Normal file
77
JNFrame2/Assets/JNGame/Sync/System/Data/STileDataSystem.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Collections;
|
||||
using JNGame.Sync.Entity;
|
||||
using JNGame.Sync.Frame.Entity.Components;
|
||||
using JNGame.Sync.State.Tile;
|
||||
using JNGame.Sync.State.Tile.Entity;
|
||||
|
||||
namespace JNGame.Sync.System.Data
|
||||
{
|
||||
|
||||
public abstract class ISTileData : ISStateData
|
||||
{
|
||||
public abstract bool IsHost { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 支持区块的数据类
|
||||
/// </summary>
|
||||
public abstract class STileDataSystem<T,E> : SStateDataSystem<T> where T : ISTileData,new() where E : JNTileEntity, new()
|
||||
{
|
||||
|
||||
public abstract JNTileContext<E> NodeContext { get; }
|
||||
|
||||
protected STileDataSystem(SStateDataEnum type) : base(type)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnUByteUpdate(Dictionary<long, byte[]> bytes)
|
||||
{
|
||||
base.OnUByteUpdate(bytes);
|
||||
if (isServer)
|
||||
{
|
||||
OnDataSyncContext();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将数据Data同步到Context
|
||||
/// </summary>
|
||||
protected virtual void OnDataSyncContext()
|
||||
{
|
||||
|
||||
var lIsTileData = new Dictionary<long, T>(Data);
|
||||
|
||||
NodeContext.GetEntities().ForEach(child =>
|
||||
{
|
||||
//如果有则删除
|
||||
if (lIsTileData.Remove(child.Id,out var data))
|
||||
{
|
||||
//并且同步属性到实体中
|
||||
child.TileSyncData(data);
|
||||
}
|
||||
});
|
||||
|
||||
//将数据同步到实体中
|
||||
foreach (var keyValue in lIsTileData)
|
||||
{
|
||||
var entity = NodeContext.TileSyncCreate(keyValue.Key);
|
||||
entity.TileSyncData(keyValue.Value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//只更新有权限的实体
|
||||
public override void Update(T data)
|
||||
{
|
||||
if (!data.IsHost) return;
|
||||
base.Update(data);
|
||||
}
|
||||
public override void Add(T data)
|
||||
{
|
||||
if (!data.IsHost) return;
|
||||
base.Add(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64294f09974c48ca82724ebb3e1a3338
|
||||
timeCreated: 1722477295
|
||||
0
JNFrame2/Assets/JNGame/Sync/System/Logic.meta
Normal file
0
JNFrame2/Assets/JNGame/Sync/System/Logic.meta
Normal file
187
JNFrame2/Assets/JNGame/Sync/System/Logic/JNInputSystem.cs
Normal file
187
JNFrame2/Assets/JNGame/Sync/System/Logic/JNInputSystem.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Google.Protobuf;
|
||||
using JNGame.Util.Types;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace JNGame.Sync.System.View
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Json的输入类
|
||||
/// </summary>
|
||||
public class JNInputJson : JNInputBase
|
||||
{
|
||||
public byte[] Encoder()
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this));
|
||||
}
|
||||
|
||||
public virtual object Decoder(byte[] bytes)
|
||||
{
|
||||
return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bytes),this.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
public interface JNInputBase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public byte[] Encoder();
|
||||
|
||||
/// <summary>
|
||||
/// 解码
|
||||
/// </summary>
|
||||
public object Decoder(byte[] bytes);
|
||||
|
||||
}
|
||||
|
||||
public abstract class JNInputSystem : SLogicSystem
|
||||
{
|
||||
|
||||
protected abstract KeyValue<Type, int> TClass { get; }
|
||||
protected Dictionary<Type, JNInputBase> TNewClass = new ();
|
||||
protected readonly Dictionary<int, JNInputBase> Inputs = new ();
|
||||
protected readonly Dictionary<int, Dictionary<int,JNInputBase>> SInputs = new ();
|
||||
|
||||
protected Dictionary<int,JNFrameInput> frame = new();
|
||||
|
||||
/// <summary>
|
||||
/// 移入数据
|
||||
/// </summary>
|
||||
public void Enqueue(JNFrameInput input)
|
||||
{
|
||||
frame[input.NId] = input;
|
||||
}
|
||||
|
||||
protected JNInputSystem()
|
||||
{
|
||||
OnInit();
|
||||
OnApply();
|
||||
}
|
||||
|
||||
protected virtual void OnInit(){}
|
||||
|
||||
/// <summary>
|
||||
/// 应用
|
||||
/// </summary>
|
||||
protected virtual void OnApply()
|
||||
{
|
||||
TNewClass.Clear();
|
||||
foreach (var key in TClass.Keys)
|
||||
{
|
||||
TNewClass.Add(key,Activator.CreateInstance(key) as JNInputBase);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSyncUpdate()
|
||||
{
|
||||
base.OnSyncUpdate();
|
||||
UpdateSInputs();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取同步输入(逻辑中获取 不可修改)
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public JNInputBase SInput<T>(int clientId) where T : JNInputBase, new()
|
||||
{
|
||||
var key = TClass.Key2Value(typeof(T));
|
||||
if (SInputs.TryGetValue(key, out var inputs))
|
||||
{
|
||||
inputs.TryGetValue(clientId,out var input);
|
||||
return input;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Dictionary<int,JNInputBase> SInput<T>() where T : JNInputBase, new()
|
||||
{
|
||||
var key = TClass.Key2Value(typeof(T));
|
||||
if (SInputs.TryGetValue(key, out var inputs))
|
||||
{
|
||||
return inputs;
|
||||
}
|
||||
return new();
|
||||
}
|
||||
public JNInputBase SInputOne<T>() where T : JNInputBase, new()
|
||||
{
|
||||
var key = TClass.Key2Value(typeof(T));
|
||||
if (SInputs.TryGetValue(key, out var inputs))
|
||||
{
|
||||
if (inputs.Count > 0)
|
||||
{
|
||||
return inputs.Values.First();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取输入 (禁止在逻辑中获取 只允许在UI层调用)
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public T Input<T>() where T : JNInputBase,new()
|
||||
{
|
||||
if (!(Inputs.TryGetValue(TClass.Key2Value(typeof(T)),out var input)))
|
||||
{
|
||||
Inputs[TClass.Key2Value(typeof(T))] = input = new T();
|
||||
}
|
||||
return (T)input;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移出输入
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public JNFrameInputs Dequeue()
|
||||
{
|
||||
JNFrameInputs inputs = new JNFrameInputs();
|
||||
foreach (var key in Inputs.Keys)
|
||||
{
|
||||
var input = new JNFrameInput();
|
||||
var info = Inputs[key];
|
||||
input.NId = key;
|
||||
input.Input = ByteString.CopyFrom(info.Encoder());
|
||||
inputs.Inputs.Add(input);
|
||||
}
|
||||
Inputs.Clear();
|
||||
return inputs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移入输入
|
||||
/// </summary>
|
||||
public void UpdateSInputs()
|
||||
{
|
||||
|
||||
SInputs.Clear();
|
||||
//解析输入
|
||||
foreach (var kInput in frame)
|
||||
{
|
||||
var input = kInput.Value;
|
||||
var tClass = TClass.Value2Key(input.NId);
|
||||
|
||||
if (!(SInputs.TryGetValue(input.NId,out var inputs)))
|
||||
{
|
||||
SInputs.Add(input.NId, inputs = new Dictionary<int, JNInputBase>());
|
||||
}
|
||||
|
||||
inputs.Add(input.ClientId,TNewClass[tClass].Decoder(input.Input.ToByteArray()) as JNInputBase);
|
||||
|
||||
}
|
||||
frame.Clear();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6c14ce606094eecbc415faab78bb5ad
|
||||
timeCreated: 1721635056
|
||||
56
JNFrame2/Assets/JNGame/Sync/System/Logic/JNRandomSystem.cs
Normal file
56
JNFrame2/Assets/JNGame/Sync/System/Logic/JNRandomSystem.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using JNGame.Math;
|
||||
using JNGame.Sync.System;
|
||||
using Plugins.JNGame.Util;
|
||||
|
||||
namespace JNGame.Sync.Frame.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 随机数
|
||||
/// </summary>
|
||||
public class JNRandomSystem : SLogicSystem
|
||||
{
|
||||
|
||||
//随机数
|
||||
private Func<LFloat,LFloat,LFloat> nRandomFloat;
|
||||
private Func<int,int,int> nRandomInt;
|
||||
|
||||
//Id
|
||||
private long _id = 0;
|
||||
|
||||
public JNRandomSystem(int seed)
|
||||
{
|
||||
nRandomFloat = RandomUtil.SyncRandomFloat(seed);
|
||||
nRandomInt = RandomUtil.SyncRandomInt(seed);
|
||||
}
|
||||
|
||||
public LFloat Float()
|
||||
{
|
||||
return Float(0,1);
|
||||
}
|
||||
|
||||
public LFloat Float(LFloat min,LFloat max)
|
||||
{
|
||||
return nRandomFloat(min,max);
|
||||
}
|
||||
|
||||
public int Int(int max,int min)
|
||||
{
|
||||
return nRandomInt(max,min);
|
||||
}
|
||||
|
||||
public long NextId()
|
||||
{
|
||||
return ++_id;
|
||||
}
|
||||
|
||||
public void SetIdValue(long id)
|
||||
{
|
||||
if (_id < id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30a8e21f1e344fb59f39047129fce186
|
||||
timeCreated: 1721187856
|
||||
16
JNFrame2/Assets/JNGame/Sync/System/SBaseSystem.cs
Normal file
16
JNFrame2/Assets/JNGame/Sync/System/SBaseSystem.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Entitas;
|
||||
using JNGame.Sync.Entity;
|
||||
using NotImplementedException = System.NotImplementedException;
|
||||
|
||||
namespace JNGame.Sync.System
|
||||
{
|
||||
/// <summary>
|
||||
/// 同步 - 基础系统
|
||||
/// </summary>
|
||||
public class SBaseSystem : JNBaseSystem
|
||||
{
|
||||
|
||||
public JNContexts Contexts;
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/System/SBaseSystem.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/System/SBaseSystem.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12633ea43bb44b6ba2e88bafd0a6bb6e
|
||||
timeCreated: 1721009209
|
||||
89
JNFrame2/Assets/JNGame/Sync/System/SDataSystem.cs
Normal file
89
JNFrame2/Assets/JNGame/Sync/System/SDataSystem.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DotRecast.Core.Collections;
|
||||
using JNGame.Sync.Frame.Service;
|
||||
using NotImplementedException = System.NotImplementedException;
|
||||
|
||||
namespace JNGame.Sync.System
|
||||
{
|
||||
|
||||
public class SDByteOperate
|
||||
{
|
||||
public static readonly byte[] DELETE = { 0 }; //删除
|
||||
|
||||
public static bool IsDelete(byte[] value)
|
||||
{
|
||||
return value.Length == 1 && value[0] == DELETE[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据接口
|
||||
/// </summary>
|
||||
public abstract class ISData : IJNSyncId
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 数据唯一Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否一样
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool IsEquals(ISData data);
|
||||
|
||||
}
|
||||
|
||||
public abstract class SDataSystemBase : SBaseSystem,IJNSyncCycle
|
||||
{
|
||||
public abstract void OnSyncStart();
|
||||
|
||||
public abstract void OnSyncUpdate();
|
||||
|
||||
public virtual void OnSyncDestroy()
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 状态系统 - 数据层
|
||||
/// </summary>
|
||||
public abstract class SDataSystem<T> : SDataSystemBase where T : ISData,new()
|
||||
{
|
||||
|
||||
//数据Id
|
||||
public long Id { get; private set; }
|
||||
|
||||
public JNRandomSystem Random => GetSystem<JNRandomSystem>();
|
||||
|
||||
//数据集
|
||||
public Dictionary<long, T> Data = new();
|
||||
|
||||
public virtual T[] Datas {
|
||||
get
|
||||
{
|
||||
lock (Data)
|
||||
{
|
||||
return Data.Values.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSyncStart()
|
||||
{
|
||||
//设置数据唯一Id
|
||||
Id = Random.NextId();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回最新数据 (收集最新的ISData数据 正常来讲只有服务端会运行)
|
||||
/// </summary>
|
||||
public virtual Dictionary<long, T> GetLatest()
|
||||
{
|
||||
return new ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/System/SDataSystem.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/System/SDataSystem.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cc5c86befd84d0a98fbfe2c3ccf1073
|
||||
timeCreated: 1721039079
|
||||
33
JNFrame2/Assets/JNGame/Sync/System/SLogicSystem.cs
Normal file
33
JNFrame2/Assets/JNGame/Sync/System/SLogicSystem.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using JNGame.Sync.Frame.Service;
|
||||
using NotImplementedException = System.NotImplementedException;
|
||||
|
||||
namespace JNGame.Sync.System
|
||||
{
|
||||
/// <summary>
|
||||
/// 帧同步 - 逻辑系统
|
||||
/// </summary>
|
||||
public class SLogicSystem : SBaseSystem,IJNSyncCycle,IJNSyncId
|
||||
{
|
||||
|
||||
private long _id;
|
||||
public long Id => _id;
|
||||
|
||||
public virtual void OnSyncStart()
|
||||
{
|
||||
|
||||
JNRandomSystem random;
|
||||
if (this is JNRandomSystem) random = (JNRandomSystem)this;
|
||||
else random = GetSystem<JNRandomSystem>();
|
||||
|
||||
_id = random.NextId();
|
||||
|
||||
}
|
||||
|
||||
public virtual void OnSyncUpdate()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnSyncDestroy(){}
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/System/SLogicSystem.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/System/SLogicSystem.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 479b71cc642641aeb965e980ee3580e5
|
||||
timeCreated: 1721187888
|
||||
22
JNFrame2/Assets/JNGame/Sync/System/SViewSystem.cs
Normal file
22
JNFrame2/Assets/JNGame/Sync/System/SViewSystem.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Entitas;
|
||||
using NotImplementedException = System.NotImplementedException;
|
||||
|
||||
namespace JNGame.Sync.System
|
||||
{
|
||||
/// <summary>
|
||||
/// 帧同步 - 视图系统
|
||||
/// </summary>
|
||||
public class SViewSystem : SBaseSystem,IJNSyncCycle,IExecuteSystem
|
||||
{
|
||||
public virtual void Execute(){}
|
||||
public virtual void OnSyncStart()
|
||||
{
|
||||
}
|
||||
public virtual void OnSyncUpdate()
|
||||
{
|
||||
}
|
||||
public virtual void OnSyncDestroy()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/System/SViewSystem.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/System/SViewSystem.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c655f765f124661b81d5be2c7555206
|
||||
timeCreated: 1721008791
|
||||
3
JNFrame2/Assets/JNGame/Sync/System/View.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/System/View.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae13387f055c48969fe5a2229582c832
|
||||
timeCreated: 1721635230
|
||||
0
JNFrame2/Assets/JNGame/Sync/View.meta
Normal file
0
JNFrame2/Assets/JNGame/Sync/View.meta
Normal file
9
JNFrame2/Assets/JNGame/Sync/View/IViewData.cs
Normal file
9
JNFrame2/Assets/JNGame/Sync/View/IViewData.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace JNGame.Sync.View
|
||||
{
|
||||
public interface IViewData
|
||||
{
|
||||
|
||||
public void Execute();
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/View/IViewData.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/View/IViewData.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 480622cdae584eda8bf3d2eb1d37176c
|
||||
timeCreated: 1721188091
|
||||
84
JNFrame2/Assets/JNGame/Sync/View/ViewData.cs
Normal file
84
JNFrame2/Assets/JNGame/Sync/View/ViewData.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Sync.Entity;
|
||||
using JNGame.Sync.Frame.Entity;
|
||||
using JNGame.Sync.System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace JNGame.Sync.View
|
||||
{
|
||||
public class ViewGameObject
|
||||
{
|
||||
//更新
|
||||
public int Update;
|
||||
public GameObject Data;
|
||||
}
|
||||
|
||||
public abstract class ViewData<T> : IViewData where T : ISData
|
||||
{
|
||||
|
||||
private Dictionary<long, ViewGameObject> views = new();
|
||||
private SViewSystem root;
|
||||
public SViewSystem Root => root;
|
||||
|
||||
private int Update = 0;
|
||||
|
||||
public ViewData(SViewSystem root)
|
||||
{
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public virtual void Execute()
|
||||
{
|
||||
Update++;
|
||||
|
||||
var dataList = GetData();
|
||||
|
||||
bool isRest = dataList.Length != views.Count;
|
||||
|
||||
foreach (var data in dataList){
|
||||
|
||||
ViewGameObject view;
|
||||
if (!views.TryGetValue(data.Id,out view))
|
||||
{
|
||||
isRest = true;
|
||||
view = new(){Data = NewView(data)};
|
||||
views.Add(data.Id, view);
|
||||
}
|
||||
|
||||
view.Update = Update;
|
||||
ViewUpdate(data,view.Data);
|
||||
|
||||
}
|
||||
|
||||
if (isRest)
|
||||
{
|
||||
List<long> deletes = new List<long>();
|
||||
foreach (var child in views)
|
||||
{
|
||||
if (child.Value.Update != Update)
|
||||
{
|
||||
deletes.Add(child.Key);
|
||||
}
|
||||
}
|
||||
foreach (var delete in deletes)
|
||||
{
|
||||
ViewRemove(views[delete].Data);
|
||||
views.Remove(delete);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public abstract void ViewUpdate(T data,GameObject view);
|
||||
public abstract GameObject NewView(T data);
|
||||
public abstract T[] GetData();
|
||||
|
||||
public abstract void ViewRemove(GameObject view);
|
||||
|
||||
public T GetService<T>() where T : SBaseSystem
|
||||
{
|
||||
return root.GetSystem<T>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
3
JNFrame2/Assets/JNGame/Sync/View/ViewData.cs.meta
Normal file
3
JNFrame2/Assets/JNGame/Sync/View/ViewData.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e18d400c170f47439cdbb511f330b7a4
|
||||
timeCreated: 1721188075
|
||||
Reference in New Issue
Block a user