Search Unity

Feature Request Clear Error messages on missing UnityEvents

Discussion in 'Editor & General Support' started by SupremeCookieDev, Apr 6, 2021.

  1. SupremeCookieDev

    SupremeCookieDev

    Joined:
    Jun 8, 2015
    Posts:
    3
    Something I noticed last night is that when you move a method from one class to another, any unity events that were bound to that method will now show "<missing eventName>"
    The only way to notice this issue is if you happen to know what logic that event should show, and when, and then to happen upon it.

    What would be great, is that those missing events would show as errors, for example; when trying to call them, when compiling, whenever really. Just properly show us that the event is missing a method binding.
    There's apparently information available to be able to show "<missing eventName>" so it should be doable to take that 'state' of the event and display it as an error.

    Kind Regards!
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,911
    Agreed, and let's go ahead and extend that to missing MonoBehaviour scripts as well!
     
    SupremeCookieDev likes this.
  3. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,196
    Agreed that something built-in for this would be welcome. In the mean time, you can check for problems yourself:

    Code (CSharp):
    1.  
    2. public static void FindAllMissingMethods()
    3. {
    4.     foreach (var controller in GameObject.FindObjectsOfType<MonoBehaviour>())
    5.     {
    6.         foreach (var field in controller.GetType().GetFields().Where(f => f.GetValue(controller) is UnityEventBase))
    7.         {
    8.             ValidateMissingUnityEventImplementation(controller, field.GetValue(controller) as UnityEventBase, false);
    9.         }
    10.     }
    11. }
    12.  
    13.  
    14. public static void ValidateMissingUnityEventImplementation(MonoBehaviour controller, UnityEventBase unityEvent, bool requireHandler = false)
    15. {
    16. #if UNITY_EDITOR
    17.     var field = controller.GetType().GetFields().FirstOrDefault(f => f.GetValue(controller) == unityEvent);
    18.  
    19.     if (requireHandler)
    20.     {
    21.         if (unityEvent == null || unityEvent.GetPersistentEventCount() == 0)
    22.         {
    23.             throw new Exception($"GameObject '{controller.gameObject.name}' has no handler for UnityEvent '{field.Name}', but one is required.'");
    24.         }
    25.     }
    26.  
    27.  
    28.     if (unityEvent != null)
    29.     {
    30.         for (int eventIndex = 0; eventIndex < unityEvent.GetPersistentEventCount(); eventIndex++)
    31.         {
    32.             var methodName = unityEvent.GetPersistentMethodName(eventIndex);
    33.  
    34.             if (string.IsNullOrWhiteSpace(methodName))
    35.             {
    36.                 throw new Exception($"GameObject '{controller.gameObject.name}' has UnityEvent '{field.Name}' with no selected method name.");
    37.             }
    38.  
    39.             var target = unityEvent.GetPersistentTarget(eventIndex);
    40.             var method = target.GetType().GetMethods().FirstOrDefault(m => m.Name == methodName);
    41.             if (method == null)
    42.             {
    43.                 throw new Exception($"GameObject '{controller.gameObject.name}' has a UnityEvent '{field.Name}' with a missing method name ({methodName}).");
    44.             }
    45.         }
    46.     }
    47. #endif
    48. }
    49.  
    You can just call "FindAllMissingMethods" whenever you load a scene. For missing events, it would then log an error like this:

    "Exception: GameObject 'CourseClosedTrigger' has a UnityEvent 'TriggerEnter' with a missing method name (DisplayCourseClosedMessage)."

    It's not perfect: I haven't taken the time to make this warn about argument mismatches. For example, if your event was calling ABC(), but you change ABC() to ABC(bool), that will break the event, but this code won't notice the problem. But this catches 95% of the issues I have with events missing their implementations.

    There are probably other improvements as well, but just having some basic runtime validation like this saved me a lot of headaches.

    And if you have some events on specific objects that you always want to make sure you've added an event, you can call
    ValidateMissingUnityEventImplementation
    on specific events, passing in True for required. I use that for prefabs that I've dropped into a scene, where I'll always want its events wired up, but I might have forgotten to.
     
    Last edited: Apr 6, 2021
    SupremeCookieDev likes this.