using System; using System.Collections.Generic; using System.Threading.Tasks; 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; //帧队列 private List _nFrameQueue = new(); //本地帧数 private int _nLocalFrame = 0; //运行的帧 private int _nFrameRun = 0; //暂存帧列表 private Dictionary _nFrameTempQueue = new(); //ID 每添加 JNSyncFrameComponent + 1 public Func nSyncID = RandomUtil.Next(0); //随机数 public Func nRandom = RandomUtil.SyncRandom(100); //随机数整数 public Func nRandomInt = RandomUtil.SyncRandomInt(100); //是否开始同步 Boolean _isStart = false; //帧更新 int dtTotal = 0; //输入更新 int dtInputTotal = 0; public override Task OnInit() { Physics.autoSimulation = false; Physics.autoSyncTransforms = false; return Task.CompletedTask; } //重置数据 public void Reset() { 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() { } //自适应间隔时间 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 是否最新的帧数据 */ public void AddInput(JNFrameInfo frame,Boolean isLatestData = false){ if(isLatestData){ //如果推的帧小于本地帧 则 重开 if(frame.Index < _nLocalFrame){ Reset(); return; } } //我需要的下一帧 int index = _nLocalFrame + 1; //判断接受的帧是否下一帧 如果不是则加入未列入 if (frame.Index != index){ _nFrameTempQueue.Add(frame.Index,frame); //在未列入中拿到需要的帧 JNFrameInfo tamp = null; if ((tamp = _nFrameTempQueue[index]) == null){ //如果没有则向服务器请求我需要的帧数 } else { //如果有则覆盖 frame = tamp; } } //删除临时帧 _nFrameTempQueue.Remove(frame.Index); _nLocalFrame = index; //分帧插入 _nFrameQueue.Add(frame); for (var i = 0; i < this._nDivideFrame - 1; index++) { _nFrameQueue.Add(new JNFrameInfo()); } } //发送帧数据 protected abstract void OnSendInput(JNFrameInputs inputs); } }