How to debug unsuccessful unsubscribing from events

Hi =)

I have a local multiplater setup, where you can control one of many cannons at a time.
A player walks over to a cannon and interacts with it and passes its input class. The movement part of the input system is disabled and the cannon part is enabled. The Player can demount the cannon and go over to another cannon and mount it. However now both the old and the new cannon now responds to the input from the player.

The following is used to deactivate the settings from the player movement controls and activating the cannon controls:

public void GrabCannon(MasterInput input)
{
   _input = input;
   _input.Cannon.Aim.started += context => IsAiming = true;
   _input.Cannon.Aim.performed += context => SetAimAmount(context.ReadValue<Vector2>());
   _input.Cannon.Aim.canceled += context => IsAiming = false;
   _input.Cannon.Shoot.performed += context => LightCannon();
   Invoke("SetupDisable", 0.1f);//Delayed as the same button is used to mount and demount the cannon.

   _input.Player.Disable();
   _input.Cannon.Enable();
}

private void SetupDisable()
{
  _input.Cannon.Exit.performed += context => Disable();
}

The following is used when disabling the cannon controls

public void Disable()
{
   print("unsubcribing"); //Is displayed in the log when testing and no errors afterwards

   _input.Cannon.Aim.started -= context => IsAiming = true;
   _input.Cannon.Aim.performed -= context => SetAimAmount(context.ReadValue<Vector2>());
   _input.Cannon.Aim.canceled -= context => IsAiming = false;
   _input.Cannon.Shoot.performed -= context => LightCannon();
   _input.Cannon.Exit.performed -= context => Disable();

   _input.Cannon.Disable();
   _input.Player.Enable();
}

I do not know how to investigate this problem further. Maybe it is something I do incorrectly is in the setup.
Do anybody have any ideas on how to investigate further?

Best regards Povl

This won’t quite work. To unsubscribe, you need to pass a C# delegate that compares equal to the one you used to register. Here, you are creating a new delegate in the right side expression.

One way to fix this is by storing the delegates you create in GrabCannon in fields and then using the values of those fields when unsubscribing.

Hi Rene-Damm

Thank you very much.
I tried the following and it worked =)

General in the class

 private Action<InputAction.CallbackContext> fireAction;

In the subcribe part

 fireAction = context => LightCannon();
        _input.Cannon.Shoot.performed += fireAction;

In unsubscribe part

 _input.Cannon.Shoot.performed -= fireAction;

I can understand why the old method did not work for the anonymous methods (e.g. context => IsAiming = false:wink: , but I am not quite certain with this type: context => LightCannon();
My guess is they are also created as anonymous methods, even though I feel like they are not (might be some missing information on my part).

Do you have a better way to manage the delegates than my idea? I will end up with five delegates on this controller alone.

Best wishes and thank you for helping me =)

Povl Eller

It is because this basically stores the value of your anonymous function.
I generally don’t like this syntactic sugar, because it hides multiple method calls. But seems popular among people, so I’m just a grumpy old man with my closer-to-the-metal viewpoint. :slight_smile:

The thing is, when you subscribe/unsubscribe in this case, you subscribe/unsubscribe the fireAction, not the LightCannon or an anonymous function. That’s why it works.

I still like more the
private void LightCannon(Context[whatever]…) {}
and simply _input.Cannon.Shoot.performed [+|-]= LightCannon;

You always can call the context.ReadValue inside your method, so much more clear this way and you never have the problem with the unsubscribe part.

1 Like

Hi Lurking-Ninja,

I just tried your version and it also works!
I think I will use this method, to avoid too many extra properties.
Thank you =)
And I don’t find you grumpy =)

For reference for others with the same problem
Method that is subscribed/unsubscribed

    public void SetAimAmount(InputAction.CallbackContext context)
    {
        _aimAmount = context.ReadValue<Vector2>();
    }

Subscribing

_input.Cannon.Aim.performed += SetAimAmount;

Unsubscribing

_input.Cannon.Aim.performed -= SetAimAmount;