Owned States

States don't need a reference to the StateMachine they're used in for the system to function, however you can optionally implement IOwnedState (which inherits from IState) in order to use the Extension Methods in the StateExtensions class with your states.

Example

The State Type implements IOwnedState:

public abstract class CharacterState : StateBehaviour, IOwnedState<CharacterState>
{
    [SerializeField]
    private Character _Character;
    public Character Character => _Character;

    // Implement the OwnerStateMachine property from IOwnedState<CharacterState>:
    public StateMachine<CharacterState> OwnerStateMachine => _Character.StateMachine;
    
    // Make a non-generic state machine class for this state type:
    [Serializable] public class StateMachine : StateMachine<CharacterState> { }
}

The class holding the StateMachine looks the same as usual:

public class Character : MonoBehaviour
{
    [SerializeField] private CharacterState.StateMachine _StateMachine;
    
    public CharacterState.StateMachine StateMachine => _StateMachine;
    
    protected virtual void Awake()
    {
        _StateMachine.InitializeAfterDeserialize();
    }
}

And now other scripts that control the StateMachine can be a bit simpler:

public class CharacterBrain : MonoBehaviour
{
    [SerializeField] private Character _Character;
    [SerializeField] private CharacterState _Walk;

    protected virtual void Update()
    {
        if (Input.GetKey(KeyCode.W))
        {
            // Normally we would need to tell the StateMachine which state to enter.
            _Character.StateMachine.TrySetState(_Walk);

            // But since CharacterState implements IOwnedState we can do the same thing with:
            _Walk.TryEnterState();
        }
    }

    private bool IsWalking()
    {
        // Without IOwnedState:
        return _Character.StateMachine.CurrentState == _Walk;

        // With IOwnedState:
        return _Walk.IsCurrentState();
    }
}