-
Notifications
You must be signed in to change notification settings - Fork 461
fix: NetworkAnimator does not work using the server authoritative model [MTT-3745] #2003
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
bd952c7
c8363ed
1192f0f
1817629
b8d224c
2fde234
7072c35
d2932fe
4135bd6
8667ac6
0430833
f5f5424
ac367a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,11 +58,10 @@ public void NetworkUpdate(NetworkUpdateStage updateStage) | |
| m_ProcessParameterUpdates.Clear(); | ||
|
|
||
| // Only owners check for Animator changes | ||
| if (m_NetworkAnimator.IsOwner) | ||
| if (m_NetworkAnimator.IsOwner && !m_NetworkAnimator.IsServerAuthoritative || m_NetworkAnimator.IsServerAuthoritative && m_NetworkAnimator.NetworkManager.IsServer) | ||
| { | ||
| m_NetworkAnimator.CheckForAnimatorChanges(); | ||
| } | ||
|
|
||
| break; | ||
| } | ||
| } | ||
|
|
@@ -209,6 +208,42 @@ public Animator Animator | |
| } | ||
| } | ||
|
|
||
| [Tooltip("When enabled, the NetworkAnimator will operate in server authoritative mode.")] | ||
| [SerializeField] | ||
| private bool m_IsServerAuthoritative; | ||
|
|
||
| /// <summary> | ||
| /// Server-Side Only: | ||
| /// Can be used to switch between server and owner authoritative modes during runtime. | ||
| /// Note: Only when the associated NetworkObject is spawned. | ||
| /// </summary> | ||
| public bool IsServerAuthoritative | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to keep this API similar to |
||
| { | ||
| get | ||
| { | ||
| return m_IsServerAuthoritative; | ||
| } | ||
| set | ||
| { | ||
| if (!IsSpawned) | ||
| { | ||
| m_IsServerAuthoritative = value; | ||
| } | ||
| else if (IsSpawned && IsServer) | ||
| { | ||
| m_IsServerAuthoritative = value; | ||
| m_ServerAuthoritativeMode.Value = value; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private NetworkVariable<bool> m_ServerAuthoritativeMode = new NetworkVariable<bool>(); | ||
|
|
||
| private void OnServerAuthoritativeModeChanged(bool previous, bool next) | ||
| { | ||
| m_IsServerAuthoritative = next; | ||
| } | ||
|
|
||
| // Animators only support up to 32 params | ||
| private const int k_MaxAnimationParams = 32; | ||
|
|
||
|
|
@@ -276,13 +311,10 @@ public override void OnDestroy() | |
| base.OnDestroy(); | ||
| } | ||
|
|
||
|
|
||
| private List<int> m_ParametersToUpdate; | ||
|
|
||
| private List<ulong> m_ClientSendList; | ||
| private ClientRpcParams m_ClientRpcParams; | ||
|
|
||
|
|
||
| public override void OnNetworkSpawn() | ||
| { | ||
| if (IsOwner || IsServer) | ||
|
|
@@ -295,6 +327,7 @@ public override void OnNetworkSpawn() | |
| if (IsServer) | ||
| { | ||
| NetworkManager.OnClientConnectedCallback += OnClientConnectedCallback; | ||
| m_ServerAuthoritativeMode.Value = m_IsServerAuthoritative; | ||
| } | ||
|
|
||
| // Store off our current layer weights | ||
|
|
@@ -316,6 +349,11 @@ public override void OnNetworkSpawn() | |
| } | ||
| } | ||
|
|
||
| if (!IsServer) | ||
| { | ||
| m_ServerAuthoritativeMode.OnValueChanged = OnServerAuthoritativeModeChanged; | ||
| } | ||
|
|
||
| var parameters = m_Animator.parameters; | ||
| m_CachedAnimatorParameters = new NativeArray<AnimatorParamCache>(parameters.Length, Allocator.Persistent); | ||
| m_ParametersToUpdate = new List<int>(parameters.Length); | ||
|
|
@@ -439,7 +477,7 @@ private void OnClientConnectedCallback(ulong playerId) | |
|
|
||
| internal void CheckForAnimatorChanges() | ||
| { | ||
| if (!IsOwner) | ||
| if (!IsOwner && !IsServerAuthoritative || m_IsServerAuthoritative && !IsServer) | ||
| { | ||
| return; | ||
| } | ||
|
|
@@ -753,19 +791,26 @@ private unsafe void UpdateAnimationState(AnimationMessage animationState) | |
| [ServerRpc] | ||
| private unsafe void SendParametersUpdateServerRpc(ParametersUpdateMessage parametersUpdate, ServerRpcParams serverRpcParams = default) | ||
| { | ||
| if (serverRpcParams.Receive.SenderClientId != OwnerClientId) | ||
| if (IsServerAuthoritative) | ||
| { | ||
| return; | ||
| m_NetworkAnimatorStateChangeHandler.SendParameterUpdate(parametersUpdate); | ||
| } | ||
| UpdateParameters(parametersUpdate); | ||
| if (NetworkManager.ConnectedClientsIds.Count - 2 > 0) | ||
| else | ||
| { | ||
| m_ClientSendList.Clear(); | ||
| m_ClientSendList.AddRange(NetworkManager.ConnectedClientsIds); | ||
| m_ClientSendList.Remove(serverRpcParams.Receive.SenderClientId); | ||
| m_ClientSendList.Remove(NetworkManager.ServerClientId); | ||
| m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; | ||
| m_NetworkAnimatorStateChangeHandler.SendParameterUpdate(parametersUpdate, m_ClientRpcParams); | ||
| if (serverRpcParams.Receive.SenderClientId != OwnerClientId) | ||
| { | ||
| return; | ||
| } | ||
| UpdateParameters(parametersUpdate); | ||
| if (NetworkManager.ConnectedClientsIds.Count - 2 > 0) | ||
| { | ||
| m_ClientSendList.Clear(); | ||
| m_ClientSendList.AddRange(NetworkManager.ConnectedClientsIds); | ||
| m_ClientSendList.Remove(serverRpcParams.Receive.SenderClientId); | ||
| m_ClientSendList.Remove(NetworkManager.ServerClientId); | ||
| m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; | ||
| m_NetworkAnimatorStateChangeHandler.SendParameterUpdate(parametersUpdate, m_ClientRpcParams); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -775,7 +820,7 @@ private unsafe void SendParametersUpdateServerRpc(ParametersUpdateMessage parame | |
| [ClientRpc] | ||
| internal unsafe void SendParametersUpdateClientRpc(ParametersUpdateMessage parametersUpdate, ClientRpcParams clientRpcParams = default) | ||
| { | ||
| if (!IsOwner) | ||
| if (!IsServerAuthoritative && !IsOwner || IsServerAuthoritative) | ||
| { | ||
| m_NetworkAnimatorStateChangeHandler.ProcessParameterUpdate(parametersUpdate); | ||
| } | ||
|
|
@@ -788,20 +833,26 @@ internal unsafe void SendParametersUpdateClientRpc(ParametersUpdateMessage param | |
| [ServerRpc] | ||
| private unsafe void SendAnimStateServerRpc(AnimationMessage animSnapshot, ServerRpcParams serverRpcParams = default) | ||
| { | ||
| if (serverRpcParams.Receive.SenderClientId != OwnerClientId) | ||
| if (IsServerAuthoritative) | ||
| { | ||
| return; | ||
| m_NetworkAnimatorStateChangeHandler.SendAnimationUpdate(animSnapshot); | ||
| } | ||
|
|
||
| UpdateAnimationState(animSnapshot); | ||
| if (NetworkManager.ConnectedClientsIds.Count - 2 > 0) | ||
| else | ||
| { | ||
| m_ClientSendList.Clear(); | ||
| m_ClientSendList.AddRange(NetworkManager.ConnectedClientsIds); | ||
| m_ClientSendList.Remove(serverRpcParams.Receive.SenderClientId); | ||
| m_ClientSendList.Remove(NetworkManager.ServerClientId); | ||
| m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; | ||
| m_NetworkAnimatorStateChangeHandler.SendAnimationUpdate(animSnapshot, m_ClientRpcParams); | ||
| if (serverRpcParams.Receive.SenderClientId != OwnerClientId) | ||
| { | ||
| return; | ||
| } | ||
| UpdateAnimationState(animSnapshot); | ||
| if (NetworkManager.ConnectedClientsIds.Count - 2 > 0) | ||
| { | ||
| m_ClientSendList.Clear(); | ||
| m_ClientSendList.AddRange(NetworkManager.ConnectedClientsIds); | ||
| m_ClientSendList.Remove(serverRpcParams.Receive.SenderClientId); | ||
| m_ClientSendList.Remove(NetworkManager.ServerClientId); | ||
| m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; | ||
| m_NetworkAnimatorStateChangeHandler.SendAnimationUpdate(animSnapshot, m_ClientRpcParams); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -811,7 +862,7 @@ private unsafe void SendAnimStateServerRpc(AnimationMessage animSnapshot, Server | |
| [ClientRpc] | ||
| private unsafe void SendAnimStateClientRpc(AnimationMessage animSnapshot, ClientRpcParams clientRpcParams = default) | ||
| { | ||
| if (!IsOwner) | ||
| if (!IsServerAuthoritative && !IsOwner || IsServerAuthoritative) | ||
| { | ||
| UpdateAnimationState(animSnapshot); | ||
| } | ||
|
|
@@ -824,23 +875,30 @@ private unsafe void SendAnimStateClientRpc(AnimationMessage animSnapshot, Client | |
| [ServerRpc] | ||
| private void SendAnimTriggerServerRpc(AnimationTriggerMessage animationTriggerMessage, ServerRpcParams serverRpcParams = default) | ||
| { | ||
| if (serverRpcParams.Receive.SenderClientId != OwnerClientId) | ||
| if (IsServerAuthoritative) | ||
| { | ||
| return; | ||
| m_NetworkAnimatorStateChangeHandler.SendTriggerUpdate(animationTriggerMessage); | ||
| } | ||
|
|
||
| // trigger the animation locally on the server... | ||
| m_Animator.SetBool(animationTriggerMessage.Hash, animationTriggerMessage.IsTriggerSet); | ||
|
|
||
| if (NetworkManager.ConnectedClientsIds.Count - 2 > 0) | ||
| else | ||
| { | ||
| m_ClientSendList.Clear(); | ||
| m_ClientSendList.AddRange(NetworkManager.ConnectedClientsIds); | ||
| m_ClientSendList.Remove(serverRpcParams.Receive.SenderClientId); | ||
| m_ClientSendList.Remove(NetworkManager.ServerClientId); | ||
| m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; | ||
| m_NetworkAnimatorStateChangeHandler.SendTriggerUpdate(animationTriggerMessage, m_ClientRpcParams); | ||
| if (serverRpcParams.Receive.SenderClientId != OwnerClientId) | ||
| { | ||
| return; | ||
| } | ||
| // trigger the animation locally on the server... | ||
| m_Animator.SetBool(animationTriggerMessage.Hash, animationTriggerMessage.IsTriggerSet); | ||
|
|
||
| if (NetworkManager.ConnectedClientsIds.Count - 2 > 0) | ||
| { | ||
| m_ClientSendList.Clear(); | ||
| m_ClientSendList.AddRange(NetworkManager.ConnectedClientsIds); | ||
| m_ClientSendList.Remove(serverRpcParams.Receive.SenderClientId); | ||
| m_ClientSendList.Remove(NetworkManager.ServerClientId); | ||
| m_ClientRpcParams.Send.TargetClientIds = m_ClientSendList; | ||
| m_NetworkAnimatorStateChangeHandler.SendTriggerUpdate(animationTriggerMessage, m_ClientRpcParams); | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -852,7 +910,7 @@ private void SendAnimTriggerServerRpc(AnimationTriggerMessage animationTriggerMe | |
| [ClientRpc] | ||
| internal void SendAnimTriggerClientRpc(AnimationTriggerMessage animationTriggerMessage, ClientRpcParams clientRpcParams = default) | ||
| { | ||
| if (!IsOwner) | ||
| if (!IsServerAuthoritative && !IsOwner || IsServerAuthoritative) | ||
| { | ||
| m_Animator.SetBool(animationTriggerMessage.Hash, animationTriggerMessage.IsTriggerSet); | ||
| } | ||
|
|
@@ -872,7 +930,7 @@ public void SetTrigger(string triggerName) | |
| /// <param name="reset">If true, resets the trigger</param> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. needs update, |
||
| public void SetTrigger(int hash, bool setTrigger = true) | ||
| { | ||
| if (IsOwner) | ||
| if (IsOwner && !IsServerAuthoritative || IsServer && IsServerAuthoritative) | ||
| { | ||
| var animTriggerMessage = new AnimationTriggerMessage() { Hash = hash, IsTriggerSet = setTrigger }; | ||
| if (IsServer) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be set to true by default as to not create a breaking change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. If we want to make server authoritative the default that is easy enough to do.
Do we want users to default to the server authoritative model or client authoritative model?
(both approaches have pro's and con's)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for making server-auth the default to not change the current default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NetworkAnimator follows the same pattern as NetworkTransform to make it client/owner authoritative.