Stop Coroutine from another script - StopCoroutine not working

Hi all,

I am trying to implement crouching in a state machine. When the transition from Idle to Crouch or vice versa happens, the player should lean the upper body forward or backwards. As long as the Coroutines can finish, everything works fine. But if the player is still going down and the first coroutine is still running and the player wants then stand up in the middle of the coroutine, it breaks. So when the player presses C again to stand up, I want to Stop the first coroutine and just then start the second one.
Unfortunately the StopCoroutine doesn’t work. When I debug, I see it still running. And I don’t unterstand why. What am I doing wrong in my code?

Thank you
Huxi

Note: I am starting the coroutine via the playerCamera cause my other scripts are non-MonoBehavior.

public class LeanForward
{
    public ProcanimStateData data;

    public IEnumerator LeaningForward()
    {
        // Stop the another coroutine - they cannot run at the same time.
        // THIS IS WHAT IS NOT WORKING FOR ME
        data.playerCamera.GetComponent<CameraMovement.().StopCoroutine(data.leanForward.LeaningForward());

        Vector3 target = new Vector3(data.spineDefEulerRotation.x + 11, data.spineDefEulerRotation.y, data.spineDefEulerRotation.z);

        while (Vector3.Distance(data.spine.localEulerAngles, target) > 0.1f)
        {
            data.spine.localEulerAngles = Vector3.Slerp(data.spine.localEulerAngles, target, 6 * Time.deltaTime);
            yield return null;
        }
        yield break;
    }
}

I think you’ve misunderstood what calling this.LeaningForward() does:
else if (data.currentLeanCoroutine != this.LeaningForward())
The if-statement will ALWAYS be true because you get a new IEnumerator reference every time you call LeaningForward()

The following code is not a direct solution to your issue, but it should help you understand how coroutine references work:

public class CoroutineExample : MonoBehaviour
{
    private IEnumerator currentAttackCoroutine;
    
    IEnumerator AttackCoroutine(float attackSpeed)
    {
        Debug.Log("Started attacking with speed: " + attackSpeed);

        while (true)
        {
            // Do some attacking here (until we stop the attack)
            // (...)

            yield return null;
        }
    }

    IEnumerator LeaningForwardCoroutine()
    {
        while (true)
        {
            // Animate until done leaning
            // (or until we stop the coroutine)
            // (...)

            yield return null;
        }
    }

    void Start()
    {
        // Note that both of these IEnumerators are returned from the same method, AttackCoroutine(),
        // only the attackSpeed arguments differ,
        // yet the IEnumerator references will not be the same
        IEnumerator attackCoroutineSlowVersion = AttackCoroutine(10);
        IEnumerator attackCoroutineFastVersion = AttackCoroutine(50);
        Debug.Log(attackCoroutineSlowVersion == attackCoroutineFastVersion); // false
        
        // Points currentAttackCoroutine to the slow version of the AttackCoroutine
        currentAttackCoroutine = attackCoroutineSlowVersion;

        // Starts the slow version of the AttackCoroutine.
        // This is the same as StartCoroutine(currentAttackCoroutine) in this case.
        StartCoroutine(attackCoroutineSlowVersion); 

        // currentAttackCoroutine is still not the same as AttackCoroutine(10)
        // even though that's how it was created.
        Debug.Log(currentAttackCoroutine == AttackCoroutine(10)); // false
        
        // Stops whatever coroutine the currentAttackCoroutine variable is pointing to.
        // This is the same as StopCoroutine(attackCoroutineSlowVersion) in this case.
        StopCoroutine(currentAttackCoroutine);

        // Note that when calling (not starting) the same Coroutine method twice
        // you will get two different references
        Debug.Log(AttackCoroutine(20) == AttackCoroutine(20)); // false

        // This is true even when the Coroutine's method definition has no parameters
        // like in your case
        Debug.Log(LeaningForwardCoroutine() == LeaningForwardCoroutine()); // false
    }
}

Do you see why this will always be true?:
if (data.currentLeanCoroutine != this.LeaningForward())

Something that’s confusing me and preventing me from giving you a solution is why are you letting the LeaningForward() method start and stop coroutines?
Why is this not handled outside the method?
Is this a limitation of some animation tool in Unity or something? (I don’t use the animation tools often to be honest)