Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Check if UnityEvent already contains a method without name check

Discussion in 'Scripting' started by FerdowsurAsif, Aug 11, 2022.

  1. FerdowsurAsif

    FerdowsurAsif

    Joined:
    Feb 7, 2017
    Posts:
    268
    Hi!,
    I have a unity event that gets methods from different scripts. I want to make sure that the same method doesn't get added twice by accident.
    The closest to I came to my solution is comparing the names of the methods. Which can cause issues if there are multiple scripts with the same method name.
    What would be the best solution to my problem?

    Here is a simplified test code:

    Code (CSharp):
    1.     [SerializeField] UnityEvent unityEvent;
    2.  
    3.     [ContextMenu("Test")]
    4.     private void Test()
    5.     {
    6.         bool alreadyContains = false;
    7.  
    8.         for (int i = 0; i < unityEvent.GetPersistentEventCount(); i++)
    9.         {
    10.             //if (unityEvent.GetPersistentTarget(i) == MyMethod) //something like this
    11.             if (unityEvent.GetPersistentMethodName(i) == nameof(MyMethod)) //this might cause issues with similar names
    12.             {
    13.                 Debug.Log("Already exists");
    14.                 alreadyContains = true;
    15.                 break;
    16.             }
    17.         }
    18.  
    19.         if (!alreadyContains)
    20.         {
    21.             UnityEventTools.AddPersistentListener(unityEvent, MyMethod);
    22.         }
    23.     }
    24.  
    25.     private void MyMethod() { }
     
  2. Sphinks

    Sphinks

    Joined:
    Apr 6, 2019
    Posts:
    267
    I don´t know if it is a good solution, but you could use a Dictionary, with the script (-name) as key and the method name as value, so you could compare the script/key and the method/value.
     
    FerdowsurAsif likes this.
  3. FerdowsurAsif

    FerdowsurAsif

    Joined:
    Feb 7, 2017
    Posts:
    268
    Thanks. That gave me an idea to compare the target type.
    Code (CSharp):
    1.         for (int i = 0; i < unityEvent.GetPersistentEventCount(); i++)
    2.         {
    3.             if (unityEvent.GetPersistentTarget(i).GetType() == (typeof(TestScript))) //Added this
    4.             {
    5.                 if (unityEvent.GetPersistentMethodName(i) == nameof(MyMethod)) //this might cause issues
    6.                 {
    7.                     Debug.Log("Already exists");
    8.                     alreadyContains = true;
    9.                     break;
    10.                 }
    11.             }
    12.         }
    This should work in my case but still feels like a hack since there could be multiple instances of a script in the scene. Example: Multiple enemies with healthScript trying to addListener.
     
  4. FerdowsurAsif

    FerdowsurAsif

    Joined:
    Feb 7, 2017
    Posts:
    268
    I think I figured it out. I think in this scenario, "object this" refers to the specific instance of the script. I can test against that to confirm. I haven't tested yet but this should be ok.

    Code (CSharp):
    1.         for (int i = 0; i < unityEvent.GetPersistentEventCount(); i++)
    2.         {
    3.             if (unityEvent.GetPersistentTarget(i) == this) //this          
    4.             {
    5.                 if (unityEvent.GetPersistentMethodName(i) == nameof(MyMethod))
    6.                 {
    7.                     Debug.Log("Already exists");
    8.                     alreadyContains = true;
    9.                     break;
    10.                 }
    11.             }
    12.         }
    I can't think of any scenario where this won't work. If anyone figures out a better way, please let me know.
     
    Sphinks likes this.
  5. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    507
    Not sure if you can use this for your case, but I had a rare case where I wanted to prevent duplicated listeners and my lazy solution was to just call RemoveListener(MyMethod) directly before calling AddListener(MyMethod).

    If the method was not added before the remove all will do nothing and it will be added, but if it was already there it will be removed and readded again, so it will never be added as a duplicate.
     
    FerdowsurAsif likes this.
  6. FerdowsurAsif

    FerdowsurAsif

    Joined:
    Feb 7, 2017
    Posts:
    268
    Actually, that fits my use case and sounds like should work fine. But, I already am using GetPersistentTarget(I). If that doesn't work out, I will try it. Thanks for the suggestion!