Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
2c9715f
fix
NoelStephensUnity May 6, 2022
5eb6691
test and style
NoelStephensUnity May 9, 2022
c17bf81
style
NoelStephensUnity May 9, 2022
881f701
style
NoelStephensUnity May 9, 2022
b198c36
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 9, 2022
3c1158f
update and test
NoelStephensUnity May 9, 2022
586b8a6
style
NoelStephensUnity May 9, 2022
b645a5a
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 9, 2022
395fe2d
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 10, 2022
c969dd4
update
NoelStephensUnity May 10, 2022
7aee925
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 10, 2022
e7ccb41
update and fix
NoelStephensUnity May 10, 2022
0de2cb6
update and fix
NoelStephensUnity May 10, 2022
15b3e92
update
NoelStephensUnity May 10, 2022
26a5424
fix
NoelStephensUnity May 11, 2022
ffe55fc
fix
NoelStephensUnity May 11, 2022
db9a051
test
NoelStephensUnity May 11, 2022
f28ba3f
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 11, 2022
51fea68
test and style
NoelStephensUnity May 11, 2022
73adf63
Test and Style
NoelStephensUnity May 11, 2022
3e867cf
Update
NoelStephensUnity May 12, 2022
04b247a
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 12, 2022
19e6605
fix
NoelStephensUnity May 13, 2022
00cf503
wip
NoelStephensUnity May 14, 2022
808fb7e
fix
NoelStephensUnity May 15, 2022
b0cbc07
style
NoelStephensUnity May 15, 2022
faadd4d
style
NoelStephensUnity May 15, 2022
f96e012
update
NoelStephensUnity May 17, 2022
b01fe0e
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 17, 2022
3427152
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 19, 2022
5df40ee
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 19, 2022
d7a6402
update
NoelStephensUnity May 23, 2022
9337020
Test
NoelStephensUnity May 23, 2022
080301f
update - optimize
NoelStephensUnity May 23, 2022
01b7e76
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 23, 2022
85d359b
style
NoelStephensUnity May 23, 2022
6eb0b1c
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 23, 2022
28138a0
update
NoelStephensUnity May 25, 2022
d65f045
update
NoelStephensUnity May 25, 2022
1099dc3
Merge branch 'develop' into fix/network-animator-single-layer
NoelStephensUnity May 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 162 additions & 22 deletions com.unity.netcode.gameobjects/Components/NetworkAnimator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#if COM_UNITY_MODULES_ANIMATION
using System.Collections.Generic;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
Expand Down Expand Up @@ -43,6 +44,8 @@ public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReade
}
}

[Tooltip("When true the owner drives the animations and when false the server drives the animations.")]
public bool OwnerAuthoritative;
[SerializeField] private Animator m_Animator;

public Animator Animator
Expand Down Expand Up @@ -70,8 +73,22 @@ private unsafe struct AnimatorParamCache
internal fixed byte Value[4]; // this is a max size of 4 bytes
}

/// <summary>
/// Used to track parameter state change in order to update the changed
/// parameters when the animator's layer has not changed
/// </summary>
private class ParameterState
{
public AnimatorControllerParameterType AnimatorControllerParameterType;
public bool CurrentStateBool;
public int CurrentStateInt;
public float CurrentStateFloat;
}

// 128 bytes per Animator
private FastBufferWriter m_ParameterWriter = new FastBufferWriter(k_MaxAnimationParams * sizeof(float), Allocator.Persistent);


private NativeArray<AnimatorParamCache> m_CachedAnimatorParameters;

// We cache these values because UnsafeUtility.EnumToInt uses direct IL that allows a non-boxing conversion
Expand Down Expand Up @@ -101,7 +118,7 @@ public override void OnDestroy()

public override void OnNetworkSpawn()
{
if (IsServer)
if (OwnerAuthoritative && IsOwner || IsServer)
{
m_SendMessagesAllowed = true;
int layers = m_Animator.layerCount;
Expand Down Expand Up @@ -138,6 +155,7 @@ public override void OnNetworkSpawn()
case AnimatorControllerParameterType.Float:
var value = m_Animator.GetFloat(cacheParam.Hash);
UnsafeUtility.WriteArrayElement(cacheParam.Value, 0, value);

break;
Comment thread
NoelStephensUnity marked this conversation as resolved.
case AnimatorControllerParameterType.Int:
var valueInt = m_Animator.GetInteger(cacheParam.Hash);
Expand All @@ -147,6 +165,7 @@ public override void OnNetworkSpawn()
case AnimatorControllerParameterType.Bool:
var valueBool = m_Animator.GetBool(cacheParam.Hash);
UnsafeUtility.WriteArrayElement(cacheParam.Value, 0, valueBool);

break;
case AnimatorControllerParameterType.Trigger:
default:
Expand Down Expand Up @@ -193,11 +212,19 @@ private void FixedUpdate()
WriteParameters(m_ParameterWriter);
animMsg.Parameters = m_ParameterWriter.ToArray();

SendAnimStateClientRpc(animMsg);

if (!IsServer && OwnerAuthoritative)
{
SendAnimStateServerRpc(animMsg);
}
else
{
SendAnimStateClientRpc(animMsg);
}
}
}

private bool CheckAnimStateChanged(out int stateHash, out float normalizedTime, int layer)
unsafe private bool CheckAnimStateChanged(out int stateHash, out float normalizedTime, int layer)
{
bool shouldUpdate = false;
stateHash = 0;
Expand Down Expand Up @@ -239,6 +266,55 @@ private bool CheckAnimStateChanged(out int stateHash, out float normalizedTime,
}
}

// Whether the layer has changed or not, we always check to see if parameters have changed and send updates if they have.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for a future PR we could create a full index of what changed and then send only what has changed.
For this PR I kept it relatively simple since updating meant it would send all values anyway.

for (int i = 0; i < m_CachedAnimatorParameters.Length; i++)
{
ref var cacheValue = ref UnsafeUtility.ArrayElementAsRef<AnimatorParamCache>(m_CachedAnimatorParameters.GetUnsafePtr(), i);
var hash = cacheValue.Hash;
if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterInt)
{
var valueInt = m_Animator.GetInteger(hash);
var currentValue = valueInt;
fixed (void* value = cacheValue.Value)
{
currentValue = UnsafeUtility.ReadArrayElement<int>(value, 0);
}
if (currentValue != valueInt)
{
shouldUpdate = true;
break;
}
}
else if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterBool)
{
var valueBool = m_Animator.GetBool(hash);
var currentValue = valueBool;
fixed (void* value = cacheValue.Value)
{
currentValue = UnsafeUtility.ReadArrayElement<bool>(value, 0);
}
if (currentValue != valueBool)
{
shouldUpdate = true;
break;
}
}
else if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterFloat)
{
var valueFloat = m_Animator.GetFloat(hash);
var currentValue = valueFloat;
fixed (void* value = cacheValue.Value)
{
currentValue = UnsafeUtility.ReadArrayElement<float>(value, 0);
}
if (currentValue != valueFloat)
{
shouldUpdate = true;
break;
}
}
}

return shouldUpdate;
}

Expand Down Expand Up @@ -278,7 +354,6 @@ private unsafe void WriteParameters(FastBufferWriter writer)
var valueFloat = m_Animator.GetFloat(hash);
fixed (void* value = cacheValue.Value)
{

UnsafeUtility.WriteArrayElement(value, 0, valueFloat);
writer.WriteValueSafe(valueFloat);
}
Expand All @@ -295,8 +370,8 @@ private unsafe void ReadParameters(FastBufferReader reader)

if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterInt)
{
ByteUnpacker.ReadValuePacked(reader, out int newValue);
m_Animator.SetInteger(hash, newValue);
ByteUnpacker.ReadValuePacked(reader, out uint newValue);
m_Animator.SetInteger(hash, (int)newValue);
fixed (void* value = cacheValue.Value)
{
UnsafeUtility.WriteArrayElement(value, 0, newValue);
Expand All @@ -323,14 +398,7 @@ private unsafe void ReadParameters(FastBufferReader reader)
}
}

/// <summary>
/// Internally-called RPC client receiving function to update some animation parameters on a client when
/// the server wants to update them
/// </summary>
/// <param name="animSnapshot">the payload containing the parameters to apply</param>
/// <param name="clientRpcParams">unused</param>
[ClientRpc]
private unsafe void SendAnimStateClientRpc(AnimationMessage animSnapshot, ClientRpcParams clientRpcParams = default)
private unsafe void UpdateAnimationState(AnimationMessage animSnapshot)
{
if (animSnapshot.StateHash != 0)
{
Expand All @@ -349,6 +417,36 @@ private unsafe void SendAnimStateClientRpc(AnimationMessage animSnapshot, Client
}
}

[ServerRpc(RequireOwnership = false)]
private unsafe void SendAnimStateServerRpc(AnimationMessage animSnapshot, ServerRpcParams serverRpcParams = default)
{
if (OwnerAuthoritative && OwnerClientId == serverRpcParams.Receive.SenderClientId)
{
UpdateAnimationState(animSnapshot);
var clientRpcParams = new ClientRpcParams();
clientRpcParams.Send = new ClientRpcSendParams();
var clientIds = new List<ulong>(NetworkManager.ConnectedClientsIds);
clientIds.Remove(serverRpcParams.Receive.SenderClientId);
clientRpcParams.Send.TargetClientIds = clientIds;
SendAnimStateClientRpc(animSnapshot, clientRpcParams);
}
}

/// <summary>
/// Internally-called RPC client receiving function to update some animation parameters on a client when
/// the server wants to update them
/// </summary>
/// <param name="animSnapshot">the payload containing the parameters to apply</param>
/// <param name="clientRpcParams">unused</param>
[ClientRpc]
private unsafe void SendAnimStateClientRpc(AnimationMessage animSnapshot, ClientRpcParams clientRpcParams = default)
{
if ((!IsOwner && OwnerAuthoritative) || !OwnerAuthoritative)
{
UpdateAnimationState(animSnapshot);
}
}

/// <summary>
/// Internally-called RPC client receiving function to update a trigger when the server wants to forward
/// a trigger for a client to play / reset
Expand All @@ -358,13 +456,38 @@ private unsafe void SendAnimStateClientRpc(AnimationMessage animSnapshot, Client
[ClientRpc]
private void SendAnimTriggerClientRpc(AnimationTriggerMessage animSnapshot, ClientRpcParams clientRpcParams = default)
{
if (animSnapshot.Reset)
if ((!IsOwner && OwnerAuthoritative) || !OwnerAuthoritative)
{
m_Animator.ResetTrigger(animSnapshot.Hash);
if (animSnapshot.Reset)
{
m_Animator.ResetTrigger(animSnapshot.Hash);
}
else
{
m_Animator.SetTrigger(animSnapshot.Hash);
}
}
else
}

[ServerRpc(RequireOwnership = false)]
private void SendAnimTriggerServerRpc(AnimationTriggerMessage animSnapshot, ServerRpcParams serverRpcParams = default)
{
if (OwnerAuthoritative && OwnerClientId == serverRpcParams.Receive.SenderClientId)
{
m_Animator.SetTrigger(animSnapshot.Hash);
if (animSnapshot.Reset)
{
m_Animator.ResetTrigger(animSnapshot.Hash);
}
else
{
m_Animator.SetTrigger(animSnapshot.Hash);
}
var clientRpcParams = new ClientRpcParams();
clientRpcParams.Send = new ClientRpcSendParams();
var clientIds = new List<ulong>(NetworkManager.ConnectedClientsIds);
clientIds.Remove(serverRpcParams.Receive.SenderClientId);
clientRpcParams.Send.TargetClientIds = clientIds;
SendAnimTriggerClientRpc(animSnapshot, clientRpcParams);
}
}

Expand All @@ -390,7 +513,7 @@ public void SetTrigger(int hash, bool reset = false)
animMsg.Hash = hash;
animMsg.Reset = reset;

if (IsServer)
if (IsServer && !OwnerAuthoritative || OwnerAuthoritative && IsOwner)
{
// trigger the animation locally on the server...
if (reset)
Expand All @@ -402,12 +525,28 @@ public void SetTrigger(int hash, bool reset = false)
m_Animator.SetTrigger(hash);
}

// ...then tell all the clients to do the same
SendAnimTriggerClientRpc(animMsg);
// Owner authoritative sends the update to the server
// the server then updates the remaining clients with the changes
if (OwnerAuthoritative && IsOwner && !IsServer)
{
SendAnimTriggerServerRpc(animMsg);
}
else
{
// Server authoritative, the server updates all of the clients
SendAnimTriggerClientRpc(animMsg);
}
}
else
{
Debug.LogWarning("Trying to call NetworkAnimator.SetTrigger on a client...ignoring");
if (!IsServer && !OwnerAuthoritative)
{
Debug.LogWarning("Trying to call NetworkAnimator.SetTrigger on a client when in server authoritative mode ...ignoring");
}
else if (OwnerAuthoritative && !IsOwner)
{
Debug.LogWarning("Trying to call NetworkAnimator.SetTrigger on a non-owner when in owner authoritative mode...ignoring");
}
}
}

Expand All @@ -427,5 +566,6 @@ public void ResetTrigger(int hash)
SetTrigger(hash, true);
}
}

}
#endif // COM_UNITY_MODULES_ANIMATION
Loading