2024-01-26 19:15:07 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Threading.Tasks;
|
2024-01-29 02:28:42 +08:00
|
|
|
|
using Cysharp.Threading.Tasks;
|
|
|
|
|
using Plugins.JNGame.Sync.Frame.game;
|
2024-01-26 19:15:07 +08:00
|
|
|
|
using Plugins.JNGame.System;
|
|
|
|
|
using Plugins.JNGame.Util;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
|
|
|
|
|
namespace Plugins.JNGame.Sync.Frame
|
|
|
|
|
{
|
|
|
|
|
public abstract class JNSyncFrame : SystemBase
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//同步时间 (和服务器保持一致)
|
|
|
|
|
private int _nSyncTime = 67;
|
|
|
|
|
//大于多少帧进行追帧
|
|
|
|
|
private int _nMaxFrameBan = 3;
|
|
|
|
|
//大于多少帧进行快速追帧
|
|
|
|
|
private int _nMaxFrameLoopBan = 18;
|
|
|
|
|
//将服务器帧数进行平分
|
|
|
|
|
private int _nDivideFrame = 3;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//帧队列
|
2024-01-29 02:28:42 +08:00
|
|
|
|
private Queue<JNFrameInfo> _nFrameQueue = new();
|
2024-01-26 19:15:07 +08:00
|
|
|
|
|
|
|
|
|
//本地帧数
|
|
|
|
|
private int _nLocalFrame = 0;
|
|
|
|
|
//运行的帧
|
|
|
|
|
private int _nFrameRun = 0;
|
|
|
|
|
|
|
|
|
|
//暂存帧列表
|
|
|
|
|
private Dictionary<int,JNFrameInfo> _nFrameTempQueue = new();
|
|
|
|
|
|
2024-01-29 02:28:42 +08:00
|
|
|
|
//需要同步的Actor
|
|
|
|
|
private List<JNSyncFrameComponent<object>> _nSyncActors = new();
|
|
|
|
|
|
2024-01-26 19:15:07 +08:00
|
|
|
|
//ID 每添加 JNSyncFrameComponent + 1
|
|
|
|
|
public Func<int> nSyncID = RandomUtil.Next(0);
|
|
|
|
|
|
|
|
|
|
//随机数
|
|
|
|
|
public Func<double> nRandom = RandomUtil.SyncRandom(100);
|
|
|
|
|
|
|
|
|
|
//随机数整数
|
|
|
|
|
public Func<int, int, int> nRandomInt = RandomUtil.SyncRandomInt(100);
|
|
|
|
|
|
|
|
|
|
//是否开始同步
|
|
|
|
|
Boolean _isStart = false;
|
|
|
|
|
|
2024-01-29 02:28:42 +08:00
|
|
|
|
//是否请求后台数据
|
|
|
|
|
private Boolean _isRequestServerData = false;
|
|
|
|
|
|
2024-01-26 19:15:07 +08:00
|
|
|
|
//帧更新
|
|
|
|
|
int dtTotal = 0;
|
|
|
|
|
//输入更新
|
|
|
|
|
int dtInputTotal = 0;
|
|
|
|
|
|
|
|
|
|
public override Task OnInit()
|
|
|
|
|
{
|
|
|
|
|
Physics.autoSimulation = false;
|
|
|
|
|
Physics.autoSyncTransforms = false;
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-29 02:28:42 +08:00
|
|
|
|
//开始
|
|
|
|
|
public void onStart(){
|
|
|
|
|
this._isStart = true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-26 19:15:07 +08:00
|
|
|
|
//重置数据
|
2024-01-29 02:28:42 +08:00
|
|
|
|
public void onStop()
|
2024-01-26 19:15:07 +08:00
|
|
|
|
{
|
2024-01-29 02:28:42 +08:00
|
|
|
|
this._isStart = false;
|
2024-01-26 19:15:07 +08:00
|
|
|
|
this.nSyncID = RandomUtil.Next(0);
|
|
|
|
|
this.nRandom = RandomUtil.SyncRandom(100);
|
|
|
|
|
this.nRandomInt = RandomUtil.SyncRandomInt(100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//更新同步
|
|
|
|
|
public void Update(int dt)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if(!_isStart) return;
|
|
|
|
|
|
|
|
|
|
dtTotal += dt;
|
|
|
|
|
dtInputTotal += dt;
|
|
|
|
|
|
|
|
|
|
int nSyncTime = this.DyTime();
|
|
|
|
|
|
|
|
|
|
if(nSyncTime > 0){
|
|
|
|
|
while(nSyncTime != 0 && this.dtTotal > nSyncTime){
|
|
|
|
|
this.onUpdate();
|
|
|
|
|
this.dtTotal -= nSyncTime;
|
|
|
|
|
nSyncTime = this.DyTime();
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
//追帧运行 保持前端 15 帧 刷新
|
|
|
|
|
int endTime = DateTime.Now.Millisecond + 66;
|
|
|
|
|
while(this.DyTime() == 0 && DateTime.Now.Millisecond < endTime){
|
|
|
|
|
this.onUpdate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//运行帧
|
|
|
|
|
public void onUpdate()
|
|
|
|
|
{
|
2024-01-29 02:28:42 +08:00
|
|
|
|
if(!(_nFrameQueue.TryDequeue(out var frame))) return;
|
|
|
|
|
|
|
|
|
|
int dt = this._nSyncTime / this._nDivideFrame;
|
2024-01-26 19:15:07 +08:00
|
|
|
|
|
2024-01-29 02:28:42 +08:00
|
|
|
|
//拆出输入
|
|
|
|
|
Dictionary<int, JNFrameInput> inputs = new();
|
|
|
|
|
foreach (var message in frame.Messages)
|
|
|
|
|
{
|
|
|
|
|
inputs.Add(message.NId,message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//更新帧
|
|
|
|
|
this._nSyncActors.ForEach(child =>
|
|
|
|
|
{
|
|
|
|
|
if (inputs.ContainsKey(child.NID))
|
|
|
|
|
{
|
|
|
|
|
child.OnSyncUpdate(dt,frame,child.Decoder(inputs[child.NID].Input.ToByteArray()));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
child.OnSyncUpdate(dt,frame,null);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//执行下一帧物理
|
|
|
|
|
Physics.Simulate((float)dt / 1000);
|
|
|
|
|
Physics.SyncTransforms();
|
|
|
|
|
|
|
|
|
|
|
2024-01-26 19:15:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//自适应间隔时间
|
|
|
|
|
private int DyTime(){
|
|
|
|
|
int dt = this._nSyncTime / this._nDivideFrame;
|
|
|
|
|
int loop = 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 接收帧数据
|
|
|
|
|
* @param frame 帧数据
|
|
|
|
|
* @param isLatestData 是否最新的帧数据
|
|
|
|
|
*/
|
2024-01-29 02:28:42 +08:00
|
|
|
|
public void AddInput(JNFrameInfo frame,Boolean isLatestData = true)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (!_isStart) return;
|
2024-01-26 19:15:07 +08:00
|
|
|
|
|
|
|
|
|
if(isLatestData){
|
|
|
|
|
//如果推的帧小于本地帧 则 重开
|
|
|
|
|
if(frame.Index < _nLocalFrame){
|
2024-01-29 02:28:42 +08:00
|
|
|
|
onStop();
|
|
|
|
|
onStart();
|
2024-01-26 19:15:07 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//我需要的下一帧
|
|
|
|
|
int index = _nLocalFrame + 1;
|
|
|
|
|
|
|
|
|
|
//判断接受的帧是否下一帧 如果不是则加入未列入
|
|
|
|
|
if (frame.Index != index){
|
|
|
|
|
|
2024-01-29 02:28:42 +08:00
|
|
|
|
_nFrameTempQueue.TryAdd(frame.Index,frame);
|
2024-01-26 19:15:07 +08:00
|
|
|
|
|
|
|
|
|
//在未列入中拿到需要的帧
|
|
|
|
|
JNFrameInfo tamp = null;
|
|
|
|
|
|
2024-01-29 02:28:42 +08:00
|
|
|
|
if ((tamp = _nFrameTempQueue.GetValueOrDefault(index,null)) == null){
|
2024-01-26 19:15:07 +08:00
|
|
|
|
|
|
|
|
|
//如果没有则向服务器请求我需要的帧数
|
2024-01-29 02:28:42 +08:00
|
|
|
|
if (!this._isRequestServerData)
|
|
|
|
|
{
|
|
|
|
|
this._isRequestServerData = true;
|
|
|
|
|
|
|
|
|
|
//请求
|
|
|
|
|
this.OnServerData(this._nLocalFrame, 0).ContinueWith(infos =>
|
|
|
|
|
{
|
|
|
|
|
foreach (var frameInfo in infos.Frames)
|
|
|
|
|
{
|
|
|
|
|
this.AddInput(frameInfo,false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._isRequestServerData = false;
|
|
|
|
|
}).Forget();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
2024-01-26 19:15:07 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//如果有则覆盖
|
|
|
|
|
frame = tamp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//删除临时帧
|
|
|
|
|
_nFrameTempQueue.Remove(frame.Index);
|
|
|
|
|
|
|
|
|
|
_nLocalFrame = index;
|
|
|
|
|
|
|
|
|
|
//分帧插入
|
2024-01-29 02:28:42 +08:00
|
|
|
|
_nFrameQueue.Enqueue(frame);
|
|
|
|
|
for (var i = 0; i < this._nDivideFrame - 1; i++) {
|
|
|
|
|
_nFrameQueue.Enqueue(new JNFrameInfo());
|
2024-01-26 19:15:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//发送帧数据
|
|
|
|
|
protected abstract void OnSendInput(JNFrameInputs inputs);
|
2024-01-29 02:28:42 +08:00
|
|
|
|
//获取帧数据
|
|
|
|
|
protected abstract UniTask<JNFrameInfos> OnServerData(int start,int end);
|
2024-01-26 19:15:07 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|