I am using a Network Animator over my character and animations are visible for each local player locally but aren’t getting synced with other players.
Host (Server) player’s animation is visible to all clients but client animation is not visible to other clients/host.
Hi @niharchitnis @bosko0509, I’ve recently resolved this.
Background info
First of all I think this is the default principle/behaviour which comes with Unity network components (e.g. NetworkTransform, NetworkVariable). The default behaviour is that only Server is permitted to to network data changes and sync them with all connected clients.
For example, if you add NetworkTransform to some obj and will try to move this obj within the client instance of a game – you will observe your obj immovable (because changes are made on client instance of an object and Server doesn’t know about such changes for his instance of the object but at the same time Server always forces the position value of his object to the client object).
Solution:
-
Request client animation changes from clients on Server (possibly via RPC calls)
-
To grant a client permission to change network animations and enable sync to other clients you simply need to create your own version of NetworkAnimator with overridden OnIsServerAuthoritative and use this as a component in your objects. Check the code:
public class ClientNetworkAnimator : NetworkAnimator
{
protected override bool OnIsServerAuthoritative() => false;
}
P.S. I’m not an Unity expert. Above is only my vision how to explain and resolve this issue
This is what worked for me @niharchitnis @bosko0509
- Script that plays the animations should be (you could probably use [SerializedField] or GetComponent<> but when I tried it didn’t work for me) on the same game object that also has the Animator & NetworkAnimator
- Checking the IsOwner and IsSpawn on the NetworkBehaviour script that is playing the Animations
- Use [ServerRpc] to play the animation
using Unity.Netcode;
using Unity.Netcode.Components;
using UnityEngine;
[RequireComponent(typeof(Animator))]
public class AnimationBlendTreeController : NetworkBehaviour
{
// Credits : iHeartGameDev : https://www.youtube.com/watch?v=m8rGyoStfgQ&list=PLwyUzJb_FNeTQwyGujWRLqnfKpV-cj-eO&index=4
[SerializeField] private PlayerMovement _playerMovement;
[SerializeField] private float _accelaration = 0.1f;
[SerializeField] private float _deccelaration = 0.5f;
[SerializeField][Range(0f, 5f)] private float _maxVelocity = 1f;
private Animator _animator;
private float _velocity = 0.0f;
private int _velocityHash;
private void Awake()
{
_animator = GetComponent<Animator>();
_velocityHash = Animator.StringToHash("Velocity");
}
// Update is called once per frame
void Update()
{
if (IsOwner && IsSpawned)
{
// handle calculations on the client
HandleMovement();
if (_playerMovement.IsGrounded)
{
// have the server play the animations
HandleAnimationServerRpc(_velocity);
}
}
}
public void HandleMovement()
{
bool forwardPressed = Input.GetKey(KeyCode.W);
bool runPressed = Input.GetKey(KeyCode.LeftShift);
if (forwardPressed && _velocity < _maxVelocity)
{
_velocity += Time.deltaTime * _accelaration;
}
if (!forwardPressed && _velocity > 0.0f)
{
_velocity -= Time.deltaTime * _deccelaration;
}
if (!forwardPressed && _velocity < 0.0f)
{
_velocity = 0.0f;
}
}
[ServerRpc]
private void HandleAnimationServerRpc(float velocity)
{
_animator.SetFloat(_velocityHash, velocity);
}
}
Same problem did you find any solution yet?