private void OnMercuryEvent(object sender, MercuryEventBase e) { if (e.eventId == (int)EMercuryEvent.E_ME_OBJ_DELIVER) { MEObjDeliver evt = (MEObjDeliver)e; if (evt.opcode == (int)EObjDeliverOPCode.E_OP_HANDLE_FRAMEPACK) { object[] args = (object[])evt.obj; if (!HandleFrameCommandPackage((uint)args[0], args[1])) { uint frameID = (uint)args[0]; if (frameID >= _begFrqNo) { FrapWrap wrap = ObjectCachePool.instance.Fetch <FrapWrap>(); wrap.frameID = frameID; wrap.data = args[1]; //Èç¹û¸ÃÖ¡ÒÑ´æÔÚ£¬Ôò¶ªÆú if (!Utility.LinkedListInsert(_laterFrames, wrap, FrapWrap.FrapWrapInsertComparsionFunc)) { ProcessFrameDropInternal(frameID, wrap.data, false); wrap.Release(); } } } } } }
// private void PushFrame2LaterFrameList(MercuryEventBase e) { if (e != null) { MEObjDeliver evt = (MEObjDeliver)e; FrapWrap frap = ObjectCachePool.instance.Fetch <FrapWrap>(); frap.frameID = (uint)evt.args[0]; frap.data = evt.args[1]; e.Release(); if (Utility.LinkedListInsert(_laterFrames, frap, FrapWrap.FrapWrapInsertComparsionFunc)) { if (_lastFrameNeedToTrace < frap.frameID) { _lastFrameNeedToTrace = (int)frap.frameID; // record last frame while tracing the newest frame. } } else { // release duplicated data AbstractSmartObj obj = (AbstractSmartObj)frap.data; if (obj != null) { obj.Release(); } frap.Release(); } } }
private void RequestRepairLackFrames() { if (_maxFrqNo <= _begFrqNo) { return; } //voilin: request small repair List <int> frames = new List <int>(); //»á¶àÇëÇóÁ½Ö¡ int len = Mathf.Min((int)(_maxFrqNo - _begFrqNo + 2u), (int)MAX_REPAIR_FRAMECOUNT); for (uint ii = _begFrqNo; ii < _begFrqNo + len; ++ii) { //ÔÙ×öÒ»´Î¼ì²â£¬·ÀÖ¹ÓÉÓÚÖ¡ÂÒÐòµ½´ï¶øÖظ´ÇëÇó int pos = (int)_FrameNo2WindowIdx(ii); if (_receiveWindow[pos] == null) { frames.Add((int)ii); } } if (frames.Count > 0) { MEObjDeliver e = ObjectCachePool.instance.Fetch <MEObjDeliver>(); int[] tmp = frames.ToArray(); e.args[0] = (object)tmp; e.opcode = (int)EObjDeliverOPCode.E_OP_LACK_FRAMES; Mercury.instance.Broadcast(EventTokenTable.et_game_framework, this, e); } }
private void ProcessFrameCommandInternal(object msg) { MEObjDeliver e = ObjectCachePool.instance.Fetch <MEObjDeliver>(); e.args[0] = msg; e.opcode = (int)EObjDeliverOPCode.E_OP_PROCESS_FRAMEPACK; Mercury.instance.Broadcast(EventTokenTable.et_game_framework, this, e); }
private void ProcessFrameDropInternal(uint frameID, object msg, bool releaseSharedBuf = true) { MEObjDeliver e = ObjectCachePool.instance.Fetch <MEObjDeliver>(); e.args[0] = frameID; e.args[1] = msg; e.args[2] = releaseSharedBuf; e.opcode = (int)EObjDeliverOPCode.E_OP_PROCESS_FRAMEDROP; Mercury.instance.Broadcast(EventTokenTable.et_game_framework, this, e); }
private void ReportProgress(int progress = -1) { // reconnection progress int percent = progress < 0 ? UnityEngine.Mathf.Clamp((int)(FrameSyncService.instance.GetFrameSyncChr().CurFrameNum * 1f / _lastFrameNeedToTrace * 100), 0, 99) : progress; if (percent > _lastReportPercent) { _lastReportPercent = percent; MEObjDeliver report = ObjectCachePool.instance.Fetch <MEObjDeliver>(); report.opcode = (int)EObjDeliverOPCode.E_OP_RECONNECTION_PROGRESS; report.args[0] = percent;//progress < 0 ? UnityEngine.Mathf.Clamp(percent, 0, 99) : progress; Mercury.instance.Broadcast(EventTokenTable.et_loading_ui, this, report); } }
private void ProcessLaterFrames() { if (_laterFrames.Count > 0) { LinkedListNode <FrapWrap> node = _laterFrames.First; while (node != null && node.Value != null) { FrapWrap frap = node.Value; MEObjDeliver e = ObjectCachePool.instance.Fetch <MEObjDeliver>(); e.args[0] = frap.frameID; e.args[1] = frap.data; e.opcode = (int)EObjDeliverOPCode.E_OP_HANDLE_FRAMEPACK; Mercury.instance.Broadcast(EventTokenTable.et_framewindow, this, e); ReportProgress(); frap.Release(); node = node.Next; } _laterFrames.Clear(); } }
// extension RequireReconnection to implement message pack and send logic // NOTE: do not use this internal function indepentently. public bool _RequireReconnection(int TotalFramesPassed) { if (_state == EState.E_STATE_NONE && TotalFramesPassed > 0) { _state = EState.E_STATE_RECEIVING_FRAMES; _lastFrameNeedToTrace = TotalFramesPassed; _currentFrameTraced = 0; _lastReportPercent = 0; _tracedFrame = 0; _canPerformCheck = false; _adjustGap = true; MEObjDeliver e = ObjectCachePool.instance.Fetch <MEObjDeliver> (); e.opcode = (int)EObjDeliverOPCode.E_OP_START_RECONNECTION; Mercury.instance.Broadcast(EventTokenTable.et_game_framework, this, e); return(true); } else if (_state == EState.E_STATE_NONE && TotalFramesPassed == 0) { ReportProgress(100); } return(false); }
public void Update() { if (_state == EState.E_STATE_EXECUTING_FRAMES) { ProcessLaterFrames(); if (FrameSyncService.instance.BlockFrameWaitNum > kFrameBlockThreshold && FrameSyncService.instance.GetFrameSyncChr().CurFrameNum < _lastFrameNeedToTrace) { _currentFrameTraced = (int)FrameSyncService.instance.GetFrameSyncChr().CurFrameNum + 1; _state = EState.E_STATE_RECEIVING_FRAMES; _canPerformCheck = false; return; } // tolerent by maxium repair count bool fin = FrameSyncService.instance.GetFrameSyncChr().CurFrameNum >= _lastFrameNeedToTrace; if (fin) { ReportProgress(100); MEObjDeliver e = ObjectCachePool.instance.Fetch <MEObjDeliver>(); e.opcode = (int)EObjDeliverOPCode.E_OP_END_RECONNECTION; Mercury.instance.Broadcast(EventTokenTable.et_game_framework, this, e); _canPerformCheck = true; _state = EState.E_STATE_NONE; } } else if (_state == EState.E_STATE_RECEIVING_FRAMES) { if (_adjustGap) { if (_laterFrames.Count > 0) { // adjust gap, the gap is generated by loading stuck int gap = (int)_laterFrames.First.Value.frameID - _lastFrameNeedToTrace - 1; if (gap > 0) { _lastFrameNeedToTrace = (int)_laterFrames.First.Value.frameID - 1; } _adjustGap = false; } } int frameEnd = UnityEngine.Mathf.Min(_currentFrameTraced + kFramesDevourPerTick, _lastFrameNeedToTrace); if (frameEnd > _currentFrameTraced) { MEObjDeliver e = ObjectCachePool.instance.Fetch <MEObjDeliver>(); e.opcode = (int)EObjDeliverOPCode.E_OP_FETCH_RECONNECTION_FRAMES; e.args[0] = _currentFrameTraced; e.args[1] = frameEnd; Mercury.instance.Broadcast(EventTokenTable.et_game_framework, this, e); _lastTracedFrame = _currentFrameTraced; _tracedFrame = frameEnd; _stuckTimes = 0; _state = EState.E_STATE_WAIT_HANDLING_FRAMES; } else { // force processing later frames ProcessLaterFrames(); _state = EState.E_STATE_EXECUTING_FRAMES; } } else if (_state == EState.E_STATE_WAIT_HANDLING_FRAMES) { if (_currentFrameTraced == _lastTracedFrame) { ++_stuckTimes; } else { _lastTracedFrame = _currentFrameTraced; _stuckTimes = 0; } // request again while stucking if (_stuckTimes >= kFrameReqStuckTimesThreshold) { _state = EState.E_STATE_RECEIVING_FRAMES; return; } if (_currentFrameTraced < _tracedFrame) { return; } if (_tracedFrame < _lastFrameNeedToTrace) { _state = EState.E_STATE_RECEIVING_FRAMES; } //追上之后,处理后来帧 else { ProcessLaterFrames(); _canPerformCheck = true; _state = EState.E_STATE_EXECUTING_FRAMES; } } }
/// <summary> /// 该方法每个渲染帧会执行一次,但是会以逻辑帧间隔,经过平均延迟计算,触发逻辑帧的执行 /// </summary> /// <param name="bLocalTimeDriver"></param> private void UpdateMultiFrame(bool bLocalTimeDriver = false) { { MEObjDeliver e = ObjectCachePool.instance.Fetch <MEObjDeliver>(); e.opcode = (int)EObjDeliverOPCode.E_OP_UPDATE_TAILS_OF_GAME_LOGIC; Mercury.instance.Broadcast(EventTokenTable.et_framesynchr, this, e); } int drift = (int)((EndFrameNum - CurFrameNum) / (uint)nDriftFactor); tryCount = Mathf.Clamp(drift, 1, 100); int i = tryCount; float rt = Time.realtimeSinceStartup; if (bLocalTimeDriver) { rt = fLocalRunTime + startFrameTime; } //帧同步开始后经过了多少时间。nowtime 是渲染帧间隔,小于一个逻辑帧 long nowTime = (long)((rt - startFrameTime) * 1000f); long nDelayMs = nowTime - (long)((SvrFrameIndex + 1u) * SvrFrameDelta); //平均延迟(以30帧计算) int smoothDelay = CalculateJitterDelay(nDelayMs); nowTime *= (long)frameSpeed; while (i > 0) { long lastTime = (long)(CurFrameNum * FrameDelta); long deltaTime = nowTime - lastTime; deltaTime -= (long)smoothDelay; //这里是处理核心,如果 deltaTime 随着渲染帧的增长而增长,当他小于一个逻辑帧时,则不做任何处理,当他大于一个逻辑帧时,则触发一次逻辑帧处理 if (deltaTime >= (long)FrameDelta) { //假设一直没有收到新的逻辑帧,则每次都会执行到这里 if (CurFrameNum >= EndFrameNum) { EndBlockWaitNum += 1u; i = 0; } else { EndBlockWaitNum = 0u; CurFrameNum += 1u; LogicFrameTick += (ulong)FrameDelta; //先执行命令,再刷新游戏逻辑 while (commandQueue.Count > 0) { IFrameCommand frameCommand = commandQueue.Peek(); uint commandFrame = (frameCommand.frameNum + SvrFrameLater) * KeyFrameRate; if (commandFrame > CurFrameNum) { break; } frameCommand = commandQueue.Dequeue(); frameCommand.frameNum = commandFrame; frameCommand.ExecCommand(); AbstractSmartObj obj = (AbstractSmartObj)frameCommand; if (obj != null) { obj.Release(); } } if (!bEscape) { //通知刷新游戏逻辑层 MEObjDeliver e = ObjectCachePool.instance.Fetch <MEObjDeliver>(); e.args[0] = (int)FrameDelta; e.args[1] = i == 1 && deltaTime < (long)(2u * FrameDelta); //false; e.opcode = (int)EObjDeliverOPCode.E_OP_UPDATE_GAME_LOGIC; Mercury.instance.Broadcast(EventTokenTable.et_framesynchr, this, e); } i--; } } else { i = 0; } } }