public static void OnEditAnimationEvents(AnimationWindowEvent[] awEvents)
        {
            AnimationWindowEventData data = GetData(awEvents);

            if (data.events == null || data.selectedEvents == null || data.selectedEvents.Length == 0)
            {
                return;
            }

            AnimationEvent firstEvent = data.selectedEvents[0];

            bool singleFunctionName = Array.TrueForAll(data.selectedEvents, evt => evt.functionName == firstEvent.functionName);

            GUI.changed = false;

            if (data.root != null)
            {
                List <AnimationWindowEventMethod> methods = new List <AnimationWindowEventMethod>();
                HashSet <string> overloads = new HashSet <string>();
                CollectSupportedMethods(data.root, methods, overloads);

                var methodsFormatted = new List <string>(methods.Count);

                for (int i = 0; i < methods.Count; ++i)
                {
                    AnimationWindowEventMethod method = methods[i];

                    string postFix = " ( )";
                    if (method.parameterType != null)
                    {
                        if (method.parameterType == typeof(float))
                        {
                            postFix = " ( float )";
                        }
                        else if (method.parameterType == typeof(int))
                        {
                            postFix = " ( int )";
                        }
                        else
                        {
                            postFix = string.Format(" ( {0} )", method.parameterType.Name);
                        }
                    }

                    methodsFormatted.Add(method.name + postFix);
                }

                int notSupportedIndex = methods.Count;
                int selected          = methods.FindIndex(method => method.name == firstEvent.functionName);
                if (selected == -1)
                {
                    selected = methods.Count;

                    AnimationWindowEventMethod newMethod = new AnimationWindowEventMethod();
                    newMethod.name          = firstEvent.functionName;
                    newMethod.parameterType = null;

                    methods.Add(newMethod);

                    if (string.IsNullOrEmpty(firstEvent.functionName))
                    {
                        methodsFormatted.Add(kNoneSelected);
                    }
                    else
                    {
                        methodsFormatted.Add(firstEvent.functionName + kNotSupportedPostFix);
                    }
                }

                EditorGUIUtility.labelWidth = 130;

                EditorGUI.showMixedValue = !singleFunctionName;
                int wasSelected = singleFunctionName ? selected : -1;
                selected = EditorGUILayout.Popup("Function: ", selected, methodsFormatted.ToArray());
                if (wasSelected != selected && selected != -1 && selected != notSupportedIndex)
                {
                    foreach (var evt in data.selectedEvents)
                    {
                        evt.functionName    = methods[selected].name;
                        evt.stringParameter = string.Empty;
                    }
                }
                EditorGUI.showMixedValue = false;

                var selectedParameter = methods[selected].parameterType;

                if (singleFunctionName && selectedParameter != null)
                {
                    EditorGUILayout.Space();
                    if (selectedParameter == typeof(AnimationEvent))
                    {
                        EditorGUILayout.PrefixLabel("Event Data");
                    }
                    else
                    {
                        EditorGUILayout.PrefixLabel("Parameters");
                    }

                    DoEditRegularParameters(data.selectedEvents, selectedParameter);
                }

                if (overloads.Count > 0)
                {
                    EditorGUILayout.Space();
                    EditorGUILayout.HelpBox(s_OverloadWarning.text, MessageType.Warning, true);
                }
            }
            else
            {
                EditorGUI.showMixedValue = !singleFunctionName;
                string oldFunctionName = singleFunctionName ? firstEvent.functionName : "";
                string functionName    = EditorGUILayout.TextField(EditorGUIUtility.TrTextContent("Function"), oldFunctionName).Replace(" ", "");
                if (functionName != oldFunctionName)
                {
                    foreach (var evt in data.selectedEvents)
                    {
                        evt.functionName    = functionName;
                        evt.stringParameter = string.Empty;
                    }
                }
                EditorGUI.showMixedValue = false;

                if (singleFunctionName)
                {
                    DoEditRegularParameters(data.selectedEvents, typeof(AnimationEvent));
                }
                else
                {
                    using (new EditorGUI.DisabledScope(true)) {
                        AnimationEvent dummyEvent = new AnimationEvent();
                        DoEditRegularParameters(new AnimationEvent[] { dummyEvent }, typeof(AnimationEvent));
                    }
                }
            }

            if (GUI.changed)
            {
                SetData(awEvents, data);
            }
        }
        public static void CollectSupportedMethods(GameObject gameObject, List <AnimationWindowEventMethod> supportedMethods, HashSet <string> overloadedMethods)
        {
            if (gameObject == null)
            {
                return;
            }

            MonoBehaviour[] behaviours = gameObject.GetComponents <MonoBehaviour>();

            foreach (MonoBehaviour behaviour in behaviours)
            {
                if (behaviour == null)
                {
                    continue;
                }

                Type type = behaviour.GetType();
                while (type != typeof(MonoBehaviour) && type != null)
                {
                    MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                    for (int i = 0; i < methods.Length; i++)
                    {
                        MethodInfo method = methods[i];
                        string     name   = method.Name;

                        if (!IsSupportedMethodName(name))
                        {
                            continue;
                        }

                        ParameterInfo[] parameters = method.GetParameters();
                        if (parameters.Length > 1)
                        {
                            continue;
                        }

                        Type parameterType = null;

                        if (parameters.Length == 1)
                        {
                            parameterType = parameters[0].ParameterType;
                            if (!(parameterType == typeof(string) ||
                                  parameterType == typeof(float) ||
                                  parameterType == typeof(int) ||
                                  parameterType == typeof(AnimationEvent) ||
                                  parameterType == typeof(UnityEngine.Object) ||
                                  parameterType.IsSubclassOf(typeof(UnityEngine.Object)) ||
                                  parameterType.IsEnum))
                            {
                                continue;
                            }
                        }

                        AnimationWindowEventMethod newMethod = new AnimationWindowEventMethod();
                        newMethod.name          = method.Name;
                        newMethod.parameterType = parameterType;

                        // Since AnimationEvents only stores method name, it can't handle functions with multiple overloads.
                        // Only retrieve first found function, but discard overloads.
                        int existingMethodIndex = supportedMethods.FindIndex(m => m.name == name);
                        if (existingMethodIndex != -1)
                        {
                            // The method is only ambiguous if it has a different signature to the one we saw before
                            if (supportedMethods[existingMethodIndex].parameterType != parameterType)
                            {
                                overloadedMethods.Add(name);
                            }
                        }
                        else
                        {
                            supportedMethods.Add(newMethod);
                        }
                    }
                    type = type.BaseType;
                }
            }
        }