@@ -227,7 +227,7 @@ private void BuildDestinationToTransitionInfoTable()
227
227
}
228
228
229
229
/// <summary>
230
- /// Creates the
230
+ /// Creates the TransitionStateInfoList table
231
231
/// </summary>
232
232
private void BuildTransitionStateInfoList ( )
233
233
{
@@ -305,7 +305,6 @@ public void OnBeforeSerialize()
305
305
306
306
internal struct AnimationState : INetworkSerializable
307
307
{
308
- internal bool IsDirty ;
309
308
// Not to be serialized, used for processing the animation state
310
309
internal bool HasBeenProcessed ;
311
310
internal int StateHash ;
@@ -392,56 +391,41 @@ internal struct AnimationMessage : INetworkSerializable
392
391
// Not to be serialized, used for processing the animation message
393
392
internal bool HasBeenProcessed ;
394
393
395
- // state hash per layer. if non-zero, then Play() this animation, skipping transitions
394
+ // This is preallocated/populated in OnNetworkSpawn for all instances in the event ownership or
395
+ // authority changes. When serializing, IsDirtyCount determines how many AnimationState entries
396
+ // should be serialized from the list. When deserializing the list is created and populated with
397
+ // only the number of AnimationStates received which is dictated by the deserialized IsDirtyCount.
396
398
internal List < AnimationState > AnimationStates ;
397
399
398
- /// <summary>
399
- /// Resets all AnimationStates' IsDirty flag
400
- /// </summary>
401
- internal void ClearDirty ( )
402
- {
403
- if ( AnimationStates == null )
404
- {
405
- return ;
406
- }
407
- for ( int i = 0 ; i < AnimationStates . Count ; i ++ )
408
- {
409
- var animationState = AnimationStates [ i ] ;
410
- animationState . IsDirty = false ;
411
- AnimationStates [ i ] = animationState ;
412
- }
413
- }
400
+ // Used to determine how many AnimationState entries we are sending or receiving
401
+ internal int IsDirtyCount ;
414
402
415
403
public void NetworkSerialize < T > ( BufferSerializer < T > serializer ) where T : IReaderWriter
416
404
{
405
+ var animationState = new AnimationState ( ) ;
417
406
if ( serializer . IsReader )
418
407
{
419
- if ( AnimationStates == null )
420
- {
421
- AnimationStates = new List < AnimationState > ( ) ;
422
- }
423
- else if ( AnimationStates . Count > 0 )
408
+ AnimationStates = new List < AnimationState > ( ) ;
409
+
410
+ serializer . SerializeValue ( ref IsDirtyCount ) ;
411
+ // Since we create a new AnimationMessage when deserializing
412
+ // we need to create new animation states for each incoming
413
+ // AnimationState being updated
414
+ for ( int i = 0 ; i < IsDirtyCount ; i ++ )
424
415
{
425
- AnimationStates . Clear ( ) ;
416
+ animationState = new AnimationState ( ) ;
417
+ serializer . SerializeValue ( ref animationState ) ;
418
+ AnimationStates . Add ( animationState ) ;
426
419
}
427
420
}
428
- var count = AnimationStates . Count ;
429
- serializer . SerializeValue ( ref count ) ;
430
-
431
- var animationState = new AnimationState ( ) ;
432
- for ( int i = 0 ; i < count ; i ++ )
421
+ else
433
422
{
434
- if ( serializer . IsWriter )
423
+ // When writing, only send the counted dirty animation states
424
+ serializer . SerializeValue ( ref IsDirtyCount ) ;
425
+ for ( int i = 0 ; i < IsDirtyCount ; i ++ )
435
426
{
436
- if ( AnimationStates [ i ] . IsDirty )
437
- {
438
- animationState = AnimationStates [ i ] ;
439
- }
440
- }
441
- serializer . SerializeNetworkSerializable ( ref animationState ) ;
442
- if ( serializer . IsReader )
443
- {
444
- AnimationStates . Add ( animationState ) ;
427
+ animationState = AnimationStates [ i ] ;
428
+ serializer . SerializeNetworkSerializable ( ref animationState ) ;
445
429
}
446
430
}
447
431
}
@@ -563,7 +547,17 @@ public override void OnDestroy()
563
547
private List < int > m_ParametersToUpdate ;
564
548
private List < ulong > m_ClientSendList ;
565
549
private ClientRpcParams m_ClientRpcParams ;
566
- private List < AnimationState > m_AnimationMessageStates ;
550
+ private AnimationMessage m_AnimationMessage ;
551
+
552
+ /// <summary>
553
+ /// Used for integration test to validate that the
554
+ /// AnimationMessage.AnimationStates remains the same
555
+ /// size as the layer count.
556
+ /// </summary>
557
+ internal AnimationMessage GetAnimationMessage ( )
558
+ {
559
+ return m_AnimationMessage ;
560
+ }
567
561
568
562
// Only used in Cleanup
569
563
private NetworkManager m_CachedNetworkManager ;
@@ -590,17 +584,19 @@ public override void OnNetworkSpawn()
590
584
m_CachedNetworkManager = NetworkManager ;
591
585
NetworkManager . OnClientConnectedCallback += OnClientConnectedCallback ;
592
586
}
593
-
594
- // !! Note !!
595
- // Do not clear this list. We re-use the AnimationState entries
596
- // initialized below
597
- m_AnimationMessageStates = new List < AnimationState > ( ) ;
587
+ // We initialize the m_AnimationMessage for all instances in the event that
588
+ // ownership or authority changes during runtime.
589
+ m_AnimationMessage = new AnimationMessage ( ) ;
590
+ m_AnimationMessage . AnimationStates = new List < AnimationState > ( ) ;
598
591
599
592
// Store off our current layer weights and create our animation
600
593
// state entries per layer.
601
594
for ( int layer = 0 ; layer < m_Animator . layerCount ; layer ++ )
602
595
{
603
- m_AnimationMessageStates . Add ( new AnimationState ( ) ) ;
596
+ // We create an AnimationState per layer to preallocate the maximum
597
+ // number of possible AnimationState changes we could send in one
598
+ // AnimationMessage.
599
+ m_AnimationMessage . AnimationStates . Add ( new AnimationState ( ) ) ;
604
600
float layerWeightNow = m_Animator . GetLayerWeight ( layer ) ;
605
601
if ( layerWeightNow != m_LayerWeights [ layer ] )
606
602
{
@@ -677,19 +673,19 @@ internal void ServerSynchronizeNewPlayer(ulong playerId)
677
673
}
678
674
SendParametersUpdate ( m_ClientRpcParams ) ;
679
675
680
- var animationMessage = new AnimationMessage
681
- {
682
- // Assign the existing m_AnimationMessageStates list
683
- AnimationStates = m_AnimationMessageStates
684
- } ;
676
+ // Reset the dirty count before synchronizing the newly connected client with all layers
677
+ m_AnimationMessage . IsDirtyCount = 0 ;
685
678
686
679
for ( int layer = 0 ; layer < m_Animator . layerCount ; layer ++ )
687
680
{
688
681
AnimatorStateInfo st = m_Animator . GetCurrentAnimatorStateInfo ( layer ) ;
689
682
var stateHash = st . fullPathHash ;
690
683
var normalizedTime = st . normalizedTime ;
691
684
var isInTransition = m_Animator . IsInTransition ( layer ) ;
692
- var animMsg = m_AnimationMessageStates [ layer ] ;
685
+
686
+ // Grab one of the available AnimationState entries so we can fill it with the current
687
+ // layer's animation state.
688
+ var animationState = m_AnimationMessage . AnimationStates [ layer ] ;
693
689
694
690
// Synchronizing transitions with trigger conditions for late joining clients is now
695
691
// handled by cross fading between the late joining client's current layer's AnimationState
@@ -723,25 +719,23 @@ internal void ServerSynchronizeNewPlayer(ulong playerId)
723
719
var destinationInfo = m_DestinationStateToTransitioninfo [ layer ] [ nextState . shortNameHash ] ;
724
720
stateHash = destinationInfo . OriginatingState ;
725
721
// Set the destination state to cross fade to from the originating state
726
- animMsg . DestinationStateHash = destinationInfo . DestinationState ;
722
+ animationState . DestinationStateHash = destinationInfo . DestinationState ;
727
723
}
728
724
}
729
725
}
730
726
731
- animMsg . Transition = isInTransition ; // The only time this could be set to true
732
- animMsg . StateHash = stateHash ; // When a transition, this is the originating/starting state
733
- animMsg . NormalizedTime = normalizedTime ;
734
- animMsg . Layer = layer ;
735
- animMsg . Weight = m_LayerWeights [ layer ] ;
736
- animMsg . IsDirty = true ;
737
- m_AnimationMessageStates [ layer ] = animMsg ;
738
- }
739
- if ( animationMessage . AnimationStates . Count > 0 )
740
- {
741
- // Server always send via client RPC
742
- SendAnimStateClientRpc ( animationMessage , m_ClientRpcParams ) ;
743
- animationMessage . ClearDirty ( ) ;
727
+ animationState . Transition = isInTransition ; // The only time this could be set to true
728
+ animationState . StateHash = stateHash ; // When a transition, this is the originating/starting state
729
+ animationState . NormalizedTime = normalizedTime ;
730
+ animationState . Layer = layer ;
731
+ animationState . Weight = m_LayerWeights [ layer ] ;
732
+
733
+ // Apply the changes
734
+ m_AnimationMessage . AnimationStates [ layer ] = animationState ;
744
735
}
736
+ // Send all animation states
737
+ m_AnimationMessage . IsDirtyCount = m_Animator . layerCount ;
738
+ SendAnimStateClientRpc ( m_AnimationMessage , m_ClientRpcParams ) ;
745
739
}
746
740
747
741
/// <summary>
@@ -779,13 +773,10 @@ internal void CheckForAnimatorChanges()
779
773
int stateHash ;
780
774
float normalizedTime ;
781
775
782
- var animationMessage = new AnimationMessage
783
- {
784
- // Assign the existing m_AnimationMessageStates list
785
- AnimationStates = m_AnimationMessageStates
786
- } ;
776
+ // Reset the dirty count before checking for AnimationState updates
777
+ m_AnimationMessage . IsDirtyCount = 0 ;
787
778
788
- // This sends updates only if a layer's AnimationState changes
779
+ // This sends updates only if a layer's state has changed
789
780
for ( int layer = 0 ; layer < m_Animator . layerCount ; layer ++ )
790
781
{
791
782
AnimatorStateInfo st = m_Animator . GetCurrentAnimatorStateInfo ( layer ) ;
@@ -797,31 +788,33 @@ internal void CheckForAnimatorChanges()
797
788
continue ;
798
789
}
799
790
800
- var animationState = new AnimationState
801
- {
802
- IsDirty = true ,
803
- Transition = false , // Only used during synchronization
804
- StateHash = stateHash ,
805
- NormalizedTime = normalizedTime ,
806
- Layer = layer ,
807
- Weight = m_LayerWeights [ layer ]
808
- } ;
791
+ // If we made it here, then we need to synchronize this layer's animation state.
792
+ // Get one of the preallocated AnimationState entries and populate it with the
793
+ // current layer's state.
794
+ var animationState = m_AnimationMessage . AnimationStates [ m_AnimationMessage . IsDirtyCount ] ;
795
+
796
+ animationState . Transition = false ; // Only used during synchronization
797
+ animationState . StateHash = stateHash ;
798
+ animationState . NormalizedTime = normalizedTime ;
799
+ animationState . Layer = layer ;
800
+ animationState . Weight = m_LayerWeights [ layer ] ;
809
801
810
- animationMessage . AnimationStates . Add ( animationState ) ;
802
+ // Apply the changes
803
+ m_AnimationMessage . AnimationStates [ m_AnimationMessage . IsDirtyCount ] = animationState ;
804
+ m_AnimationMessage . IsDirtyCount ++ ;
811
805
}
812
806
813
- // Make sure there is something to send
814
- if ( animationMessage . AnimationStates . Count > 0 )
807
+ // Send an AnimationMessage only if there are dirty AnimationStates to send
808
+ if ( m_AnimationMessage . IsDirtyCount > 0 )
815
809
{
816
810
if ( ! IsServer && IsOwner )
817
811
{
818
- SendAnimStateServerRpc ( animationMessage ) ;
812
+ SendAnimStateServerRpc ( m_AnimationMessage ) ;
819
813
}
820
814
else
821
815
{
822
- SendAnimStateClientRpc ( animationMessage ) ;
816
+ SendAnimStateClientRpc ( m_AnimationMessage ) ;
823
817
}
824
- animationMessage . ClearDirty ( ) ;
825
818
}
826
819
}
827
820
0 commit comments