@@ -208,6 +208,7 @@ internal bool IsTeleportingNextFrame
208
208
internal double SentTime ;
209
209
210
210
internal bool IsDirty ;
211
+ internal int ExtrapolateTick ;
211
212
212
213
/// <summary>
213
214
/// This will reset the NetworkTransform BitSet
@@ -423,6 +424,9 @@ internal NetworkVariable<NetworkTransformState> ReplicatedNetworkState
423
424
private int m_LastSentTick ;
424
425
private NetworkTransformState m_LastSentState ;
425
426
427
+ // Used by the non-authoritative side to handle ending extrapolation (replaces server sending)
428
+ private NetworkTransformState m_LastReceivedState ;
429
+
426
430
internal NetworkTransformState GetLastSentState ( )
427
431
{
428
432
return m_LastSentState ;
@@ -483,32 +487,11 @@ private void TryCommitTransform(Transform transformToCommit, double dirtyTime)
483
487
NetworkLog . LogError ( $ "[{ name } ] is trying to commit the transform without authority!") ;
484
488
return ;
485
489
}
486
- var isDirty = ApplyTransformToNetworkState ( ref m_LocalAuthoritativeNetworkState , dirtyTime , transformToCommit ) ;
487
490
488
- // if dirty, send
489
- // if not dirty anymore, but hasn't sent last value for limiting extrapolation, still set isDirty
490
- // if not dirty and has already sent last value, don't do anything
491
- // extrapolation works by using last two values. if it doesn't receive anything anymore, it'll continue to extrapolate.
492
- // This is great in case there's message loss, not so great if we just don't have new values to send.
493
- // the following will send one last "copied" value so unclamped interpolation tries to extrapolate between two identical values, effectively
494
- // making it immobile.
495
- if ( isDirty )
491
+ if ( ApplyTransformToNetworkState ( ref m_LocalAuthoritativeNetworkState , dirtyTime , transformToCommit ) )
496
492
{
497
493
// Commit the state
498
494
ReplicatedNetworkState . Value = m_LocalAuthoritativeNetworkState ;
499
- m_HasSentLastValue = false ;
500
- m_LastSentTick = m_CachedNetworkManager . LocalTime . Tick ;
501
- m_LastSentState = m_LocalAuthoritativeNetworkState ;
502
- }
503
- else if ( ! m_HasSentLastValue && m_CachedNetworkManager . LocalTime . Tick >= m_LastSentTick + 1 ) // check for state.IsDirty since update can happen more than once per tick. No need for client, RPCs will just queue up
504
- {
505
- // Since the last m_LocalAuthoritativeNetworkState could have included a IsTeleportingNextFrame
506
- // we need to reset this here so only the deltas are applied and interpolation is not reset again.
507
- m_LastSentState . IsTeleportingNextFrame = false ;
508
- m_LastSentState . SentTime = m_CachedNetworkManager . LocalTime . Time ; // time 1+ tick later
509
- // Commit the state
510
- ReplicatedNetworkState . Value = m_LastSentState ;
511
- m_HasSentLastValue = true ;
512
495
}
513
496
}
514
497
@@ -671,26 +654,33 @@ private void ApplyAuthoritativeState()
671
654
{
672
655
interpolatedPosition . x = isTeleporting || ! Interpolate ? networkState . PositionX : m_PositionXInterpolator . GetInterpolatedValue ( ) ;
673
656
}
657
+ else if ( Interpolate && SyncPositionX )
658
+ {
659
+ interpolatedPosition . x = m_PositionXInterpolator . GetInterpolatedValue ( ) ;
660
+ }
674
661
675
662
if ( networkState . HasPositionY )
676
663
{
677
664
interpolatedPosition . y = isTeleporting || ! Interpolate ? networkState . PositionY : m_PositionYInterpolator . GetInterpolatedValue ( ) ;
678
665
}
666
+ else if ( Interpolate && SyncPositionY )
667
+ {
668
+ interpolatedPosition . y = m_PositionYInterpolator . GetInterpolatedValue ( ) ;
669
+ }
679
670
680
671
if ( networkState . HasPositionZ )
681
672
{
682
673
interpolatedPosition . z = isTeleporting || ! Interpolate ? networkState . PositionZ : m_PositionZInterpolator . GetInterpolatedValue ( ) ;
683
674
}
675
+ else if ( Interpolate && SyncPositionZ )
676
+ {
677
+ interpolatedPosition . z = m_PositionZInterpolator . GetInterpolatedValue ( ) ;
678
+ }
684
679
685
680
// Update the rotation values that were changed in this state update
686
681
if ( networkState . HasRotAngleChange )
687
682
{
688
- var eulerAngles = new Vector3 ( ) ;
689
- if ( Interpolate )
690
- {
691
- eulerAngles = m_RotationInterpolator . GetInterpolatedValue ( ) . eulerAngles ;
692
- }
693
-
683
+ var eulerAngles = Interpolate ? m_RotationInterpolator . GetInterpolatedValue ( ) . eulerAngles : new Vector3 ( ) ;
694
684
if ( networkState . HasRotAngleX )
695
685
{
696
686
interpolatedRotAngles . x = isTeleporting || ! Interpolate ? networkState . RotAngleX : eulerAngles . x ;
@@ -706,6 +696,25 @@ private void ApplyAuthoritativeState()
706
696
interpolatedRotAngles . z = isTeleporting || ! Interpolate ? networkState . RotAngleZ : eulerAngles . z ;
707
697
}
708
698
}
699
+ else if ( Interpolate && SyncRotAngleX || SyncRotAngleY || SyncRotAngleZ )
700
+ {
701
+ var eulerAngles = m_RotationInterpolator . GetInterpolatedValue ( ) . eulerAngles ;
702
+ interpolatedRotAngles = eulerAngles ;
703
+ if ( SyncRotAngleY )
704
+ {
705
+ interpolatedRotAngles . x = m_RotationInterpolator . GetInterpolatedValue ( ) . eulerAngles . x ;
706
+ }
707
+
708
+ if ( SyncRotAngleY )
709
+ {
710
+ interpolatedRotAngles . y = m_RotationInterpolator . GetInterpolatedValue ( ) . eulerAngles . y ;
711
+ }
712
+
713
+ if ( SyncRotAngleY )
714
+ {
715
+ interpolatedRotAngles . y = m_RotationInterpolator . GetInterpolatedValue ( ) . eulerAngles . y ;
716
+ }
717
+ }
709
718
710
719
// Update all scale axis that were changed in this state update
711
720
if ( networkState . HasScaleX )
@@ -724,11 +733,10 @@ private void ApplyAuthoritativeState()
724
733
}
725
734
726
735
// Apply the new position
727
- if ( networkState . HasPositionChange )
736
+ if ( networkState . HasPositionChange || Interpolate && ( SyncPositionX || SyncPositionY || SyncPositionZ ) )
728
737
{
729
738
if ( InLocalSpace )
730
739
{
731
-
732
740
transform . localPosition = interpolatedPosition ;
733
741
}
734
742
else
@@ -738,7 +746,7 @@ private void ApplyAuthoritativeState()
738
746
}
739
747
740
748
// Apply the new rotation
741
- if ( networkState . HasRotAngleChange )
749
+ if ( networkState . HasRotAngleChange || Interpolate && ( SyncRotAngleX || SyncRotAngleY || SyncRotAngleZ ) )
742
750
{
743
751
if ( InLocalSpace )
744
752
{
@@ -751,12 +759,18 @@ private void ApplyAuthoritativeState()
751
759
}
752
760
753
761
// Apply the new scale
754
- if ( networkState . HasScaleChange )
762
+ if ( networkState . HasScaleChange || Interpolate && ( SyncScaleX || SyncScaleY || SyncScaleZ ) )
755
763
{
756
764
transform . localScale = interpolatedScale ;
757
765
}
758
766
}
759
767
768
+ [ ServerRpc ]
769
+ private void UpdateServerWithAppliedRotationServerRpc ( Vector3 eulerAngles )
770
+ {
771
+ Debug . Log ( $ "[{ name } ] client updated their rotation to ({ eulerAngles } )") ;
772
+ }
773
+
760
774
/// <summary>
761
775
/// Only non-authoritative instances should invoke this
762
776
/// </summary>
@@ -910,10 +924,31 @@ private void AddInterpolatedState(NetworkTransformState newState)
910
924
}
911
925
912
926
currentRotation . eulerAngles = currentEulerAngles ;
927
+ if ( ! IsServer && IsOwner )
928
+ {
929
+ UpdateServerWithUpdatedRotationServerRpc ( currentEulerAngles ) ;
930
+ }
913
931
m_RotationInterpolator . AddMeasurement ( currentRotation , sentTime ) ;
914
932
}
915
933
}
916
934
935
+ [ ServerRpc ]
936
+ private void UpdateServerWithUpdatedRotationServerRpc ( Vector3 eulerAngles )
937
+ {
938
+ Debug . Log ( $ "[{ name } ] Client notified it updated rotation interpolator with ({ eulerAngles } )") ;
939
+ }
940
+
941
+ private void ApplyLastState ( )
942
+ {
943
+ if ( ! m_LastReceivedState . IsDirty || m_LastReceivedState . ExtrapolateTick >= NetworkManager . LocalTime . Tick )
944
+ {
945
+ return ;
946
+ }
947
+ m_LastReceivedState . SentTime += 1.0 / NetworkManager . NetworkConfig . TickRate ;
948
+ AddInterpolatedState ( m_LastReceivedState ) ;
949
+ m_LastReceivedState . ClearBitSetForNextTick ( ) ;
950
+ }
951
+
917
952
/// <summary>
918
953
/// Only non-authoritative instances should invoke this method
919
954
/// </summary>
@@ -932,7 +967,10 @@ private void OnNetworkStateChanged(NetworkTransformState oldState, NetworkTransf
932
967
933
968
if ( Interpolate )
934
969
{
970
+ ApplyLastState ( ) ;
935
971
AddInterpolatedState ( newState ) ;
972
+ m_LastReceivedState = newState ;
973
+ m_LastReceivedState . ExtrapolateTick = NetworkManager . LocalTime . Tick ;
936
974
}
937
975
}
938
976
@@ -1207,6 +1245,9 @@ protected virtual void Update()
1207
1245
}
1208
1246
// Now apply the current authoritative state
1209
1247
ApplyAuthoritativeState ( ) ;
1248
+
1249
+
1250
+ ApplyLastState ( ) ;
1210
1251
}
1211
1252
}
1212
1253
0 commit comments