Animation issue when networking

saboehnke

New member
Hi there. I'm using FishNet for a networking solution and the Opsive 3rd person controller. I'm having an issue where animations that are triggered via abilities do not sync over the network. I haven't been able to find the actual code that triggers the animation after following the youtube video for setting up the ability with an animation. I'm not sure how the animation would be handled differently in abilities that would cause them to not be synced over the network when normal animations such as walking and idle animations (obviously don't use abilities) seem to work just fine. Any ideas on what is special about the animations triggered via abilities, where I can find that code, and why these animations would be treated differently than the walk/idle animations?
 
The animations are triggered by the AbilityIndex so I would start there. Since networking is inherently a complex subject I recommend that you grab the PUN add-on as a reference so you can trace how the PUN implementation works. Unfortunately there's not a way to create a step by step guide with networking since each implementation is different and it's such a large subject.
 
Well I have seen things about the Animator Motion component. Do you know if ability triggered animations would require root motion and/or an animator motion component?
Also, I'm currently only putting the UltimateCharacterLocomotion component on the local player if that matters.

EDIT: Looks like the Animator Motion component is getting added automatically for me

I really don't know what to even look for here. I have experience with PUN as well. PUN just uses a network transform and network animator component like Fishnet does. If the network animator component is watching the controller and can pick up the idle, walking, and running...it has to be something different in how the abilities trigger the animations. But I can't even find where the abilities trigger the animations to be honest.
Since this asset is client authoritative...maybe I have to send RPCs for the abilities? I can't even find things online from someone that has used opsive and fishnet together. Maybe I need to add new animation parameters and set them to the transitions to see if those will sync.
 
Last edited:
You definitely need the Animator Monitor component. With PUN I subclassed the AnimatorMonitor and sync all of the parameters within that subclass. SetHorizontalMovementParameter/SetForwardMovementParameter, etc are all virtual so you can override them.
 
Maybe I don't need to make new params. I've confirmed that the networked player's animator does have the params being passed for the abilityIndex. The abilityChanged param doesn't change though. So the issue must be in how I setup the networked players. Any ideas?


C#:
var networkAnimator = GetComponent<NetworkAnimator>();
var playerAnimator = playerObj.GetComponent<Animator>();
playerAnimator.runtimeAnimatorController = Resources.Load<RuntimeAnimatorController>("Demo");
playerAnimator.SetBool("IsHumanoid", playerAnimator.isHuman);
networkAnimator.SetAnimator(playerAnimator);

if (IsOwner)
{
    CharacterBuilder.BuildCharacter(gameObject, new GameObject[1] { playerObj }, true,
        new RuntimeAnimatorController[1] { playerAnimator.runtimeAnimatorController }, string.Empty, ControllerType,
        false, new GameObject[0][], null, false);
    CharacterBuilder.BuildCharacterComponents(gameObject, false, false, null, null, false, true, true, playerAnimator.isHuman, false, false);
    var characterLocomotion = gameObject.GetComponent<UltimateCharacterLocomotion>();
    AddAbilities(characterLocomotion);

    var camera = CameraUtility.FindCamera(gameObject);
    if (camera != null)
    {
        var cameraController = camera.GetComponent<CameraController>();
        if (cameraController != null)
        {
            cameraController.Character = gameObject;
        }
    }
}
else
{
    CharacterBuilder.BuildCharacter(gameObject, new GameObject[1] { playerObj }, true,
        new RuntimeAnimatorController[1] { playerAnimator.runtimeAnimatorController }, string.Empty, ControllerType,
        false, new GameObject[0][], null, false);
    CharacterBuilder.BuildCharacterComponents(gameObject, false, false, null, null, false, true, true, playerAnimator.isHuman, false, false);

    var characterLocomotion = gameObject.GetComponent<UltimateCharacterLocomotion>();
    AddAbilities(characterLocomotion);
}

I'm not really sure what a networked player would require in regards to building like above. The docs don't cover it either.

Here's the AddAbilities() logic:

C#:
private void AddAbilities(UltimateCharacterLocomotion characterLocomotion)
{
    AbilityBuilder.AddAbility(characterLocomotion, typeof(MoveTowards));
    AbilityBuilder.AddAbility(characterLocomotion, typeof(SpeedChange));
    AbilityBuilder.AddAbility(characterLocomotion, typeof(HeightChange));
    AbilityBuilder.AddAbility(characterLocomotion, typeof(Interact));
    AddEmotesToAnimator(characterLocomotion);
    AddGenericJumpToAnimator(characterLocomotion);
    AddSittingToAnimator(characterLocomotion);
}

private void AddEmotesToAnimator(UltimateCharacterLocomotion characterLocomotion)
{
    for (int i = 1; i < 11; i++)
    {
        var emoteAbility = (Emote)AbilityBuilder.AddAbility(characterLocomotion, typeof(Emote));
        emoteAbility.InputNames = new string[] { "Emote" + i.ToString("00") };
        emoteAbility.AbilityIndexParameter = 10000 + i;
        emoteAbility.StopEvent = new AnimationEventTrigger(true, 0f);
        emoteAbility.StopType = Ability.AbilityStopType.ButtonToggle;
    }
}

private void AddGenericJumpToAnimator(UltimateCharacterLocomotion characterLocomotion)
{
    var jumpAbility = (Generic)AbilityBuilder.AddAbility(characterLocomotion, typeof(Generic));
    jumpAbility.InputNames = new string[] { "Jump" };
    jumpAbility.AbilityIndexParameter = 10011;
    jumpAbility.StopEvent = new AnimationEventTrigger(true, 0f);
}

private void AddSittingToAnimator(UltimateCharacterLocomotion characterLocomotion)
{
    var sittingAbility = (Sitting)AbilityBuilder.AddAbility(characterLocomotion, typeof(Sitting));
    sittingAbility.InputNames = new string[] { "Sit" };
    sittingAbility.AbilityIndexParameter = 10012;
    sittingAbility.StartType = Ability.AbilityStartType.ButtonDown;
}

Honestly...adding the character locomotion to the networked players screws with them and makes their movement mess up and they flicker in place. Just calling CharacterBuilder.BuildCharacter() for the networked player causes them to snap back and forth between the location they spawned and the location that they have moved to since spawning.

I really wish there was a way for me to understand how a networked player should be setup that won't mess with simple animations and will allow abilities to work...without having to pay for an add-on that I will not be able to use since I'm not using PUN.
 
Last edited:
The abilityChanged param doesn't change though.
That's the issue. In order for the animator to transition the ability changed trigger needs to occur. One of the reasons why the Animator Monitor is subclassed is so it can call SetAbilityIndexParameter which will then enable the trigger.

Beyond that it's really hard to say what the issue is since networking is such a large subject and I am not familiar with Fishnet. The PUN add-on ends up being a great return on investment even if you aren't using PUN since you will be able to step through an example of a complex networking integration.
 
I wrote a small subclass of the AnimatorMonitor that makes that call and switched the Locomotion handler to the Networked version and it seems to be working now.
 
Top