123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- using System.Linq;
- using UnityEngine;
- using UnityEngine.Serialization;
- namespace Mirror
- {
-
-
-
-
-
-
-
-
-
- [AddComponentMenu("Network/NetworkAnimator")]
- [RequireComponent(typeof(NetworkIdentity))]
- [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-animator")]
- public class NetworkAnimator : NetworkBehaviour
- {
- [Header("Authority")]
- [Tooltip("Set to true if animations come from owner client, set to false if animations always come from server")]
- public bool clientAuthority;
-
-
-
- [FormerlySerializedAs("m_Animator")]
- [Header("Animator")]
- [Tooltip("Animator that will have parameters synchronized")]
- public Animator animator;
-
-
-
- [SyncVar(hook = nameof(OnAnimatorSpeedChanged))]
- float animatorSpeed;
- float previousSpeed;
-
- int[] lastIntParameters;
- float[] lastFloatParameters;
- bool[] lastBoolParameters;
- AnimatorControllerParameter[] parameters;
-
- int[] animationHash;
- int[] transitionHash;
- float[] layerWeight;
- double nextSendTime;
- bool SendMessagesAllowed
- {
- get
- {
- if (isServer)
- {
- if (!clientAuthority)
- return true;
-
-
-
-
-
- if (netIdentity != null && netIdentity.connectionToClient == null)
- return true;
- }
- return (hasAuthority && clientAuthority);
- }
- }
- void Awake()
- {
-
-
- parameters = animator.parameters
- .Where(par => !animator.IsParameterControlledByCurve(par.nameHash))
- .ToArray();
- lastIntParameters = new int[parameters.Length];
- lastFloatParameters = new float[parameters.Length];
- lastBoolParameters = new bool[parameters.Length];
- animationHash = new int[animator.layerCount];
- transitionHash = new int[animator.layerCount];
- layerWeight = new float[animator.layerCount];
- }
- void FixedUpdate()
- {
- if (!SendMessagesAllowed)
- return;
- if (!animator.enabled)
- return;
- CheckSendRate();
- for (int i = 0; i < animator.layerCount; i++)
- {
- int stateHash;
- float normalizedTime;
- if (!CheckAnimStateChanged(out stateHash, out normalizedTime, i))
- {
- continue;
- }
- using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
- {
- WriteParameters(writer);
- SendAnimationMessage(stateHash, normalizedTime, i, layerWeight[i], writer.ToArray());
- }
- }
- CheckSpeed();
- }
- void CheckSpeed()
- {
- float newSpeed = animator.speed;
- if (Mathf.Abs(previousSpeed - newSpeed) > 0.001f)
- {
- previousSpeed = newSpeed;
- if (isServer)
- {
- animatorSpeed = newSpeed;
- }
- else if (isClient)
- {
- CmdSetAnimatorSpeed(newSpeed);
- }
- }
- }
- void OnAnimatorSpeedChanged(float _, float value)
- {
-
-
- if (isServer || (hasAuthority && clientAuthority))
- return;
- animator.speed = value;
- }
- bool CheckAnimStateChanged(out int stateHash, out float normalizedTime, int layerId)
- {
- bool change = false;
- stateHash = 0;
- normalizedTime = 0;
- float lw = animator.GetLayerWeight(layerId);
- if (Mathf.Abs(lw - layerWeight[layerId]) > 0.001f)
- {
- layerWeight[layerId] = lw;
- change = true;
- }
- if (animator.IsInTransition(layerId))
- {
- AnimatorTransitionInfo tt = animator.GetAnimatorTransitionInfo(layerId);
- if (tt.fullPathHash != transitionHash[layerId])
- {
-
- transitionHash[layerId] = tt.fullPathHash;
- animationHash[layerId] = 0;
- return true;
- }
- return change;
- }
- AnimatorStateInfo st = animator.GetCurrentAnimatorStateInfo(layerId);
- if (st.fullPathHash != animationHash[layerId])
- {
-
- if (animationHash[layerId] != 0)
- {
-
- stateHash = st.fullPathHash;
- normalizedTime = st.normalizedTime;
- }
- transitionHash[layerId] = 0;
- animationHash[layerId] = st.fullPathHash;
- return true;
- }
- return change;
- }
- void CheckSendRate()
- {
- double now = NetworkTime.localTime;
- if (SendMessagesAllowed && syncInterval >= 0 && now > nextSendTime)
- {
- nextSendTime = now + syncInterval;
- using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
- {
- if (WriteParameters(writer))
- SendAnimationParametersMessage(writer.ToArray());
- }
- }
- }
- void SendAnimationMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters)
- {
- if (isServer)
- {
- RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, weight, parameters);
- }
- else if (isClient)
- {
- CmdOnAnimationServerMessage(stateHash, normalizedTime, layerId, weight, parameters);
- }
- }
- void SendAnimationParametersMessage(byte[] parameters)
- {
- if (isServer)
- {
- RpcOnAnimationParametersClientMessage(parameters);
- }
- else if (isClient)
- {
- CmdOnAnimationParametersServerMessage(parameters);
- }
- }
- void HandleAnimMsg(int stateHash, float normalizedTime, int layerId, float weight, NetworkReader reader)
- {
- if (hasAuthority && clientAuthority)
- return;
-
-
-
- if (stateHash != 0 && animator.enabled)
- {
- animator.Play(stateHash, layerId, normalizedTime);
- }
- animator.SetLayerWeight(layerId, weight);
- ReadParameters(reader);
- }
- void HandleAnimParamsMsg(NetworkReader reader)
- {
- if (hasAuthority && clientAuthority)
- return;
- ReadParameters(reader);
- }
- void HandleAnimTriggerMsg(int hash)
- {
- if (animator.enabled)
- animator.SetTrigger(hash);
- }
- void HandleAnimResetTriggerMsg(int hash)
- {
- if (animator.enabled)
- animator.ResetTrigger(hash);
- }
- ulong NextDirtyBits()
- {
- ulong dirtyBits = 0;
- for (int i = 0; i < parameters.Length; i++)
- {
- AnimatorControllerParameter par = parameters[i];
- bool changed = false;
- if (par.type == AnimatorControllerParameterType.Int)
- {
- int newIntValue = animator.GetInteger(par.nameHash);
- changed = newIntValue != lastIntParameters[i];
- if (changed)
- lastIntParameters[i] = newIntValue;
- }
- else if (par.type == AnimatorControllerParameterType.Float)
- {
- float newFloatValue = animator.GetFloat(par.nameHash);
- changed = Mathf.Abs(newFloatValue - lastFloatParameters[i]) > 0.001f;
-
- if (changed)
- lastFloatParameters[i] = newFloatValue;
- }
- else if (par.type == AnimatorControllerParameterType.Bool)
- {
- bool newBoolValue = animator.GetBool(par.nameHash);
- changed = newBoolValue != lastBoolParameters[i];
- if (changed)
- lastBoolParameters[i] = newBoolValue;
- }
- if (changed)
- {
- dirtyBits |= 1ul << i;
- }
- }
- return dirtyBits;
- }
- bool WriteParameters(NetworkWriter writer, bool forceAll = false)
- {
- ulong dirtyBits = forceAll ? (~0ul) : NextDirtyBits();
- writer.WriteULong(dirtyBits);
- for (int i = 0; i < parameters.Length; i++)
- {
- if ((dirtyBits & (1ul << i)) == 0)
- continue;
- AnimatorControllerParameter par = parameters[i];
- if (par.type == AnimatorControllerParameterType.Int)
- {
- int newIntValue = animator.GetInteger(par.nameHash);
- writer.WriteInt(newIntValue);
- }
- else if (par.type == AnimatorControllerParameterType.Float)
- {
- float newFloatValue = animator.GetFloat(par.nameHash);
- writer.WriteFloat(newFloatValue);
- }
- else if (par.type == AnimatorControllerParameterType.Bool)
- {
- bool newBoolValue = animator.GetBool(par.nameHash);
- writer.WriteBool(newBoolValue);
- }
- }
- return dirtyBits != 0;
- }
- void ReadParameters(NetworkReader reader)
- {
- bool animatorEnabled = animator.enabled;
-
- ulong dirtyBits = reader.ReadULong();
- for (int i = 0; i < parameters.Length; i++)
- {
- if ((dirtyBits & (1ul << i)) == 0)
- continue;
- AnimatorControllerParameter par = parameters[i];
- if (par.type == AnimatorControllerParameterType.Int)
- {
- int newIntValue = reader.ReadInt();
- if (animatorEnabled)
- animator.SetInteger(par.nameHash, newIntValue);
- }
- else if (par.type == AnimatorControllerParameterType.Float)
- {
- float newFloatValue = reader.ReadFloat();
- if (animatorEnabled)
- animator.SetFloat(par.nameHash, newFloatValue);
- }
- else if (par.type == AnimatorControllerParameterType.Bool)
- {
- bool newBoolValue = reader.ReadBool();
- if (animatorEnabled)
- animator.SetBool(par.nameHash, newBoolValue);
- }
- }
- }
-
-
-
-
-
-
- public override bool OnSerialize(NetworkWriter writer, bool initialState)
- {
- bool changed = base.OnSerialize(writer, initialState);
- if (initialState)
- {
- for (int i = 0; i < animator.layerCount; i++)
- {
- if (animator.IsInTransition(i))
- {
- AnimatorStateInfo st = animator.GetNextAnimatorStateInfo(i);
- writer.WriteInt(st.fullPathHash);
- writer.WriteFloat(st.normalizedTime);
- }
- else
- {
- AnimatorStateInfo st = animator.GetCurrentAnimatorStateInfo(i);
- writer.WriteInt(st.fullPathHash);
- writer.WriteFloat(st.normalizedTime);
- }
- writer.WriteFloat(animator.GetLayerWeight(i));
- }
- WriteParameters(writer, initialState);
- return true;
- }
- return changed;
- }
-
-
-
-
-
- public override void OnDeserialize(NetworkReader reader, bool initialState)
- {
- base.OnDeserialize(reader, initialState);
- if (initialState)
- {
- for (int i = 0; i < animator.layerCount; i++)
- {
- int stateHash = reader.ReadInt();
- float normalizedTime = reader.ReadFloat();
- animator.SetLayerWeight(i, reader.ReadFloat());
- animator.Play(stateHash, i, normalizedTime);
- }
- ReadParameters(reader);
- }
- }
-
-
-
-
-
- public void SetTrigger(string triggerName)
- {
- SetTrigger(Animator.StringToHash(triggerName));
- }
-
-
-
-
- public void SetTrigger(int hash)
- {
- if (clientAuthority)
- {
- if (!isClient)
- {
- Debug.LogWarning("Tried to set animation in the server for a client-controlled animator");
- return;
- }
- if (!hasAuthority)
- {
- Debug.LogWarning("Only the client with authority can set animations");
- return;
- }
- if (isClient)
- CmdOnAnimationTriggerServerMessage(hash);
-
- HandleAnimTriggerMsg(hash);
- }
- else
- {
- if (!isServer)
- {
- Debug.LogWarning("Tried to set animation in the client for a server-controlled animator");
- return;
- }
- HandleAnimTriggerMsg(hash);
- RpcOnAnimationTriggerClientMessage(hash);
- }
- }
-
-
-
-
-
- public void ResetTrigger(string triggerName)
- {
- ResetTrigger(Animator.StringToHash(triggerName));
- }
-
-
-
-
- public void ResetTrigger(int hash)
- {
- if (clientAuthority)
- {
- if (!isClient)
- {
- Debug.LogWarning("Tried to reset animation in the server for a client-controlled animator");
- return;
- }
- if (!hasAuthority)
- {
- Debug.LogWarning("Only the client with authority can reset animations");
- return;
- }
- if (isClient)
- CmdOnAnimationResetTriggerServerMessage(hash);
-
- HandleAnimResetTriggerMsg(hash);
- }
- else
- {
- if (!isServer)
- {
- Debug.LogWarning("Tried to reset animation in the client for a server-controlled animator");
- return;
- }
- HandleAnimResetTriggerMsg(hash);
- RpcOnAnimationResetTriggerClientMessage(hash);
- }
- }
- #region server message handlers
- [Command]
- void CmdOnAnimationServerMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters)
- {
-
- if (!clientAuthority)
- return;
-
-
- using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters))
- {
- HandleAnimMsg(stateHash, normalizedTime, layerId, weight, networkReader);
- RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, weight, parameters);
- }
- }
- [Command]
- void CmdOnAnimationParametersServerMessage(byte[] parameters)
- {
-
- if (!clientAuthority)
- return;
-
- using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters))
- {
- HandleAnimParamsMsg(networkReader);
- RpcOnAnimationParametersClientMessage(parameters);
- }
- }
- [Command]
- void CmdOnAnimationTriggerServerMessage(int hash)
- {
-
- if (!clientAuthority)
- return;
-
-
- bool isHostOwner = isClient && hasAuthority;
- if (!isHostOwner)
- {
- HandleAnimTriggerMsg(hash);
- }
- RpcOnAnimationTriggerClientMessage(hash);
- }
- [Command]
- void CmdOnAnimationResetTriggerServerMessage(int hash)
- {
-
- if (!clientAuthority)
- return;
-
-
- bool isHostOwner = isClient && hasAuthority;
- if (!isHostOwner)
- {
- HandleAnimResetTriggerMsg(hash);
- }
- RpcOnAnimationResetTriggerClientMessage(hash);
- }
- [Command]
- void CmdSetAnimatorSpeed(float newSpeed)
- {
-
- animator.speed = newSpeed;
- animatorSpeed = newSpeed;
- }
- #endregion
- #region client message handlers
- [ClientRpc]
- void RpcOnAnimationClientMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters)
- {
- using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters))
- HandleAnimMsg(stateHash, normalizedTime, layerId, weight, networkReader);
- }
- [ClientRpc]
- void RpcOnAnimationParametersClientMessage(byte[] parameters)
- {
- using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters))
- HandleAnimParamsMsg(networkReader);
- }
- [ClientRpc]
- void RpcOnAnimationTriggerClientMessage(int hash)
- {
-
- if (isServer || (clientAuthority && hasAuthority)) return;
- HandleAnimTriggerMsg(hash);
- }
- [ClientRpc]
- void RpcOnAnimationResetTriggerClientMessage(int hash)
- {
-
- if (isServer || (clientAuthority && hasAuthority)) return;
- HandleAnimResetTriggerMsg(hash);
- }
- #endregion
- }
- }
|