Skip to content

Commit b9a3a10

Browse files
refactor
Noticed an issue with the world space approach and rotating platforms (parents). This is a refactor of the same kind of approach (i.e. interpolator handles transform space updates) with the addition of tracking each measurement's parent, handling any transform space conversion if the current parent is different from the measurement's parent, and just keeping everything transform space relative.
1 parent c945ffb commit b9a3a10

File tree

2 files changed

+56
-34
lines changed

2 files changed

+56
-34
lines changed

com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ private float GetPrecision()
8787
/// </summary>
8888
protected internal struct BufferedItem
8989
{
90+
/// <summary>
91+
/// The transform parent for this specific value measurement.
92+
/// </summary>
93+
internal Transform MeasurementParent;
9094
/// <summary>
9195
/// The item identifier
9296
/// </summary>
@@ -111,6 +115,7 @@ public BufferedItem(T item, double timeSent, int itemId)
111115
Item = item;
112116
TimeSent = timeSent;
113117
ItemId = itemId;
118+
MeasurementParent = default;
114119
}
115120

116121
/// <summary>
@@ -124,6 +129,7 @@ public BufferedItem(T item, double timeSent)
124129
TimeSent = timeSent;
125130
// Generate a unique item id based on the time to the 2nd decimal place
126131
ItemId = (int)(timeSent * 100);
132+
MeasurementParent = default;
127133
}
128134
}
129135

@@ -135,6 +141,7 @@ public BufferedItem(T item, double timeSent)
135141
/// </remarks>
136142
internal struct CurrentState
137143
{
144+
public Transform TargetParent;
138145
public BufferedItem? Target;
139146
public double StartTime;
140147
public double EndTime;
@@ -225,7 +232,7 @@ public void Reset(T currentValue)
225232
/// </summary>
226233
internal float MaxInterpolationBound = 3.0f;
227234
internal bool EndOfBuffer => m_BufferQueue.Count == 0;
228-
internal bool StoreAsWorldSpace;
235+
internal bool AutoConvertTransformSpace;
229236
internal bool InLocalSpace;
230237
internal Transform Parent;
231238

@@ -271,22 +278,41 @@ internal void ResetTo(Transform parent, T targetValue, double serverTime)
271278
}
272279

273280
[MethodImpl(MethodImplOptions.AggressiveInlining)]
274-
private bool ConvertTransformSpace(Transform parent)
281+
private void ConvertInterpolateStateValues(Transform parent, bool inLocalSpace)
275282
{
276-
return StoreAsWorldSpace && parent != null && InLocalSpace;
283+
InterpolateState.CurrentValue = OnConvertTransformSpace(parent, InterpolateState.CurrentValue, inLocalSpace);
284+
InterpolateState.NextValue = OnConvertTransformSpace(parent, InterpolateState.NextValue, inLocalSpace);
285+
InterpolateState.PreviousValue = OnConvertTransformSpace(parent, InterpolateState.PreviousValue, inLocalSpace);
277286
}
278287

288+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
289+
private void ConvertTransformSpace()
290+
{
291+
if (!AutoConvertTransformSpace)
292+
{
293+
return;
294+
}
295+
if (InterpolateState.TargetParent != Parent)
296+
{
297+
if (InterpolateState.TargetParent != null)
298+
{
299+
// Convert to world space.
300+
ConvertInterpolateStateValues(InterpolateState.TargetParent, false);
301+
}
302+
303+
if (Parent != null)
304+
{
305+
// Convert to local space.
306+
ConvertInterpolateStateValues(Parent, true);
307+
}
308+
}
309+
}
279310

280311
[MethodImpl(MethodImplOptions.AggressiveInlining)]
281312
private void InternalReset(Transform parent, T targetValue, double serverTime, bool addMeasurement = true)
282313
{
283314
m_RateOfChange = default;
284315
var currentValue = targetValue;
285-
if (ConvertTransformSpace(parent))
286-
{
287-
// Keep everything in world space
288-
currentValue = OnConvertTransformSpace(parent, targetValue, false);
289-
}
290316

291317
// Set our initial value (what we will interpolate from relative to the next state update received)
292318
InterpolateState.Reset(currentValue);
@@ -340,6 +366,8 @@ private void TryConsumeFromBuffer(double renderTime, double minDeltaTime, double
340366
{
341367
if (m_BufferQueue.TryDequeue(out BufferedItem target))
342368
{
369+
ConvertTransformSpace();
370+
343371
if (!InterpolateState.Target.HasValue)
344372
{
345373
InterpolateState.Target = target;
@@ -365,6 +393,7 @@ private void TryConsumeFromBuffer(double renderTime, double minDeltaTime, double
365393
InterpolateState.SetTimeToTarget(Math.Max(target.TimeSent - startTime, minDeltaTime));
366394
InterpolateState.Target = target;
367395
}
396+
InterpolateState.TargetParent = target.MeasurementParent;
368397
}
369398
}
370399
else
@@ -487,6 +516,7 @@ private void TryConsumeFromBuffer(double renderTime, double serverTime)
487516
{
488517
if (m_BufferQueue.TryDequeue(out BufferedItem target))
489518
{
519+
ConvertTransformSpace();
490520
if (!InterpolateState.Target.HasValue)
491521
{
492522
InterpolateState.Target = target;
@@ -509,6 +539,7 @@ private void TryConsumeFromBuffer(double renderTime, double serverTime)
509539
InterpolateState.TimeToTargetValue = InterpolateState.EndTime - InterpolateState.StartTime;
510540
InterpolateState.Target = target;
511541
}
542+
InterpolateState.TargetParent = target.MeasurementParent;
512543
}
513544
}
514545

@@ -535,7 +566,7 @@ public T Update(float deltaTime, double renderTime, double serverTime)
535566
{
536567
TryConsumeFromBuffer(renderTime, serverTime);
537568
// Only interpolate when there is a start and end point and we have not already reached the end value
538-
if (InterpolateState.Target.HasValue && !InterpolateState.TargetReached)
569+
if (!InterpolateState.TargetReached && InterpolateState.Target.HasValue)
539570
{
540571
// The original BufferedLinearInterpolator lerping script to assure the Smooth Dampening updates do not impact
541572
// this specific behavior.
@@ -561,7 +592,7 @@ public T Update(float deltaTime, double renderTime, double serverTime)
561592
InterpolateState.TargetReached = IsApproximately(InterpolateState.CurrentValue, InterpolateState.Target.Value.Item, GetPrecision());
562593
}
563594
else // If the target is reached and we have no more state updates, we want to check to see if we need to reset.
564-
if (m_BufferQueue.Count == 0 && InterpolateState.TargetReached)
595+
if (InterpolateState.TargetReached && m_BufferQueue.Count == 0)
565596
{
566597
// When the delta between the time sent and the current tick latency time-window is greater than the max delta time
567598
// plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero),
@@ -614,14 +645,6 @@ public void AddMeasurement(T newMeasurement, double sentTime)
614645
internal void AddMeasurement(Transform parent, T newMeasurement, double sentTime)
615646
{
616647
m_NbItemsReceivedThisFrame++;
617-
var previousMeasurement = newMeasurement;
618-
// If enabled, convert everything to world space if in local space.
619-
if (ConvertTransformSpace(parent))
620-
{
621-
// Keep everything in world space
622-
newMeasurement = OnConvertTransformSpace(parent, newMeasurement, false);
623-
}
624-
625648
// This situation can happen after a game is paused. When starting to receive again, the server will have sent a bunch of messages in the meantime
626649
// instead of going through thousands of value updates just to get a big teleport, we're giving up on interpolation and teleporting to the latest value
627650
if (m_NbItemsReceivedThisFrame > k_BufferCountLimit)
@@ -633,7 +656,10 @@ internal void AddMeasurement(Transform parent, T newMeasurement, double sentTime
633656
// Reset to the new value but don't automatically add the measurement (prevents recursion)
634657
InternalReset(parent, newMeasurement, sentTime, false);
635658
m_LastMeasurementAddedTime = sentTime;
636-
m_LastBufferedItemReceived = new BufferedItem(newMeasurement, sentTime, m_BufferCount);
659+
m_LastBufferedItemReceived = new BufferedItem(newMeasurement, sentTime, m_BufferCount)
660+
{
661+
MeasurementParent = parent,
662+
};
637663
// Next line keeps renderTime above m_StartTimeConsumed. Fixes pause/unpause issues
638664
m_BufferQueue.Enqueue(m_LastBufferedItemReceived);
639665
}
@@ -644,7 +670,10 @@ internal void AddMeasurement(Transform parent, T newMeasurement, double sentTime
644670
if (sentTime > m_LastMeasurementAddedTime || m_BufferCount == 0)
645671
{
646672
m_BufferCount++;
647-
m_LastBufferedItemReceived = new BufferedItem(newMeasurement, sentTime, m_BufferCount);
673+
m_LastBufferedItemReceived = new BufferedItem(newMeasurement, sentTime, m_BufferCount)
674+
{
675+
MeasurementParent = parent,
676+
};
648677
m_BufferQueue.Enqueue(m_LastBufferedItemReceived);
649678
m_LastMeasurementAddedTime = sentTime;
650679
}
@@ -657,14 +686,7 @@ internal void AddMeasurement(Transform parent, T newMeasurement, double sentTime
657686
[MethodImpl(MethodImplOptions.AggressiveInlining)]
658687
public T GetInterpolatedValue()
659688
{
660-
var currentValue = InterpolateState.CurrentValue;
661-
// If we are auto adjusting the value from world to local
662-
if (ConvertTransformSpace(Parent))
663-
{
664-
// Convert to local space
665-
currentValue = OnConvertTransformSpace(Parent, currentValue, true);
666-
}
667-
return currentValue;
689+
return InterpolateState.CurrentValue;
668690
}
669691

670692
/// <summary>

com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2579,7 +2579,7 @@ internal void UpdatePositionInterpolator(Vector3 position, double time, bool res
25792579
{
25802580
if (resetInterpolator)
25812581
{
2582-
m_PositionInterpolator.StoreAsWorldSpace = SwitchTransformSpaceWhenParented;
2582+
m_PositionInterpolator.AutoConvertTransformSpace = SwitchTransformSpaceWhenParented;
25832583
m_PositionInterpolator.InLocalSpace = InLocalSpace;
25842584
m_PositionInterpolator.ResetTo(transform.parent, position, time);
25852585
}
@@ -3058,7 +3058,7 @@ private void ApplyTeleportingState(NetworkTransformState newState)
30583058

30593059
if (Interpolate)
30603060
{
3061-
m_RotationInterpolator.StoreAsWorldSpace = SwitchTransformSpaceWhenParented;
3061+
m_RotationInterpolator.AutoConvertTransformSpace = SwitchTransformSpaceWhenParented;
30623062
m_RotationInterpolator.InLocalSpace = newState.InLocalSpace;
30633063
m_RotationInterpolator.ResetTo(transform.parent, currentRotation, sentTime);
30643064
}
@@ -3646,12 +3646,12 @@ private void ResetInterpolatedStateToCurrentAuthoritativeState()
36463646
var rotation = GetSpaceRelativeRotation();
36473647
#endif
36483648
// Reset interpolators to the current state of the NetworkTransform
3649-
m_PositionInterpolator.StoreAsWorldSpace = SwitchTransformSpaceWhenParented;
3649+
m_PositionInterpolator.AutoConvertTransformSpace = SwitchTransformSpaceWhenParented;
36503650
m_PositionInterpolator.InLocalSpace = InLocalSpace;
36513651
UpdatePositionInterpolator(position, serverTime, true);
36523652
UpdatePositionSlerp();
36533653

3654-
m_RotationInterpolator.StoreAsWorldSpace = SwitchTransformSpaceWhenParented;
3654+
m_RotationInterpolator.AutoConvertTransformSpace = SwitchTransformSpaceWhenParented;
36553655
m_RotationInterpolator.InLocalSpace = InLocalSpace;
36563656
m_RotationInterpolator.ResetTo(transform.parent, rotation, serverTime);
36573657

@@ -3897,7 +3897,7 @@ internal override void InternalOnNetworkObjectParentChanged(NetworkObject parent
38973897

38983898
if (SynchronizePosition)
38993899
{
3900-
m_PositionInterpolator.StoreAsWorldSpace = SwitchTransformSpaceWhenParented;
3900+
m_PositionInterpolator.AutoConvertTransformSpace = SwitchTransformSpaceWhenParented;
39013901
m_PositionInterpolator.InLocalSpace = InLocalSpace;
39023902
m_PositionInterpolator.Parent = InLocalSpace ? parentNetworkObject.transform : null;
39033903
var parentName = InLocalSpace ? parentNetworkObject.name : "root";
@@ -3923,7 +3923,7 @@ internal override void InternalOnNetworkObjectParentChanged(NetworkObject parent
39233923

39243924
if (SynchronizeRotation)
39253925
{
3926-
m_RotationInterpolator.StoreAsWorldSpace = SwitchTransformSpaceWhenParented;
3926+
m_RotationInterpolator.AutoConvertTransformSpace = SwitchTransformSpaceWhenParented;
39273927
m_RotationInterpolator.InLocalSpace = InLocalSpace;
39283928
m_RotationInterpolator.Parent = InLocalSpace ? parentNetworkObject.transform : null;
39293929
if (LastTickSync == m_LocalAuthoritativeNetworkState.GetNetworkTick())

0 commit comments

Comments
 (0)