using System; 
 | 
using System.Collections.Generic; 
 | 
using UnityEngine; 
 | 
using UnityEditor; 
 | 
using UnityEngine.UI; 
 | 
using UnityEngine.Events; 
 | 
using UnityEngine.EventSystems; 
 | 
using qtools.qhierarchy.pcomponent.pbase; 
 | 
using qtools.qhierarchy.phierarchy; 
 | 
using qtools.qhierarchy.phelper; 
 | 
using qtools.qhierarchy.pdata; 
 | 
using System.Reflection; 
 | 
using System.Collections; 
 | 
using UnityEditorInternal; 
 | 
using System.Text; 
 | 
  
 | 
namespace qtools.qhierarchy.pcomponent 
 | 
{ 
 | 
    public class QErrorComponent: QBaseComponent 
 | 
    { 
 | 
        // PRIVATE 
 | 
        private Texture2D errorIconTexture; 
 | 
        private Texture2D errorChildIconTexture; 
 | 
        private Color backgroundColor; 
 | 
        private bool showErrorOfChildren; 
 | 
        private bool showErrorTypeReferenceIsNull; 
 | 
        private bool showErrorTypeStringIsEmpty; 
 | 
        private bool showErrorIconScriptIsMissing; 
 | 
        private bool showErrorIconWhenTagIsUndefined; 
 | 
        private bool showErrorForDisabledComponents; 
 | 
        private bool showErrorIconMissingEventMethod; 
 | 
        private List<string> ignoreErrorOfMonoBehaviours; 
 | 
        private StringBuilder errorStringBuilder; 
 | 
        private int errorCount; 
 | 
  
 | 
        // CONSTRUCTOR 
 | 
        public QErrorComponent () 
 | 
        { 
 | 
            errorIconTexture = QResources.getInstance().getTexture(QTexture.QErrorIcon); 
 | 
            errorChildIconTexture = QResources.getInstance().getTexture(QTexture.QErrorChildIcon); 
 | 
            backgroundColor = QResources.getInstance().getColor(QColor.Background); 
 | 
  
 | 
            QSettings.getInstance().addEventListener(QSetting.ShowErrorIconParent             , settingsChanged); 
 | 
            QSettings.getInstance().addEventListener(QSetting.ShowErrorIconReferenceIsNull    , settingsChanged); 
 | 
            QSettings.getInstance().addEventListener(QSetting.ShowErrorIconStringIsEmpty      , settingsChanged); 
 | 
            QSettings.getInstance().addEventListener(QSetting.ShowErrorIconScriptIsMissing    , settingsChanged); 
 | 
            QSettings.getInstance().addEventListener(QSetting.ShowErrorForDisabledComponents  , settingsChanged); 
 | 
            QSettings.getInstance().addEventListener(QSetting.ShowErrorIconMissingEventMethod , settingsChanged); 
 | 
            QSettings.getInstance().addEventListener(QSetting.ShowErrorIconWhenTagOrLayerIsUndefined , settingsChanged); 
 | 
            QSettings.getInstance().addEventListener(QSetting.ShowErrorComponent              , settingsChanged); 
 | 
            QSettings.getInstance().addEventListener(QSetting.ShowErrorComponentDuringPlayMode, settingsChanged); 
 | 
            QSettings.getInstance().addEventListener(QSetting.IgnoreErrorOfMonoBehaviours     , settingsChanged); 
 | 
            settingsChanged(); 
 | 
        } 
 | 
  
 | 
        // PRIVATE 
 | 
        private void settingsChanged() 
 | 
        { 
 | 
            showErrorOfChildren = QSettings.getInstance().get<bool>(QSetting.ShowErrorIconParent); 
 | 
            showErrorTypeReferenceIsNull = QSettings.getInstance().get<bool>(QSetting.ShowErrorIconReferenceIsNull); 
 | 
            showErrorTypeStringIsEmpty = QSettings.getInstance().get<bool>(QSetting.ShowErrorIconStringIsEmpty); 
 | 
            showErrorIconScriptIsMissing = QSettings.getInstance().get<bool>(QSetting.ShowErrorIconScriptIsMissing); 
 | 
            showErrorForDisabledComponents = QSettings.getInstance().get<bool>(QSetting.ShowErrorForDisabledComponents); 
 | 
            showErrorIconMissingEventMethod = QSettings.getInstance().get<bool>(QSetting.ShowErrorIconMissingEventMethod); 
 | 
            showErrorIconWhenTagIsUndefined = QSettings.getInstance().get<bool>(QSetting.ShowErrorIconWhenTagOrLayerIsUndefined); 
 | 
            enabled = QSettings.getInstance().get<bool>(QSetting.ShowErrorComponent); 
 | 
            showComponentDuringPlayMode = QSettings.getInstance().get<bool>(QSetting.ShowErrorComponentDuringPlayMode); 
 | 
            string ignoreErrorOfMonoBehavioursString = QSettings.getInstance().get<string>(QSetting.IgnoreErrorOfMonoBehaviours); 
 | 
            if (ignoreErrorOfMonoBehavioursString != "")  
 | 
            { 
 | 
                ignoreErrorOfMonoBehaviours = new List<string>(ignoreErrorOfMonoBehavioursString.Split(new char[] { ',', ';', '.', ' ' })); 
 | 
                ignoreErrorOfMonoBehaviours.RemoveAll(item => item == ""); 
 | 
            } 
 | 
            else ignoreErrorOfMonoBehaviours = null; 
 | 
        } 
 | 
  
 | 
        // DRAW 
 | 
        public override void layout(GameObject gameObject, QObjectList objectList, ref Rect rect) 
 | 
        { 
 | 
            rect.x -= 16; 
 | 
            rect.width = 16; 
 | 
        } 
 | 
  
 | 
        public override void draw(GameObject gameObject, QObjectList objectList, Rect selectionRect, Rect curRect) 
 | 
        { 
 | 
            bool errorFound = findError(gameObject, gameObject.GetComponents<MonoBehaviour>()); 
 | 
  
 | 
            EditorGUI.DrawRect(curRect, backgroundColor); 
 | 
            if (errorFound) 
 | 
            {            
 | 
                GUI.DrawTexture(curRect, errorIconTexture); 
 | 
            } 
 | 
            else if (showErrorOfChildren)  
 | 
            { 
 | 
                errorFound = findError(gameObject, gameObject.GetComponentsInChildren<MonoBehaviour>(true)); 
 | 
                if (errorFound) GUI.DrawTexture(curRect, errorChildIconTexture); 
 | 
            }             
 | 
        } 
 | 
  
 | 
        public override void eventHandler(GameObject gameObject, QObjectList objectList, Event currentEvent, Rect curRect) 
 | 
        { 
 | 
            if (currentEvent.isMouse && currentEvent.type == EventType.MouseDown && currentEvent.button == 0 && curRect.Contains(currentEvent.mousePosition)) 
 | 
            { 
 | 
                currentEvent.Use(); 
 | 
  
 | 
                errorCount = 0; 
 | 
                errorStringBuilder = new StringBuilder(); 
 | 
                findError(gameObject, gameObject.GetComponents<MonoBehaviour>(), true); 
 | 
  
 | 
                if (errorCount > 0) 
 | 
                { 
 | 
                    EditorUtility.DisplayDialog(errorCount + (errorCount == 1 ? " error was found" : " errors were found"), errorStringBuilder.ToString(), "OK"); 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
  
 | 
        // PRIVATE 
 | 
        private bool findError(GameObject gameObject, MonoBehaviour[] components, bool printError = false) 
 | 
        { 
 | 
            if (showErrorIconWhenTagIsUndefined) 
 | 
            { 
 | 
                try 
 | 
                {  
 | 
                    gameObject.tag.CompareTo(null);  
 | 
                } 
 | 
                catch  
 | 
                { 
 | 
                    if (printError) 
 | 
                    { 
 | 
                        appendErrorLine("Tag is undefined"); 
 | 
                    } 
 | 
                    else 
 | 
                    { 
 | 
                        return true; 
 | 
                    } 
 | 
                } 
 | 
  
 | 
                if (LayerMask.LayerToName(gameObject.layer).Equals(""))  
 | 
                { 
 | 
                    if (printError) 
 | 
                    { 
 | 
                        appendErrorLine("Layer is undefined"); 
 | 
                    } 
 | 
                    else 
 | 
                    { 
 | 
                        return true; 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
  
 | 
            for (int i = 0; i < components.Length; i++) 
 | 
            { 
 | 
                MonoBehaviour monoBehaviour = components[i]; 
 | 
                if (monoBehaviour == null) 
 | 
                { 
 | 
                    if (showErrorIconScriptIsMissing) 
 | 
                    { 
 | 
                        if (printError) 
 | 
                        { 
 | 
                            appendErrorLine("Component #" + i + " is missing"); 
 | 
                        } 
 | 
                        else 
 | 
                        { 
 | 
                            return true; 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    if (ignoreErrorOfMonoBehaviours != null) 
 | 
                    { 
 | 
                        for (int j = ignoreErrorOfMonoBehaviours.Count - 1; j >= 0; j--) 
 | 
                        { 
 | 
                            if (monoBehaviour.GetType().FullName.Contains(ignoreErrorOfMonoBehaviours[j])) 
 | 
                            { 
 | 
                                return false; 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
  
 | 
                    if (showErrorIconMissingEventMethod) 
 | 
                    { 
 | 
                        if (monoBehaviour.gameObject.activeSelf || showErrorForDisabledComponents) 
 | 
                        { 
 | 
                            try 
 | 
                            { 
 | 
                                if (isUnityEventsNullOrMissing(monoBehaviour, printError)) 
 | 
                                { 
 | 
                                    return true; 
 | 
                                } 
 | 
                            } 
 | 
                            catch 
 | 
                            { 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
  
 | 
                    if (showErrorTypeReferenceIsNull || showErrorTypeStringIsEmpty) 
 | 
                    {                        
 | 
                        if (!(monoBehaviour.enabled && monoBehaviour.gameObject.activeSelf) && !showErrorForDisabledComponents) continue; 
 | 
                         
 | 
                        FieldInfo[] fieldArray = monoBehaviour.GetType().GetFields(); 
 | 
                        for (int j = 0; j < fieldArray.Length; j++) 
 | 
                        { 
 | 
                            FieldInfo field = fieldArray[j]; 
 | 
                             
 | 
                            try 
 | 
                            { 
 | 
                                if (System.Attribute.IsDefined(field, typeof(HideInInspector)) || field.IsStatic) continue; 
 | 
                                 
 | 
                                object value = field.GetValue(monoBehaviour); 
 | 
                                 
 | 
                                if (showErrorTypeReferenceIsNull && (value == null || value.Equals(null))) 
 | 
                                {            
 | 
                                    if (printError) 
 | 
                                    { 
 | 
                                        appendErrorLine(monoBehaviour.GetType().Name + "." + field.Name + ": Reference is null"); 
 | 
                                    } 
 | 
                                    else 
 | 
                                    { 
 | 
                                        return true; 
 | 
                                    } 
 | 
                                } 
 | 
                                else if (field.FieldType == typeof(string)) 
 | 
                                {                                 
 | 
                                    if (showErrorTypeStringIsEmpty && value != null && ((string)value).Equals("")) 
 | 
                                    { 
 | 
                                        if (printError) 
 | 
                                        { 
 | 
                                            appendErrorLine(monoBehaviour.GetType().Name + "." + field.Name + ": String value is empty"); 
 | 
                                        } 
 | 
                                        else 
 | 
                                        { 
 | 
                                            return true;                                  
 | 
                                        } 
 | 
                                    } 
 | 
                                } 
 | 
                                else  
 | 
                                { 
 | 
                                    if (showErrorTypeReferenceIsNull && (value is IEnumerable)) 
 | 
                                    { 
 | 
                                        foreach (var item in (IEnumerable)value) 
 | 
                                        { 
 | 
                                            if (item == null) 
 | 
                                            { 
 | 
                                                if (printError) 
 | 
                                                { 
 | 
                                                    appendErrorLine(monoBehaviour.GetType().Name + "." + field.Name + ": IEnumerable has value with null reference"); 
 | 
                                                } 
 | 
                                                else 
 | 
                                                { 
 | 
                                                    return true; 
 | 
                                                } 
 | 
                                            } 
 | 
                                        } 
 | 
                                    } 
 | 
                                } 
 | 
                            } 
 | 
                            catch 
 | 
                            { 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
            return false; 
 | 
        } 
 | 
  
 | 
        private List<string> targetPropertiesNames = new List<string>(10); 
 | 
         
 | 
        private bool isUnityEventsNullOrMissing(MonoBehaviour monoBehaviour, bool printError)  
 | 
        { 
 | 
            targetPropertiesNames.Clear(); 
 | 
            FieldInfo[] fieldArray = monoBehaviour.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);  
 | 
    
 | 
            for (int i = fieldArray.Length - 1; i >= 0; i--)  
 | 
            { 
 | 
                FieldInfo field = fieldArray[i];                     
 | 
                if (field.FieldType == typeof(UnityEvent) || field.FieldType.IsSubclassOf(typeof(UnityEvent)))  
 | 
                { 
 | 
                    targetPropertiesNames.Add(field.Name); 
 | 
                } 
 | 
            } 
 | 
             
 | 
            if (targetPropertiesNames.Count > 0)  
 | 
            { 
 | 
                SerializedObject serializedMonoBehaviour = new SerializedObject(monoBehaviour);  
 | 
                for (int i = targetPropertiesNames.Count - 1; i >= 0; i--)  
 | 
                { 
 | 
                    string targetProperty = targetPropertiesNames[i]; 
 | 
  
 | 
                    SerializedProperty property = serializedMonoBehaviour.FindProperty(targetProperty); 
 | 
                    SerializedProperty propertyRelativeArrray = property.FindPropertyRelative("m_PersistentCalls.m_Calls"); 
 | 
                     
 | 
                    for (int j = propertyRelativeArrray.arraySize - 1; j >= 0; j--) 
 | 
                    { 
 | 
                        SerializedProperty arrayElementAtIndex = propertyRelativeArrray.GetArrayElementAtIndex(j); 
 | 
  
 | 
                        SerializedProperty propertyTarget       = arrayElementAtIndex.FindPropertyRelative("m_Target"); 
 | 
                        if (propertyTarget.objectReferenceValue == null) 
 | 
                        { 
 | 
                            if (printError) 
 | 
                            { 
 | 
                                appendErrorLine(monoBehaviour.GetType().Name + ": Event object reference is null"); 
 | 
                            } 
 | 
                            else 
 | 
                            { 
 | 
                                return true; 
 | 
                            } 
 | 
                        } 
 | 
  
 | 
                        SerializedProperty propertyMethodName   = arrayElementAtIndex.FindPropertyRelative("m_MethodName"); 
 | 
                        if (string.IsNullOrEmpty(propertyMethodName.stringValue))  
 | 
                        { 
 | 
                            if (printError) 
 | 
                            { 
 | 
                                appendErrorLine(monoBehaviour.GetType().Name + ": Event handler function is not selected"); 
 | 
                                continue; 
 | 
                            } 
 | 
                            else 
 | 
                            { 
 | 
                                return true; 
 | 
                            } 
 | 
                        } 
 | 
                          
 | 
                        string argumentAssemblyTypeName = arrayElementAtIndex.FindPropertyRelative("m_Arguments").FindPropertyRelative("m_ObjectArgumentAssemblyTypeName").stringValue; 
 | 
                        System.Type argumentAssemblyType; 
 | 
                        if (!string.IsNullOrEmpty(argumentAssemblyTypeName)) argumentAssemblyType = System.Type.GetType(argumentAssemblyTypeName, false) ?? typeof(UnityEngine.Object); 
 | 
                        else argumentAssemblyType = typeof(UnityEngine.Object); 
 | 
  
 | 
                        UnityEventBase dummyEvent; 
 | 
                        System.Type propertyTypeName = System.Type.GetType(property.FindPropertyRelative("m_TypeName").stringValue, false); 
 | 
                        if (propertyTypeName == null) dummyEvent = (UnityEventBase) new UnityEvent(); 
 | 
                        else dummyEvent = Activator.CreateInstance(propertyTypeName) as UnityEventBase; 
 | 
  
 | 
                        if (!UnityEventDrawer.IsPersistantListenerValid(dummyEvent, propertyMethodName.stringValue, propertyTarget.objectReferenceValue, (PersistentListenerMode)arrayElementAtIndex.FindPropertyRelative("m_Mode").enumValueIndex, argumentAssemblyType)) 
 | 
                        {  
 | 
                            if (printError) 
 | 
                            { 
 | 
                                appendErrorLine(monoBehaviour.GetType().Name + ": Event handler function is missing"); 
 | 
                            } 
 | 
                            else 
 | 
                            { 
 | 
                                return true; 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
                }    
 | 
            }             
 | 
            return false; 
 | 
        } 
 | 
  
 | 
        private void appendErrorLine(string error) 
 | 
        { 
 | 
            errorCount++; 
 | 
            errorStringBuilder.Append(errorCount.ToString()); 
 | 
            errorStringBuilder.Append(") "); 
 | 
            errorStringBuilder.AppendLine(error); 
 | 
        } 
 | 
    } 
 | 
} 
 |