@@ -227,7 +227,7 @@ private void BuildDestinationToTransitionInfoTable()
227227 }
228228
229229 /// <summary>
230- /// Creates the
230+ /// Creates the TransitionStateInfoList table
231231 /// </summary>
232232 private void BuildTransitionStateInfoList ( )
233233 {
@@ -305,7 +305,6 @@ public void OnBeforeSerialize()
305305
306306 internal struct AnimationState : INetworkSerializable
307307 {
308- internal bool IsDirty ;
309308 // Not to be serialized, used for processing the animation state
310309 internal bool HasBeenProcessed ;
311310 internal int StateHash ;
@@ -392,56 +391,41 @@ internal struct AnimationMessage : INetworkSerializable
392391 // Not to be serialized, used for processing the animation message
393392 internal bool HasBeenProcessed ;
394393
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.
396398 internal List < AnimationState > AnimationStates ;
397399
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 ;
414402
415403 public void NetworkSerialize < T > ( BufferSerializer < T > serializer ) where T : IReaderWriter
416404 {
405+ var animationState = new AnimationState ( ) ;
417406 if ( serializer . IsReader )
418407 {
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 ++ )
424415 {
425- AnimationStates . Clear ( ) ;
416+ animationState = new AnimationState ( ) ;
417+ serializer . SerializeValue ( ref animationState ) ;
418+ AnimationStates . Add ( animationState ) ;
426419 }
427420 }
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
433422 {
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 ++ )
435426 {
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 ) ;
445429 }
446430 }
447431 }
@@ -563,7 +547,17 @@ public override void OnDestroy()
563547 private List < int > m_ParametersToUpdate ;
564548 private List < ulong > m_ClientSendList ;
565549 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+ }
567561
568562 // Only used in Cleanup
569563 private NetworkManager m_CachedNetworkManager ;
@@ -590,17 +584,19 @@ public override void OnNetworkSpawn()
590584 m_CachedNetworkManager = NetworkManager ;
591585 NetworkManager . OnClientConnectedCallback += OnClientConnectedCallback ;
592586 }
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 > ( ) ;
598591
599592 // Store off our current layer weights and create our animation
600593 // state entries per layer.
601594 for ( int layer = 0 ; layer < m_Animator . layerCount ; layer ++ )
602595 {
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 ( ) ) ;
604600 float layerWeightNow = m_Animator . GetLayerWeight ( layer ) ;
605601 if ( layerWeightNow != m_LayerWeights [ layer ] )
606602 {
@@ -677,19 +673,19 @@ internal void ServerSynchronizeNewPlayer(ulong playerId)
677673 }
678674 SendParametersUpdate ( m_ClientRpcParams ) ;
679675
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 ;
685678
686679 for ( int layer = 0 ; layer < m_Animator . layerCount ; layer ++ )
687680 {
688681 AnimatorStateInfo st = m_Animator . GetCurrentAnimatorStateInfo ( layer ) ;
689682 var stateHash = st . fullPathHash ;
690683 var normalizedTime = st . normalizedTime ;
691684 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 ] ;
693689
694690 // Synchronizing transitions with trigger conditions for late joining clients is now
695691 // handled by cross fading between the late joining client's current layer's AnimationState
@@ -723,25 +719,23 @@ internal void ServerSynchronizeNewPlayer(ulong playerId)
723719 var destinationInfo = m_DestinationStateToTransitioninfo [ layer ] [ nextState . shortNameHash ] ;
724720 stateHash = destinationInfo . OriginatingState ;
725721 // Set the destination state to cross fade to from the originating state
726- animMsg . DestinationStateHash = destinationInfo . DestinationState ;
722+ animationState . DestinationStateHash = destinationInfo . DestinationState ;
727723 }
728724 }
729725 }
730726
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 ;
744735 }
736+ // Send all animation states
737+ m_AnimationMessage . IsDirtyCount = m_Animator . layerCount ;
738+ SendAnimStateClientRpc ( m_AnimationMessage , m_ClientRpcParams ) ;
745739 }
746740
747741 /// <summary>
@@ -779,13 +773,10 @@ internal void CheckForAnimatorChanges()
779773 int stateHash ;
780774 float normalizedTime ;
781775
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 ;
787778
788- // This sends updates only if a layer's AnimationState changes
779+ // This sends updates only if a layer's state has changed
789780 for ( int layer = 0 ; layer < m_Animator . layerCount ; layer ++ )
790781 {
791782 AnimatorStateInfo st = m_Animator . GetCurrentAnimatorStateInfo ( layer ) ;
@@ -797,31 +788,33 @@ internal void CheckForAnimatorChanges()
797788 continue ;
798789 }
799790
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 ] ;
809801
810- animationMessage . AnimationStates . Add ( animationState ) ;
802+ // Apply the changes
803+ m_AnimationMessage . AnimationStates [ m_AnimationMessage . IsDirtyCount ] = animationState ;
804+ m_AnimationMessage . IsDirtyCount ++ ;
811805 }
812806
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 )
815809 {
816810 if ( ! IsServer && IsOwner )
817811 {
818- SendAnimStateServerRpc ( animationMessage ) ;
812+ SendAnimStateServerRpc ( m_AnimationMessage ) ;
819813 }
820814 else
821815 {
822- SendAnimStateClientRpc ( animationMessage ) ;
816+ SendAnimStateClientRpc ( m_AnimationMessage ) ;
823817 }
824- animationMessage . ClearDirty ( ) ;
825818 }
826819 }
827820
0 commit comments