Sorry… correction, they don’t necessarily call the one without the AnimatorControllerPlayable argument.
I figured out what it is.
Even though they have virtual methods for all these messages.
I think they only exist for our benefit of having an easy way to type in the signature. Unlike MonoBehaviour where you just have to know the name/args of the messages it receives. Since these are more complicated the overrides exist so I don’t have to remember them (note - I know VS has a plugin to assist here, but not everyone has those tools available to them).
Thing is… I think they still call them following the same rules as MonoBehaviours.
That is they search up the class hierarchy starting from the bottom and call the first one they find.
So it’s your version of “OnStateEnter” that you override in the lowest down class, and shows up first in that class.
So like:
public class a_OnEnterState : StateMachineBehaviour
{
[SerializeField]
private SPAnimatorStateMachineEvent _onEnter;
//this one is called
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller)
{
if (_onEnter.HasReceivers) _onEnter.ActivateTrigger(animator, null);
}
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (_onEnter.HasReceivers) _onEnter.ActivateTrigger(animator, null);
}
}
In this one the one with the AnimatorControllerPlayable gets called.
public class a_OnEnterState : StateMachineBehaviour
{
[SerializeField]
private SPAnimatorStateMachineEvent _onEnter;
//this one is called
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (_onEnter.HasReceivers) _onEnter.ActivateTrigger(animator, null);
}
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller)
{
if (_onEnter.HasReceivers) _onEnter.ActivateTrigger(animator, null);
}
}
{
if (_onEnter.HasReceivers) _onEnter.ActivateTrigger(animator, null);
}
}
And this one the one without the AnimatorContollerPlayable gets called.
And if I did this:
public class BaseSMB : StateMachineBehaviour
{
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
//does nothing
}
}
public class a_OnEnterState : StateMachineBehaviour
{
[SerializeField]
private SPAnimatorStateMachineEvent _onEnter;
//this one is called
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller)
{
if (_onEnter.HasReceivers) _onEnter.ActivateTrigger(animator, null);
}
}
The one in a_OnEnterState is called because it’s the lowest in the class hierarchy.
…
This is all fine and dandy. They’re following some sort of rules that I’m familiar with. It’s the same rules MonoBehaviour messages do.
BUT, they’re slightly off from MonoBehaviour messages because they have the virtual methods (which MB’s don’t). Which is why I didn’t originally think to make this assumption.
But the thing is… this behaviour of MonoBehaviour messages isn’t exactly well documented either. It’s just knowledge I’ve gathered over the years of using Unity, and I suspect others who know it also just figured it out over time. And I know many don’t know it, cause it’s a quark about MB’s that I’ve had to explain here on the forums.
I just wish this sort of stuff was like… written down… somewhere easily noticeable.
Like right here in the StateMachineBehaviour api documentation:
It’s like the first place I would have thought to looked. But no, it doesn’t even show that there are 2 overloads! Let alone explain why there are, or which gets called when?
Come on Unity… I like your engine. I like it a lot. I’ve been using for a long time now! But I have gripes about it… as I do any software I use. And I suspect people have gripes with my software.
But the one thing I think y’all really need to get on top of… documentation.
It’s bizarre how large your documentation is… yet it says so little about the “magical behaviour” of your engine. Magical behaviour being things like this where it’s not obvious to know what’s actually happening since the actual rules of it exist behind closed source on the C++/internal side of the engine and never really been disclosed.
Black box behaviour.
There you go, better term for it.
Becuase this isn’t stuff that some newb developer messes up. Someone not understanding ref types or value types or what a class is. Well MSDN and swaths of books, tutorials, articles, and people in general have that covered. It’s well documented and well known stuff. Those users are just… new… and haven’t learned it.
This on the other hand is behaviour that took a developer with decades of experience to poke/prod/pry at, and reflect against existing knowledge of the quarky ways Unity does things, and suss it out.
It’s not something a beginner is going to figure out easily.