@@ -391,7 +391,6 @@ public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReade
391
391
private readonly NetworkVariable < NetworkTransformState > m_ReplicatedNetworkStateServer = new NetworkVariable < NetworkTransformState > ( new NetworkTransformState ( ) , NetworkVariableReadPermission . Everyone , NetworkVariableWritePermission . Server ) ;
392
392
private readonly NetworkVariable < NetworkTransformState > m_ReplicatedNetworkStateOwner = new NetworkVariable < NetworkTransformState > ( new NetworkTransformState ( ) , NetworkVariableReadPermission . Everyone , NetworkVariableWritePermission . Owner ) ;
393
393
394
-
395
394
internal NetworkVariable < NetworkTransformState > ReplicatedNetworkState
396
395
{
397
396
get
@@ -405,10 +404,6 @@ internal NetworkVariable<NetworkTransformState> ReplicatedNetworkState
405
404
}
406
405
}
407
406
408
- private NetworkTransformState m_LocalAuthoritativeNetworkState ;
409
-
410
- private bool m_HasSentLastValue = false ; // used to send one last value, so clients can make the difference between lost replication data (clients extrapolate) and no more data to send.
411
-
412
407
private ClientRpcParams m_ClientRpcParams = new ClientRpcParams ( ) { Send = new ClientRpcSendParams ( ) } ;
413
408
private List < ulong > m_ClientIds = new List < ulong > ( ) { 0 } ;
414
409
@@ -421,12 +416,25 @@ internal NetworkVariable<NetworkTransformState> ReplicatedNetworkState
421
416
private BufferedLinearInterpolator < float > m_ScaleZInterpolator ;
422
417
private readonly List < BufferedLinearInterpolator < float > > m_AllFloatInterpolators = new List < BufferedLinearInterpolator < float > > ( 6 ) ;
423
418
424
- private int m_LastSentTick ;
419
+ // Used by both authoritative and non-authoritative instances.
420
+ // This represents the most recent local authoritative state.
421
+ private NetworkTransformState m_LocalAuthoritativeNetworkState ;
422
+
423
+ // Used by integration test
425
424
private NetworkTransformState m_LastSentState ;
426
425
427
- // Used by the non-authoritative side to handle ending extrapolation (replaces server sending)
426
+ // Used by the non-authoritative side to handle ending extrapolation
428
427
private NetworkTransformState m_LastReceivedState ;
429
428
429
+ /// Calculated when spawned, this is used to offset a newly received non-authority side state by 1 tick duration
430
+ /// in order to end the extrapolation for that state's values.
431
+ /// Example:
432
+ /// NetworkState-A is received, processed, and measurements added
433
+ /// NetworkState-A is duplicated (NetworkState-A-Post) and its sent time is offset by the tick frequency
434
+ /// One tick later, NetworkState-A-Post is applied to end that delta's extrapolation.
435
+ /// <see cref="OnNetworkStateChanged"/> to see how NetworkState-A-Post doesn't get excluded/missed
436
+ private double m_TickFrequency ;
437
+
430
438
internal NetworkTransformState GetLastSentState ( )
431
439
{
432
440
return m_LastSentState ;
@@ -449,19 +457,8 @@ protected void TryCommitTransformToServer(Transform transformToCommit, double di
449
457
return ;
450
458
}
451
459
452
- /// If authority is invoking this, then treat it like we do with <see cref="Update"/>
453
- if ( CanCommitToTransform )
454
- {
455
- // If our replicated state is not dirty and our local authority state is dirty, clear it.
456
- if ( ! ReplicatedNetworkState . IsDirty ( ) && m_LocalAuthoritativeNetworkState . IsDirty )
457
- {
458
- // Now clear our bitset and prepare for next network tick state update
459
- m_LocalAuthoritativeNetworkState . ClearBitSetForNextTick ( ) ;
460
- }
461
-
462
- TryCommitTransform ( transformToCommit , m_CachedNetworkManager . LocalTime . Time ) ;
463
- }
464
- else
460
+ // Either updates the authority or sends and RPC to the authoritative instance
461
+ if ( ! TryUpdateAuthority ( transformToCommit ) )
465
462
{
466
463
// We are an owner requesting to update our state
467
464
if ( ! m_CachedIsServer )
@@ -488,9 +485,10 @@ private void TryCommitTransform(Transform transformToCommit, double dirtyTime)
488
485
return ;
489
486
}
490
487
488
+ // If the transform has deltas (returns dirty) then...
491
489
if ( ApplyTransformToNetworkState ( ref m_LocalAuthoritativeNetworkState , dirtyTime , transformToCommit ) )
492
490
{
493
- // Commit the state
491
+ // ...commit the state
494
492
ReplicatedNetworkState . Value = m_LocalAuthoritativeNetworkState ;
495
493
}
496
494
}
@@ -765,12 +763,6 @@ private void ApplyAuthoritativeState()
765
763
}
766
764
}
767
765
768
- [ ServerRpc ]
769
- private void UpdateServerWithAppliedRotationServerRpc ( Vector3 eulerAngles )
770
- {
771
- Debug . Log ( $ "[{ name } ] client updated their rotation to ({ eulerAngles } )") ;
772
- }
773
-
774
766
/// <summary>
775
767
/// Only non-authoritative instances should invoke this
776
768
/// </summary>
@@ -924,27 +916,24 @@ private void AddInterpolatedState(NetworkTransformState newState)
924
916
}
925
917
926
918
currentRotation . eulerAngles = currentEulerAngles ;
927
- if ( ! IsServer && IsOwner )
928
- {
929
- UpdateServerWithUpdatedRotationServerRpc ( currentEulerAngles ) ;
930
- }
919
+
931
920
m_RotationInterpolator . AddMeasurement ( currentRotation , sentTime ) ;
932
921
}
933
922
}
934
923
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 ( )
924
+ /// <summary>
925
+ /// Stops extrapolating the <see cref="m_LastReceivedState"/>.
926
+ /// </summary>
927
+ /// <remarks>
928
+ /// <see cref="OnNetworkStateChanged"/>
929
+ /// </remarks>
930
+ private void StopExtrapolatingLastState ( )
942
931
{
943
932
if ( ! m_LastReceivedState . IsDirty || m_LastReceivedState . ExtrapolateTick >= NetworkManager . LocalTime . Tick )
944
933
{
945
934
return ;
946
935
}
947
- m_LastReceivedState . SentTime += 1.0 / NetworkManager . NetworkConfig . TickRate ;
936
+ m_LastReceivedState . SentTime += m_TickFrequency ;
948
937
AddInterpolatedState ( m_LastReceivedState ) ;
949
938
m_LastReceivedState . ClearBitSetForNextTick ( ) ;
950
939
}
@@ -967,7 +956,9 @@ private void OnNetworkStateChanged(NetworkTransformState oldState, NetworkTransf
967
956
968
957
if ( Interpolate )
969
958
{
970
- ApplyLastState ( ) ;
959
+ // This is "just in case" we receive a new state before the end
960
+ // of any currently applied and potentially extrapolating state.
961
+ StopExtrapolatingLastState ( ) ;
971
962
AddInterpolatedState ( newState ) ;
972
963
m_LastReceivedState = newState ;
973
964
m_LastReceivedState . ExtrapolateTick = NetworkManager . LocalTime . Tick ;
@@ -1020,6 +1011,7 @@ public override void OnNetworkSpawn()
1020
1011
{
1021
1012
m_CachedIsServer = IsServer ;
1022
1013
m_CachedNetworkManager = NetworkManager ;
1014
+ m_TickFrequency = 1.0 / NetworkManager . NetworkConfig . TickRate ;
1023
1015
1024
1016
Initialize ( ) ;
1025
1017
@@ -1201,8 +1193,31 @@ private void SetStateServerRpc(Vector3 pos, Quaternion rot, Vector3 scale, bool
1201
1193
TryCommitTransform ( transform , m_CachedNetworkManager . LocalTime . Time ) ;
1202
1194
}
1203
1195
1204
- // todo: this is currently in update, to be able to catch any transform changes. A FixedUpdate mode could be added to be less intense, but it'd be
1205
- // conditional to users only making transform update changes in FixedUpdate.
1196
+ /// <summary>
1197
+ /// If the instance is authority it will attempt to update the current tick
1198
+ /// network state and returns true.
1199
+ /// If it is not authority it exits early returning false.
1200
+ /// </summary>
1201
+ /// <param name="transformSource">transform to be updated</param>
1202
+ private bool TryUpdateAuthority ( Transform transformSource )
1203
+ {
1204
+ if ( ! CanCommitToTransform )
1205
+ {
1206
+ return false ;
1207
+ }
1208
+
1209
+ // If our replicated state is not dirty and our local authority state is dirty, clear it.
1210
+ if ( ! ReplicatedNetworkState . IsDirty ( ) && m_LocalAuthoritativeNetworkState . IsDirty )
1211
+ {
1212
+ m_LastSentState = m_LocalAuthoritativeNetworkState ;
1213
+ // Now clear our bitset and prepare for next network tick state update
1214
+ m_LocalAuthoritativeNetworkState . ClearBitSetForNextTick ( ) ;
1215
+ }
1216
+
1217
+ TryCommitTransform ( transformSource , m_CachedNetworkManager . LocalTime . Time ) ;
1218
+ return true ;
1219
+ }
1220
+
1206
1221
/// <inheritdoc/>
1207
1222
/// <remarks>
1208
1223
/// If you override this method, be sure that:
@@ -1217,21 +1232,14 @@ protected virtual void Update()
1217
1232
return ;
1218
1233
}
1219
1234
1220
- if ( CanCommitToTransform )
1221
- {
1222
- // If our replicated state is not dirty and our local authority state is dirty, clear it.
1223
- if ( ! ReplicatedNetworkState . IsDirty ( ) && m_LocalAuthoritativeNetworkState . IsDirty )
1224
- {
1225
- // Now clear our bitset and prepare for next network tick state update
1226
- m_LocalAuthoritativeNetworkState . ClearBitSetForNextTick ( ) ;
1227
- }
1228
- TryCommitTransform ( transform , m_CachedNetworkManager . LocalTime . Time ) ;
1229
- }
1230
- else
1235
+ // Either updates the authority or handle:
1236
+ // - Non-authoritative side interpolation
1237
+ // - Applying the current authoritative state
1238
+ // - Stop extrapolating the current state (if it is 1 tick after it was received)
1239
+ if ( ! TryUpdateAuthority ( transform ) )
1231
1240
{
1232
1241
if ( Interpolate )
1233
1242
{
1234
- // eventually, we could hoist this calculation so that it happens once for all objects, not once per object
1235
1243
var serverTime = NetworkManager . ServerTime ;
1236
1244
var cachedDeltaTime = Time . deltaTime ;
1237
1245
var cachedServerTime = serverTime . Time ;
@@ -1243,11 +1251,13 @@ protected virtual void Update()
1243
1251
1244
1252
m_RotationInterpolator . Update ( cachedDeltaTime , cachedRenderTime , cachedServerTime ) ;
1245
1253
}
1246
- // Now apply the current authoritative state
1247
- ApplyAuthoritativeState ( ) ;
1248
1254
1255
+ // Apply the current authoritative state
1256
+ ApplyAuthoritativeState ( ) ;
1249
1257
1250
- ApplyLastState ( ) ;
1258
+ // Handles stopping extrapolation for any previously
1259
+ // applied state.
1260
+ StopExtrapolatingLastState ( ) ;
1251
1261
}
1252
1262
}
1253
1263
0 commit comments