Search Unity

Get number of runtime listeners

Discussion in 'UGUI & TextMesh Pro' started by pixelsplit, Jan 21, 2015.

  1. pixelsplit

    pixelsplit

    Joined:
    Sep 16, 2013
    Posts:
    173
    Hi,

    we are currently creating a new game using the new Unity GUI system. Everything working fine so far :)
    We have created a GUI which is shared by different scenes - the problem is now, that the GUI contains buttons etc. that are not used by every scene. I wanted to delete them.

    I thought it would be pretty cool to check (after the scene has been set up), if an element (e.g. toggle or button) has an event set, or not - if not, Destroy it(s gameobject). Is there any built-in way, that we could check if a certain UnityEvent has listeners registered to it?

    Thanks for your answers in advance!

    Regards,
    Bennet
     
    Last edited: Jan 21, 2015
  2. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Interesting setup there Bennet

    As far as I'm aware, the linage used weak referencing between the Input System and the UI components that expose the various interfaces. The input systems simply look for scripts that implement the interfaces when an event occurs. There is some performance batching in the back end but no hard references.

    So there should not be anything to destroy per-se.

    Maybe one of the Unity team can chime in and confirm, but that is my understanding
     
  3. pixelsplit

    pixelsplit

    Joined:
    Sep 16, 2013
    Posts:
    173
    Hm I think that is not what I meant - we are heavily using AddListener via code. There is also a method RemoveListener. So somewhere in the backend there is some sort of collection which keeps references to the specified delegates. I want to get the list of these assigned delegates of a certain UnityEvent, or at least the number of assigned listeners.
     
  4. dterbeest

    dterbeest

    Joined:
    Mar 23, 2012
    Posts:
    389
  5. pixelsplit

    pixelsplit

    Joined:
    Sep 16, 2013
    Posts:
    173
    Hehe I already tried that one - but the documentation is not very well explained at this point. I think the GetPersistentEventCount method gives the number of times, that a certain event was fired. However: it does definitely NOT return the number of assigned (runtime) listeners. Another hint for that is, that listeners assigned via runtime [via AddListener method] are called non-persistent (see http://docs.unity3d.com/460/Documentation/ScriptReference/Events.UnityEvent.AddListener.html).
     
    VenetianFox likes this.
  6. dterbeest

    dterbeest

    Joined:
    Mar 23, 2012
    Posts:
    389
    aah.. makes sense..

    well.. then i guess it would be advisable to create your own implementation of UnityEvent and override the AddListener function to keep your own count
     
  7. pixelsplit

    pixelsplit

    Joined:
    Sep 16, 2013
    Posts:
    173
    Yes, if no one replies with another elegant (hopefully built-in) solution then i'll do something like that tomorrow.
     
  8. dterbeest

    dterbeest

    Joined:
    Mar 23, 2012
    Posts:
    389
    well.. simply overriding the AddListener and RemoveListener functions won't work..

    This compiles, but i have no time to test it anymore:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Events;
    4. using System.Collections;
    5.  
    6. public class test : UnityEvent
    7. {
    8.   private int _listenerCount;
    9.  
    10.   public int ListenerCount { get { return _listenerCount; } }
    11.  
    12.   public test()
    13.   {
    14.     _listenerCount = 0;
    15.   }
    16.  
    17.   new public void AddListener(UnityAction call)
    18.   {
    19.     base.AddListener(call);
    20.     _listenerCount++;
    21.   }
    22.  
    23.   new public void RemoveListener(UnityAction call)
    24.   {
    25.     base.RemoveListener(call);
    26.     _listenerCount--;
    27.   }
    28. }
    29.  
     
  9. pixelsplit

    pixelsplit

    Joined:
    Sep 16, 2013
    Posts:
    173
    Thanks for the code - that would also have been my first attempt. But I gave it some more thoughts and I don't like the idea of subclassing UnityEvent for counting the listeners.
    • I would need to do this for every UnityEvent_x, to support the variety of parameter counts
    • The code would be coupled to this custom written UnityEvent thingy, thats not worth it - I would have to use this special UnityEvent subclass all over the place, maybe do some type casts at some points etc.
    I think i'll have to go with explicitly stating which UI Elements to use and which not. So in my scenes that additive load the "InGame GUI" Scene I would create some sort of GUIDescriptor script which explains which UI Elements are required. The other ones then would be deleted by some coordinator in the "InGame GUI".

    It's too bad, that the APIs don't provide the listener count :( That would have allowed such a nice solution.
     
    kobyle, Harinezumi and paradizIsCool like this.
  10. kobyle

    kobyle

    Joined:
    Feb 23, 2015
    Posts:
    92
    @zkw did you ever find a built-in solution for this?
     
  11. FlightOfOne

    FlightOfOne

    Joined:
    Aug 1, 2014
    Posts:
    668
    I came upon this thread trying to figure out a solution to what is being discussed. I tried what @dterbeest (thank you!) suggested and it seems to work exactly as he said. It does give the number events I have added to "UnityEvent", NOT how many times it has been fired. But I should mention that these events were added via inspector.
     
  12. kristof_nemesys

    kristof_nemesys

    Joined:
    May 22, 2019
    Posts:
    1
    yes, because if you add it via inspector, those count as persistent listeners, but if you add via code (onclick.addlistener) those are non-persistent. The built in function only lists the persistent listener count, so unfortunately this is no good (for this use case)
     
    dtaddis, gendev and FlightOfOne like this.
  13. nikolay_i

    nikolay_i

    Joined:
    Jan 5, 2020
    Posts:
    13
    Create static class with following code
    Code (csharp):
    1.  
    2. public static int GetListenerNumber(this UnityEventBase unityEvent)
    3. {
    4.     var field = typeof(UnityEventBase).GetField("m_Calls", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly );
    5.     var invokeCallList = field.GetValue(unityEvent);
    6.     var property = invokeCallList.GetType().GetProperty("Count");
    7.     return (int)property.GetValue(invokeCallList);
    8. }
    9.  
    and then use
    exceptionEvent.GetListenerNumber()

    as you can see it use aggregated count (for runtime and inspector defined events) if you need just runtime - go to
    InvokableCallList class and find the private list with runtime only events
     
    jnbbender, akuno, dtaddis and 7 others like this.
  14. Menion-Leah

    Menion-Leah

    Joined:
    Nov 5, 2014
    Posts:
    189
    It looks like this works great in the Editor, but fails on iOS (Unity 2020.3.39f1): the result of
    typeof(UnityEventBase).GetField("m_Calls", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly );
    is NULL.

    Any alternatives or workarounds available?