/// <summary> /// This is a hot path. Runs at the completion interpolation, and attempts to find/reconstruct the next suitable frame for interpolation. /// </summary> public Frame DetermineAndPrepareNextFrame(bool svrWaitingForTeleportConfirm) { // buffer is empty, no point looking for any frames - we need to extrapolate the next frame if (validFrameMask == 0) { ExtrapolateNextFrame(svrWaitingForTeleportConfirm); XDebug.Log(!XDebug.logInfo ? null : //Debug.Log( (Time.time + " NST:" + nst.NstId + " <b> Empty buffer</b>, (likely packetloss) copying current frame to " + NextFrame.frameid + " " + nst.name + "\nCurrentFrame: " + currentFrame.frameid + " scn:" + currentFrame.sceneIndex + " " + currentFrame.compPos + " " + currentFrame.rootPos + "\nNextFrame: " + NextFrame.frameid + " scn:" + NextFrame.sceneIndex + " " + NextFrame.compPos + " " + NextFrame.rootPos)); return(NextFrame); } extrapolationCount = 0; // First see if there is a future frame ready - ignoring late arrivles that may have backfilled behind the current frame Frame nextValid = GetFirstFutureValidFrame(); // if not see if there is an older frame that arrived late, if so we will jump back to that as current if (nextValid == null) { nextValid = GetOldestPastValidFrame() ?? GetOldestValidFrame(); // The only valid frames are only in the past, we need to jump back to the oldest to get our current frame in a better ballpark if (nextValid != null) { nextValid.CompletePosition(currentFrame); //Debug.Log( XDebug.Log(!XDebug.logInfo ? null : (Time.time + " NST:" + nst.NstId + " <b> Skipping back </b>(likely packetloss) to frame " + nextValid.frameid + " from current frame " + CurrentIndex + " " + nst.name + "\nOnly frames in buffer were in the past, so seems that we are getting ahead of the buffer. Should see these rarely." + "\nCurrentFrame: " + currentFrame.frameid + " scn:" + currentFrame.sceneIndex + " " + currentFrame.compPos + " " + currentFrame.rootPos + "\nNextValid: " + nextValid.frameid + " scn:" + nextValid.sceneIndex + " " + nextValid.compPos + " " + nextValid.rootPos)); return(nextValid); } } // Find out how far in the future the next valid frame is, need to know this for the reconstruction lerp. int stepsFromLast = CountFrames(CurrentIndex, nextValid.frameid); // The next frame is the next valid... not much thinking required... just use it. if (stepsFromLast == 1) { InvalidateOldFrames(NextFrame); // LIKELY UNEEDED NextFrame.CompletePosition(currentFrame); //Debug.Log( //XDebug.Log(!XDebug.logInfo ? null : // (Time.time + " NST:" + nst.NstId + " <b>Normal Next</b> from " + CurrentIndex + " to " + NextFrame.frameid + " (likely packetloss) from expected frame. " + nst.name + // "\nCurrentFrame: " + currentFrame.frameid + " scn:" + currentFrame.sceneIndex + " " + currentFrame.compPos + " " + currentFrame.rootPos + // "\nNextFrame: " + NextFrame.frameid + " scn:" + NextFrame.sceneIndex + " " + NextFrame.compPos + " " + NextFrame.rootPos)); return(NextFrame); } // if next frame on the buffer is a couple ahead of current, jump forward if (stepsFromLast > jumpForwardThreshold) { //Debug.Log( XDebug.Log(!XDebug.logInfo ? null : (Time.time + " NST:" + nst.NstId + " <b>Jumping forward</b> from " + CurrentIndex + " to " + nextValid.frameid + " (likely packetloss) from expected frame. " + nst.name + "\nCurrentFrame: " + currentFrame.frameid + " " + currentFrame.compPos + " " + currentFrame.rootPos + "\nNextValidFrame: " + nextValid.frameid + " " + nextValid.compPos + " " + nextValid.rootPos)); InvalidateOldFrames(nextValid); nextValid.CompletePosition(currentFrame); return(nextValid); } //All other cases we Reconstruct missing next frame using the current frame and a future frame NextFrame.state = currentFrame.state; float t = 1f / stepsFromLast; nextValid.CompletePosition(currentFrame); Vector3 lerpedPos = Vector3.Lerp(currentFrame.rootPos, nextValid.rootPos, t); float lerpedStartTime = Mathf.Lerp(currentFrame.packetArriveTime, nextValid.packetArriveTime, t); NextFrame.ModifyFrame(currentFrame.updateType, currentFrame.rootBitCullLevel, lerpedPos, GenericX.NULL, lerpedStartTime); //Debug.Log( XDebug.Log(!XDebug.logInfo ? null : (Time.time + " NST:" + nst.NstId + " <b>Reconstructing frame " + NextFrame.frameid + "</b> (likely packetloss) from current frame and future frame " + NextFrame.compPos + " <b>" + NextFrame.rootPos + "</b> " + nst.name + "\nCurrentFrame: " + currentFrame.frameid + " scn:" + currentFrame.sceneIndex + " " + currentFrame.compPos + " " + currentFrame.rootPos + "\nNextValidFrame: " + nextValid.frameid + " scn:" + nextValid.sceneIndex + " " + nextValid.compPos + " " + nextValid.rootPos) + " " + nextValid.rootBitCullLevel); //XDebug.Log(!XDebug.logInfo ? null : // (Time.time + "fid" + NextFrame.frameid + " <color=red><b> RECONSTRUCT ELEMENTS </b></color> " + NextFrame.RootRot + " " + currentFrame.RootRot + " " + nextValid.RootRot)); // Notify all interested components that they need to reconstruct a missing frame (elements and such) foreach (INstOnReconstructMissing callbacks in nst.iNstOnReconstructMissing) { callbacks.OnReconstructMissing(NextFrame, currentFrame, nextValid, t, svrWaitingForTeleportConfirm); } return(NextFrame); }