@@ -121,14 +121,15 @@ internal struct CurrentState
121121 public float TimeToTargetValue ;
122122 public float DeltaTime ;
123123 public float LerpT ;
124-
124+ public bool TargetReached ;
125125 public T CurrentValue ;
126126 public T PreviousValue ;
127+ public T PredictValue ;
127128
128129 private float m_AverageDeltaTime ;
129130
130131 public float AverageDeltaTime => m_AverageDeltaTime ;
131- public float FinalTimeToTarget => TimeToTargetValue - DeltaTime ;
132+ public float FinalTimeToTarget => Mathf . Max ( 0.0f , TimeToTargetValue - DeltaTime ) ;
132133
133134 public void AddDeltaTime ( float deltaTime )
134135 {
@@ -151,20 +152,21 @@ public void ResetDelta()
151152 DeltaTime = 0.0f ;
152153 }
153154
154- public bool TargetTimeAproximatelyReached ( )
155+ public bool TargetTimeAproximatelyReached ( float adjustForNext = 1.0f )
155156 {
156157 if ( ! Target . HasValue )
157158 {
158159 return false ;
159160 }
160- return m_AverageDeltaTime >= FinalTimeToTarget ;
161+ return ( m_AverageDeltaTime * adjustForNext ) >= FinalTimeToTarget ;
161162 }
162163
163164 public void Reset ( T currentValue )
164165 {
165166 Target = null ;
166167 CurrentValue = currentValue ;
167168 PreviousValue = currentValue ;
169+ TargetReached = false ;
168170 // When reset, we consider ourselves to have already arrived at the target (even if no target is set)
169171 LerpT = 0.0f ;
170172 EndTime = 0.0 ;
@@ -273,69 +275,81 @@ private void InternalReset(T targetValue, double serverTime, bool isAngularValue
273275 /// <param name="maxDeltaTime">maximum time delta which defines the maximum time duration when consuming more than one item from the buffer</param>
274276 private void TryConsumeFromBuffer ( double renderTime , float minDeltaTime , float maxDeltaTime )
275277 {
276- if ( ! InterpolateState . Target . HasValue || ( InterpolateState . Target . Value . TimeSent <= renderTime
277- && ( InterpolateState . TargetTimeAproximatelyReached ( ) || IsAproximately ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item ) ) ) )
278+ BufferedItem ? previousItem = null ;
279+ var startTime = 0.0 ;
280+ var alreadyHasBufferItem = false ;
281+ var noStateSet = ! InterpolateState . Target . HasValue ;
282+ var potentialItemNeedsProcessing = false ;
283+ var currentTargetTimeReached = false ;
284+
285+ while ( m_BufferQueue . TryPeek ( out BufferedItem potentialItem ) )
278286 {
279- BufferedItem ? previousItem = null ;
280- var startTime = 0.0 ;
281- var alreadyHasBufferItem = false ;
282- while ( m_BufferQueue . TryPeek ( out BufferedItem potentialItem ) )
287+ // If we are still on the same buffered item (FIFO Queue), then exit early as there is nothing
288+ // to consume.
289+ if ( previousItem . HasValue && previousItem . Value . TimeSent == potentialItem . TimeSent )
283290 {
284- // If we are still on the same buffered item (FIFO Queue), then exit early as there is nothing
285- // to consume.
286- if ( previousItem . HasValue && previousItem . Value . TimeSent == potentialItem . TimeSent )
291+ break ;
292+ }
293+
294+ if ( ! noStateSet )
295+ {
296+ potentialItemNeedsProcessing = ( potentialItem . TimeSent <= renderTime ) && potentialItem . TimeSent >= InterpolateState . Target . Value . TimeSent ;
297+ currentTargetTimeReached = InterpolateState . TargetTimeAproximatelyReached ( potentialItemNeedsProcessing ? 1.5f : 1.0f ) ;
298+ if ( ! potentialItemNeedsProcessing && ! InterpolateState . TargetReached )
287299 {
288- break ;
300+ InterpolateState . TargetReached = IsAproximately ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item ) ;
289301 }
302+ }
290303
291- // If we haven't set a target or the potential item's time sent is less that the current target's time sent
292- // then pull the BufferedItem from the queue. The second portion of this accounts for scenarios where there
293- // was bad latency and the buffer has more than one item in the queue that is less than the renderTime. Under
294- // this scenario, we just want to continue pulling items from the queue until the last item pulled from the
295- // queue is greater than the redner time or greater than the currently targeted item.
296- if ( ! InterpolateState . Target . HasValue ||
297- ( ( potentialItem . TimeSent <= renderTime ) && InterpolateState . Target . Value . TimeSent <= potentialItem . TimeSent ) )
304+ // If we haven't set a target or the potential item's time sent is less that the current target's time sent
305+ // then pull the BufferedItem from the queue. The second portion of this accounts for scenarios where there
306+ // was bad latency and the buffer has more than one item in the queue that is less than the renderTime. Under
307+ // this scenario, we just want to continue pulling items from the queue until the last item pulled from the
308+ // queue is greater than the redner time or greater than the currently targeted item.
309+ if ( noStateSet || ( ( currentTargetTimeReached || InterpolateState . TargetReached ) && potentialItemNeedsProcessing ) )
310+ {
311+ if ( m_BufferQueue . TryDequeue ( out BufferedItem target ) )
298312 {
299- if ( m_BufferQueue . TryDequeue ( out BufferedItem target ) )
313+ if ( ! InterpolateState . Target . HasValue )
300314 {
301- if ( ! InterpolateState . Target . HasValue )
315+ InterpolateState . Target = target ;
316+
317+ alreadyHasBufferItem = true ;
318+ InterpolateState . PredictValue = InterpolateState . CurrentValue ;
319+ InterpolateState . PreviousValue = InterpolateState . CurrentValue ;
320+ InterpolateState . TimeToTargetValue = minDeltaTime ;
321+ startTime = InterpolateState . Target . Value . TimeSent ;
322+ InterpolateState . TargetReached = false ;
323+ }
324+ else
325+ {
326+ if ( ! alreadyHasBufferItem )
302327 {
303- InterpolateState . Target = target ;
304-
305328 alreadyHasBufferItem = true ;
306- InterpolateState . PreviousValue = InterpolateState . CurrentValue ;
307- InterpolateState . TimeToTargetValue = minDeltaTime ;
308329 startTime = InterpolateState . Target . Value . TimeSent ;
330+ //InterpolateState.PreviousValue = InterpolateState.CurrentValue;
331+ //InterpolateState.PredictValue = InterpolateState.CurrentValue;
332+ InterpolateState . LerpT = 0.0f ;
333+ InterpolateState . TargetReached = false ;
309334 }
310- else
311- {
312- if ( ! alreadyHasBufferItem )
313- {
314- alreadyHasBufferItem = true ;
315- startTime = InterpolateState . Target . Value . TimeSent ;
316- InterpolateState . PreviousValue = InterpolateState . CurrentValue ;
317- InterpolateState . LerpT = 0.0f ;
318- }
319- // TODO: We might consider creating yet another queue to add these items to and assure that the time is accelerated
320- // for each item as opposed to losing the resolution of the values.
321- InterpolateState . TimeToTargetValue = Mathf . Clamp ( ( float ) ( target . TimeSent - startTime ) , minDeltaTime , maxDeltaTime ) ;
322-
323- InterpolateState . Target = target ;
324- }
325- InterpolateState . ResetDelta ( ) ;
335+ // TODO: We might consider creating yet another queue to add these items to and assure that the time is accelerated
336+ // for each item as opposed to losing the resolution of the values.
337+ InterpolateState . TimeToTargetValue = Mathf . Clamp ( ( float ) ( target . TimeSent - startTime ) , minDeltaTime , maxDeltaTime ) ;
338+ InterpolateState . Target = target ;
326339 }
340+ InterpolateState . ResetDelta ( ) ;
327341 }
328- else
329- {
330- break ;
331- }
342+ }
343+ else
344+ {
345+ break ;
346+ }
332347
333- if ( ! InterpolateState . Target . HasValue )
334- {
335- break ;
336- }
337- previousItem = potentialItem ;
348+ if ( ! InterpolateState . Target . HasValue )
349+ {
350+ break ;
338351 }
352+ previousItem = potentialItem ;
339353 }
340354 }
341355
@@ -355,18 +369,24 @@ internal T Update(float deltaTime, double tickLatencyAsTime, float minDeltaTime,
355369 {
356370 TryConsumeFromBuffer ( tickLatencyAsTime , minDeltaTime , maxDeltaTime ) ;
357371 // Only interpolate when there is a start and end point and we have not already reached the end value
358- if ( InterpolateState . Target . HasValue )
372+ if ( InterpolateState . Target . HasValue && ! InterpolateState . TargetReached )
359373 {
360374 InterpolateState . AddDeltaTime ( deltaTime ) ;
361375
362- // Smooth dampen our current time
363- var current = SmoothDamp ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item , ref m_RateOfChange , InterpolateState . TimeToTargetValue , InterpolateState . DeltaTime ) ;
364- // Smooth dampen a predicted time based on our average delta time
365- var predict = SmoothDamp ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item , ref m_PredictedRateOfChange , InterpolateState . TimeToTargetValue , InterpolateState . DeltaTime + ( InterpolateState . AverageDeltaTime * 2 ) ) ;
366- // Lerp between the current and predicted.
367- // Note: Since smooth dampening cannot over shoot, both current and predict will eventually become the same or will be very close to the same.
368- // Upon stopping motion, the final resing value should be a very close aproximation of the authority side.
369- InterpolateState . CurrentValue = Interpolate ( current , predict , deltaTime ) ;
376+ {
377+
378+ // Smooth dampen our current time
379+ InterpolateState . PreviousValue = SmoothDamp ( InterpolateState . PreviousValue , InterpolateState . Target . Value . Item , ref m_RateOfChange , InterpolateState . TimeToTargetValue , InterpolateState . DeltaTime ) ;
380+ InterpolateState . PredictValue = SmoothDamp ( InterpolateState . PredictValue , InterpolateState . Target . Value . Item , ref m_PredictedRateOfChange , InterpolateState . TimeToTargetValue , Mathf . Min ( InterpolateState . TimeToTargetValue , InterpolateState . DeltaTime + InterpolateState . AverageDeltaTime ) ) ;
381+ // Smooth dampen a predicted time based on our minimum delta time
382+ //var predict = SmoothDamp(InterpolateState.CurrentValue, InterpolateState.Target.Value.Item, ref m_PredictedRateOfChange, InterpolateState.TimeToTargetValue, Mathf.Min(InterpolateState.TimeToTargetValue, InterpolateState.DeltaTime + InterpolateState.AverageDeltaTime));
383+
384+ // Lerp between the current and predicted.
385+ // Note: Since smooth dampening cannot over shoot, both current and predict will eventually become the same or will be very close to the same.
386+ // Upon stopping motion, the final resing value should be a very close aproximation of the authority side.
387+ InterpolateState . CurrentValue = Interpolate ( InterpolateState . PreviousValue , InterpolateState . PredictValue , deltaTime ) ;
388+
389+ }
370390 }
371391 m_NbItemsReceivedThisFrame = 0 ;
372392 return InterpolateState . CurrentValue ;
0 commit comments