11using System ;
22using System . Collections . Generic ;
3+ using System . Runtime . CompilerServices ;
34using UnityEngine ;
45
56namespace Unity . Netcode
@@ -14,9 +15,16 @@ public abstract class BufferedLinearInterpolator<T> where T : struct
1415 // Constant absolute value for max buffer count instead of dynamic time based value. This is in case we have very low tick rates, so
1516 // that we don't have a very small buffer because of this.
1617 private const int k_BufferCountLimit = 100 ;
17- private const float k_AproximatePrecision = 0.0001f ;
18+ private const float k_ApproximateLowPrecision = 0.000001f ;
19+ private const float k_ApproximateHighPrecision = 1E-10f ;
1820 private const double k_SmallValue = 9.999999439624929E-11 ; // copied from Vector3's equal operator
1921
22+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
23+ private float GetPrecision ( )
24+ {
25+ return m_BufferQueue . Count == 0 ? k_ApproximateHighPrecision : k_ApproximateLowPrecision ;
26+ }
27+
2028 #region Legacy notes
2129 // Buffer consumption scenarios
2230 // Perfect case consumption
@@ -132,20 +140,23 @@ internal struct CurrentState
132140 public float CurrentDeltaTime => m_CurrentDeltaTime ;
133141 public double FinalTimeToTarget => Math . Max ( 0.0 , TimeToTargetValue - DeltaTime ) ;
134142
143+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
135144 public void AddDeltaTime ( float deltaTime )
136145 {
137146 m_CurrentDeltaTime = deltaTime ;
138147 DeltaTime = Math . Min ( DeltaTime + deltaTime , TimeToTargetValue ) ;
139148 LerpT = ( float ) ( TimeToTargetValue == 0.0 ? 1.0 : DeltaTime / TimeToTargetValue ) ;
140149 }
141150
151+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
142152 public void SetTimeToTarget ( double timeToTarget )
143153 {
144154 LerpT = 0.0f ;
145155 DeltaTime = 0.0f ;
146156 TimeToTargetValue = timeToTarget ;
147157 }
148158
159+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
149160 public bool TargetTimeAproximatelyReached ( )
150161 {
151162 if ( ! Target . HasValue )
@@ -237,6 +248,7 @@ public void ResetTo(T targetValue, double serverTime)
237248 InternalReset ( targetValue , serverTime ) ;
238249 }
239250
251+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
240252 private void InternalReset ( T targetValue , double serverTime , bool addMeasurement = true )
241253 {
242254 m_RateOfChange = default ;
@@ -271,7 +283,7 @@ private void TryConsumeFromBuffer(double renderTime, double minDeltaTime, double
271283 {
272284 if ( ! InterpolateState . TargetReached )
273285 {
274- InterpolateState . TargetReached = IsAproximately ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item ) ;
286+ InterpolateState . TargetReached = IsApproximately ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item , GetPrecision ( ) ) ;
275287 }
276288 return ;
277289 }
@@ -291,7 +303,7 @@ private void TryConsumeFromBuffer(double renderTime, double minDeltaTime, double
291303 potentialItemNeedsProcessing = ( ( potentialItem . TimeSent <= renderTime ) && potentialItem . TimeSent > InterpolateState . Target . Value . TimeSent ) ;
292304 if ( ! InterpolateState . TargetReached )
293305 {
294- InterpolateState . TargetReached = IsAproximately ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item ) ;
306+ InterpolateState . TargetReached = IsApproximately ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item , GetPrecision ( ) ) ;
295307 }
296308 }
297309
@@ -424,6 +436,7 @@ internal T Update(float deltaTime, double tickLatencyAsTime, double minDeltaTime
424436 /// This version of TryConsumeFromBuffer adheres to the original BufferedLinearInterpolator buffer consumption pattern.
425437 /// </remarks>
426438 /// <param name="renderTime"></param>
439+ /// <param name="serverTime"></param>
427440 private void TryConsumeFromBuffer ( double renderTime , double serverTime )
428441 {
429442 if ( ! InterpolateState . Target . HasValue || ( InterpolateState . Target . Value . TimeSent <= renderTime ) )
@@ -433,14 +446,16 @@ private void TryConsumeFromBuffer(double renderTime, double serverTime)
433446 while ( m_BufferQueue . TryPeek ( out BufferedItem potentialItem ) )
434447 {
435448 // If we are still on the same buffered item (FIFO Queue), then exit early as there is nothing
436- // to consume.
449+ // to consume. (just a safety check but this scenario should never happen based on the below legacy approach of
450+ // consuming until the most current state)
437451 if ( previousItem . HasValue && previousItem . Value . TimeSent == potentialItem . TimeSent )
438452 {
439453 break ;
440454 }
441455
442- if ( ( potentialItem . TimeSent <= serverTime ) &&
443- ( ! InterpolateState . Target . HasValue || InterpolateState . Target . Value . TimeSent < potentialItem . TimeSent ) )
456+ // Continue to processing until we reach the most current state
457+ if ( ( potentialItem . TimeSent <= serverTime ) && // Inverted logic (below) from original since we have to go from past to present
458+ ( ! InterpolateState . Target . HasValue || potentialItem . TimeSent > InterpolateState . Target . Value . TimeSent ) )
444459 {
445460 if ( m_BufferQueue . TryDequeue ( out BufferedItem target ) )
446461 {
@@ -449,6 +464,7 @@ private void TryConsumeFromBuffer(double renderTime, double serverTime)
449464 InterpolateState . Target = target ;
450465 alreadyHasBufferItem = true ;
451466 InterpolateState . NextValue = InterpolateState . CurrentValue ;
467+ InterpolateState . PreviousValue = InterpolateState . CurrentValue ;
452468 InterpolateState . StartTime = target . TimeSent ;
453469 InterpolateState . EndTime = target . TimeSent ;
454470 }
@@ -458,19 +474,15 @@ private void TryConsumeFromBuffer(double renderTime, double serverTime)
458474 {
459475 alreadyHasBufferItem = true ;
460476 InterpolateState . StartTime = InterpolateState . Target . Value . TimeSent ;
461- InterpolateState . NextValue = InterpolateState . CurrentValue ;
477+ InterpolateState . PreviousValue = InterpolateState . NextValue ;
462478 InterpolateState . TargetReached = false ;
463479 }
464480 InterpolateState . EndTime = target . TimeSent ;
465- InterpolateState . Target = target ;
466481 InterpolateState . TimeToTargetValue = InterpolateState . EndTime - InterpolateState . StartTime ;
482+ InterpolateState . Target = target ;
467483 }
468484 }
469485 }
470- else
471- {
472- break ;
473- }
474486
475487 if ( ! InterpolateState . Target . HasValue )
476488 {
@@ -505,19 +517,20 @@ public T Update(float deltaTime, double renderTime, double serverTime)
505517 InterpolateState . LerpT = Math . Clamp ( ( float ) ( ( renderTime - InterpolateState . StartTime ) / InterpolateState . TimeToTargetValue ) , 0.0f , 1.0f ) ;
506518 }
507519
508- var target = Interpolate ( InterpolateState . NextValue , InterpolateState . Target . Value . Item , InterpolateState . LerpT ) ;
520+ InterpolateState . NextValue = Interpolate ( InterpolateState . PreviousValue , InterpolateState . Target . Value . Item , InterpolateState . LerpT ) ;
509521
510522 if ( LerpSmoothEnabled )
511523 {
512524 // Assure our MaximumInterpolationTime is valid and that the second lerp time ranges between deltaTime and 1.0f.
513- InterpolateState . CurrentValue = Interpolate ( InterpolateState . CurrentValue , target , deltaTime / MaximumInterpolationTime ) ;
525+ InterpolateState . CurrentValue = Interpolate ( InterpolateState . CurrentValue , InterpolateState . NextValue , deltaTime / MaximumInterpolationTime ) ;
514526 }
515527 else
516528 {
517- InterpolateState . CurrentValue = target ;
529+ InterpolateState . CurrentValue = InterpolateState . NextValue ;
518530 }
531+
519532 // Determine if we have reached our target
520- InterpolateState . TargetReached = IsAproximately ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item ) ;
533+ InterpolateState . TargetReached = IsApproximately ( InterpolateState . CurrentValue , InterpolateState . Target . Value . Item , GetPrecision ( ) ) ;
521534 }
522535 else // If the target is reached and we have no more state updates, we want to check to see if we need to reset.
523536 if ( m_BufferQueue . Count == 0 && InterpolateState . TargetReached )
@@ -601,6 +614,7 @@ public void AddMeasurement(T newMeasurement, double sentTime)
601614 /// Gets latest value from the interpolator. This is updated every update as time goes by.
602615 /// </summary>
603616 /// <returns>The current interpolated value of type 'T'</returns>
617+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
604618 public T GetInterpolatedValue ( )
605619 {
606620 return InterpolateState . CurrentValue ;
@@ -638,6 +652,7 @@ public T GetInterpolatedValue()
638652 /// <param name="deltaTime">The increasing delta time from when start to finish.</param>
639653 /// <param name="maxSpeed">Maximum rate of change per pass.</param>
640654 /// <returns>The smoothed <see cref="T"/> value.</returns>
655+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
641656 private protected virtual T SmoothDamp ( T current , T target , ref T rateOfChange , float duration , float deltaTime , float maxSpeed = Mathf . Infinity )
642657 {
643658 return target ;
@@ -653,7 +668,8 @@ private protected virtual T SmoothDamp(T current, T target, ref T rateOfChange,
653668 /// <param name="second">Second value of type <see cref="T"/>.</param>
654669 /// <param name="precision">The precision of the aproximation.</param>
655670 /// <returns>true if the two values are aproximately the same and false if they are not</returns>
656- private protected virtual bool IsAproximately ( T first , T second , float precision = k_AproximatePrecision )
671+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
672+ private protected virtual bool IsApproximately ( T first , T second , float precision = k_ApproximateLowPrecision )
657673 {
658674 return false ;
659675 }
@@ -665,6 +681,7 @@ private protected virtual bool IsAproximately(T first, T second, float precision
665681 /// <param name="item">The item to convert.</param>
666682 /// <param name="inLocalSpace">local or world space (true or false).</param>
667683 /// <returns>The converted value.</returns>
684+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
668685 protected internal virtual T OnConvertTransformSpace ( Transform transform , T item , bool inLocalSpace )
669686 {
670687 return default ;
@@ -675,6 +692,7 @@ protected internal virtual T OnConvertTransformSpace(Transform transform, T item
675692 /// </summary>
676693 /// <param name="transform">The transform that the <see cref="Components.NetworkTransform"/> is associated with.</param>
677694 /// <param name="inLocalSpace">Whether the <see cref="Components.NetworkTransform"/> is now being tracked in local or world spaced.</param>
695+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
678696 internal void ConvertTransformSpace ( Transform transform , bool inLocalSpace )
679697 {
680698 var count = m_BufferQueue . Count ;
0 commit comments