Animation Priority Disparity

Reproduction Steps

Load an animation onto an AnimationController that is descendant of a non-playable character.
I am unsure if this occurs on every rig, but certainly occurs on ones structured like this.

Expected Behavior

Animation priorities should be consistent no matter what it is being loaded onto.

Actual Behavior

The priority of the animation track loaded is different depending on if you load onto a NPC or the player’s character.

Issue Area: Engine
Issue Type: Other
Impact: High
Frequency: Constantly

1 Like

It looks like you have an AnimatorController-based character inside the model of a Humanoid-based character. Firstly, don’t do that, it’s not an expected pattern, particularly if one of the characters is a Player.Character avatar. Secondly, do the Humanoid and AnimatorController both have Animators as children? If so, how do you even know which one you’re getting a reference to? Recursive FindFirstChild does not have any API guarantee about what it considers “First”, if it searches depth-first, it could find the AnimatorController Animator before the Humanoid’s Animator). It would be saner to get the references to the Humanoid and/or AnimationController first, then explicitly get the Animator you intend. But really, you should un-nest these characters and then not have this ambiguity in the first place.

We also can’t tell from your small code snippets what other scripts might be changing priority. Have you tried printing the priority on the line right after LoadAnimation returns the track? Your example has the print statement inside a self:Play(…) function, and we have no idea how much code excutes between LoadAnimation and when that print statement eventually gets called. If you have something like an Animate script that only loads for a player-controlled avatar, it could be changing track priorities, yeah?

I’d recommend trying a really simple example, just load the same animation onto a player character and non-player character, and print the track priority immediately after you load the animation, before any other code gets a chance to mess with it. Track priority replicates now (albeit indirectly through the owning Animator, not normal property replication), so even a client LocalScript could change the value on the server.

1 Like

Hi, thanks for the reply, I’ll make some explanations as to why I’ve reported like this.

“It looks like you have an AnimatorController-based character inside the model of a Humanoid-based character. Firstly, don’t do that, it’s not an expected pattern, particularly if one of the characters is a Player.Character avatar.”

I’d say that regardless of how the rig works, this would still class as an engine bug, without parenting animation controllers inside the character’s rig we are massively limiting our creative ability. Functionally for my game, it makes the most sense to have the non-humanoid-based rig parented inside the player’s avatar and I know a lot of experiences which do a similar thing since the additional rig is an extension of the player’s avatar it is logical to parent it inside the character.

I’m aware of the recursive FindFirstChild() not having any documented method, but again it’s not particularly relevant, I would assume that when I made my report it’d be evident I’d checked that it was the correct animator, else I wouldn’t have reported it as an engine bug.

Chalk it down to laziness, but replication behaviour shouldn’t affect the animation’s priority in the first place if the way it was loaded is the same, and yes of course other pieces of code could have modified this but as is true with any other bug report.

I’ve created a work-around for the problem, and I can’t particularly be bothered to go and create a simpler example as it’s not an issue that’s plaguing me anymore, just an unexpected behaviour.

Thanks for the report. We’ve filed a ticket to our internal database and we’ll keep you updated on progress!

1 Like

We are not able to reproduce the behavior as described, that is a behavior disparity between AnimationController or Humanoid driven Animators.

However, I believe the print disparity that you’re observing here is due to the intermediate state AniamtionTracks find themselves in when you request to load an animation that is not already cached in memory. The engine will asynchronously load the animation asset and will only start playing once everything is available to the animations system. This intermediate step is not surfaced to the API on purpose.

Unless a track specifically overrides the Priority value, it will have a default priority of “Action” until the requested AnimationClip is loaded and ready to go. At this point the track will inherit the priority defined by the clip. Your print statement is inaccurate because of this fairly benign “race condition” (benign because the track is a no-op until the clip is actually loaded).

I am able to repro the behavior that you’ve noticed with an NPC and a player. Since player characters generally take significantly longer to load, the script starts executing long after the NPC’s script called LoadAnimation (55 frames later), at which point the AnimationClip is already cached in memory and the track is initialized at the right priority.