Exemple #1
0
        void OnGUI()
        {
            // Frame rate tracking
            if (Event.current.type == EventType.Repaint)
            {
                AnimationHelper.UpdateTime();
            }

            GUILayout.Space(9);

            SidekickSettings settings = Settings;


            EditorGUI.BeginChangeCheck();
            InspectionConnection newConnectionMode = (InspectionConnection)GUILayout.Toolbar((int)settings.InspectionConnection, new string[] { "Local", "Remote" }, new GUIStyle("LargeButton"));

            if (EditorGUI.EndChangeCheck())
            {
                SetConnectionMode(newConnectionMode);
            }

            settings.SearchTerm = searchField2.OnGUI(settings.SearchTerm);
            GUILayout.Space(3);
            EditorGUI.BeginChangeCheck();

            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("Display");
            settings.GetGameObjectFlags = SidekickEditorGUI.EnumFlagsToggle(settings.GetGameObjectFlags, InfoFlags.Fields, "Fields");
            settings.GetGameObjectFlags = SidekickEditorGUI.EnumFlagsToggle(settings.GetGameObjectFlags, InfoFlags.Properties, "Properties");
            settings.GetGameObjectFlags = SidekickEditorGUI.EnumFlagsToggle(settings.GetGameObjectFlags, InfoFlags.Methods, "Methods");
            EditorGUILayout.EndHorizontal();

            if (EditorGUI.EndChangeCheck())
            {
                if (!string.IsNullOrEmpty(SelectionManager.SelectedPath)) // Valid path?
                {
                    APIManager.SendToPlayers(new GetGameObjectRequest(SelectionManager.SelectedPath, Settings.GetGameObjectFlags, Settings.IncludeInherited));
                }
            }

            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

            if (gameObjectResponse != null)
            {
                string activeSearchTerm = settings.SearchTerm;

                foreach (ComponentDescription component in gameObjectResponse.Components)
                {
                    SidekickEditorGUI.DrawSplitter();
                    GUIStyle style = new GUIStyle(EditorStyles.foldout);
                    style.fontStyle = FontStyle.Bold;

                    Texture    icon    = IconLookup.GetIcon(component.TypeFullName);
                    GUIContent content = new GUIContent(component.TypeShortName, icon, "Object Map ID: " + component.Guid.ToString());

                    float labelWidth = EditorGUIUtility.labelWidth; // Cache label width
                    // Temporarily set the label width to full width so the icon is not squashed with long strings
                    EditorGUIUtility.labelWidth = position.width / 2f;

                    bool wasComponentExpanded = !settings.CollapsedTypeNames.Contains(component.TypeFullName);
                    bool isComponentExpanded  = wasComponentExpanded;


                    bool?activeOrEnabled = null;
                    if (component.TypeShortName == "GameObject" && (settings.GetGameObjectFlags & InfoFlags.Properties) != 0)
                    {
                        activeOrEnabled = (bool)component.Scopes[0].GetPropertyValue("activeSelf");
                    }
                    else
                    {
                        ComponentScope behaviourScope = component.BehaviourScope;
                        if (behaviourScope != null && (settings.GetGameObjectFlags & InfoFlags.Properties) != 0)
                        {
                            activeOrEnabled = (bool)behaviourScope.GetPropertyValue("enabled");
                        }
                    }

                    bool?oldActiveOrEnabled = activeOrEnabled;

                    if (SidekickEditorGUI.DrawHeaderWithFoldout(content, isComponentExpanded, ref activeOrEnabled))
                    {
                        isComponentExpanded = !isComponentExpanded;
                    }

                    if (activeOrEnabled.HasValue && activeOrEnabled != oldActiveOrEnabled)
                    {
                        if (component.TypeShortName == "GameObject")
                        {
                            // Update local cache (requires method call)
                            var property = component.Scopes[0].GetProperty("activeSelf");
                            property.Value = activeOrEnabled.Value;

                            // Update via method call
                            APIManager.SendToPlayers(new InvokeMethodRequest(component.Guid, "SetActive", new WrappedVariable[] { new WrappedVariable("", activeOrEnabled.Value, typeof(bool), false) }));
                        }
                        else if (component.BehaviourScope != null)
                        {
                            // Update local cache, then ship via SetVariable
                            var property = component.BehaviourScope.GetProperty("enabled");
                            property.Value = activeOrEnabled.Value;

                            APIManager.SendToPlayers(new SetVariableRequest(component.Guid, property));
                        }
                    }
                    EditorGUIUtility.labelWidth = labelWidth; // Restore label width
                    if (isComponentExpanded != wasComponentExpanded)
                    {
                        if (isComponentExpanded == false)
                        {
                            // Not expanded, so collapse it
                            settings.CollapsedTypeNames.Add(component.TypeFullName);
                        }
                        else
                        {
                            // Expanded, remove it from collapse list
                            settings.CollapsedTypeNames.Remove(component.TypeFullName);
                        }
                    }

                    if (isComponentExpanded)
                    {
                        foreach (ComponentScope scope in component.Scopes)
                        {
                            if (scope.TypeFullName != component.TypeFullName)
                            {
                                SidekickEditorGUI.DrawHeader2(new GUIContent(": " + scope.TypeShortName));
                            }

                            ObjectPickerContext objectPickerContext = new ObjectPickerContext(component.Guid);
                            foreach (var field in scope.Fields)
                            {
                                if (!string.IsNullOrEmpty(activeSearchTerm) && !field.VariableName.Contains(activeSearchTerm, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    // Active search term not matched, skip it
                                    continue;
                                }

                                if (settings.IgnoreObsolete && (field.Attributes & VariableAttributes.Obsolete) == VariableAttributes.Obsolete)
                                {
                                    // Skip obsolete entries if that setting is enabled
                                    continue;
                                }
                                EditorGUI.BeginChangeCheck();
                                object newValue = VariableDrawer.Draw(objectPickerContext, field, OnOpenObjectPicker);
                                if (EditorGUI.EndChangeCheck() && (field.Attributes & VariableAttributes.ReadOnly) == VariableAttributes.None && field.DataType != DataType.Unknown)
                                {
                                    if (newValue != field.Value || field.Attributes.HasFlagByte(VariableAttributes.IsList) || field.Attributes.HasFlagByte(VariableAttributes.IsArray))
                                    {
                                        field.Value = newValue;
                                        APIManager.SendToPlayers(new SetVariableRequest(component.Guid, field));
                                    }

                                    //Debug.Log("Value changed in " + field.VariableName);
                                }
                            }
                            foreach (var property in scope.Properties)
                            {
                                if (!string.IsNullOrEmpty(activeSearchTerm) && !property.VariableName.Contains(activeSearchTerm, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    // Active search term not matched, skip it
                                    continue;
                                }

                                if (settings.IgnoreObsolete && (property.Attributes & VariableAttributes.Obsolete) == VariableAttributes.Obsolete)
                                {
                                    // Skip obsolete entries if that setting is enabled
                                    continue;
                                }

                                EditorGUI.BeginChangeCheck();
                                object newValue = VariableDrawer.Draw(objectPickerContext, property, OnOpenObjectPicker);
                                if (EditorGUI.EndChangeCheck() && (property.Attributes & VariableAttributes.ReadOnly) == VariableAttributes.None && property.DataType != DataType.Unknown)
                                {
                                    if (newValue != property.Value || property.Attributes.HasFlagByte(VariableAttributes.IsList) || property.Attributes.HasFlagByte(VariableAttributes.IsArray))
                                    {
                                        property.Value = newValue;
                                        APIManager.SendToPlayers(new SetVariableRequest(component.Guid, property));
                                    }
                                    //Debug.Log("Value changed in " + property.VariableName);
                                }
                            }

                            GUIStyle   expandButtonStyle = new GUIStyle(GUI.skin.button);
                            RectOffset padding           = expandButtonStyle.padding;
                            padding.left              = 0;
                            padding.right             = 1;
                            expandButtonStyle.padding = padding;

                            GUIStyle labelStyle = new GUIStyle(GUI.skin.label);
                            labelStyle.alignment = TextAnchor.MiddleRight;
                            GUIStyle normalButtonStyle = new GUIStyle(GUI.skin.button);
                            normalButtonStyle.padding   = normalButtonStyle.padding.SetLeft(100);
                            normalButtonStyle.alignment = TextAnchor.MiddleLeft;

                            foreach (var method in scope.Methods)
                            {
                                if (!string.IsNullOrEmpty(activeSearchTerm) && !method.MethodName.Contains(activeSearchTerm, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    // Active search term not matched, skip it
                                    continue;
                                }

                                if (settings.IgnoreObsolete && (method.MethodAttributes & MethodAttributes.Obsolete) == MethodAttributes.Obsolete)
                                {
                                    // Skip obsolete entries if that setting is enabled
                                    continue;
                                }

                                if (method.SafeToFire == false)
                                {
                                    EditorGUI.BeginDisabledGroup(true);
                                }

                                GUILayout.BeginHorizontal();
                                if (method.ReturnType == DataType.Void)
                                {
                                    labelStyle.normal.textColor = Color.grey;
                                }
                                else if ((method.ReturnTypeAttributes & VariableAttributes.IsValueType) == VariableAttributes.IsValueType)
                                {
                                    labelStyle.normal.textColor = new Color(0, 0, 1);
                                }
                                else
                                {
                                    labelStyle.normal.textColor = new Color32(255, 130, 0, 255);
                                }

                                string displayText = method.MethodName + " (" + method.ParameterCount + ")";

                                if ((method.MethodAttributes & MethodAttributes.Static) == MethodAttributes.Static)
                                {
                                    displayText += " [Static]";
                                }

                                if (method.SafeToFire == false)
                                {
                                    displayText += " [Unsupported]";
                                }

                                bool wasMethodExpanded = (method.Equals(expandedMethod));

                                if (GUILayout.Button(displayText, normalButtonStyle))
                                {
                                    if (wasMethodExpanded)
                                    {
                                        APIManager.SendToPlayers(new InvokeMethodRequest(component.Guid, method.MethodName, arguments.ToArray()));
                                    }
                                    else
                                    {
                                        // Not expanded, just use the default values
                                        List <WrappedVariable> defaultArguments = new List <WrappedVariable>();

                                        for (int i = 0; i < method.ParameterCount; i++)
                                        {
                                            WrappedParameter parameter = method.Parameters[i];
                                            defaultArguments.Add(new WrappedVariable(parameter));
                                        }

                                        APIManager.SendToPlayers(new InvokeMethodRequest(component.Guid, method.MethodName, defaultArguments.ToArray()));
                                    }
                                }

                                Rect lastRect = GUILayoutUtility.GetLastRect();
                                lastRect.xMax = normalButtonStyle.padding.left;
                                GUI.Label(lastRect, TypeUtility.NameForType(method.ReturnType), labelStyle);

                                if (method.ParameterCount > 0)
                                {
                                    bool isMethodExpanded = GUILayout.Toggle(wasMethodExpanded, "▼", expandButtonStyle, GUILayout.Width(20));
                                    GUILayout.EndHorizontal();

                                    if (isMethodExpanded != wasMethodExpanded) // has changed
                                    {
                                        if (isMethodExpanded)
                                        {
                                            // Reset the keyboard control as we don't want old text carrying over
                                            GUIUtility.keyboardControl = 0;

                                            expandedMethod = method;
                                            arguments      = new List <WrappedVariable>(method.ParameterCount);
                                            for (int i = 0; i < method.ParameterCount; i++)
                                            {
                                                WrappedParameter parameter = method.Parameters[i];
                                                arguments.Add(new WrappedVariable(parameter));
                                            }
                                        }
                                        else
                                        {
                                            expandedMethod = null;
                                            arguments      = null;
                                        }
                                    }
                                    else if (isMethodExpanded)
                                    {
                                        EditorGUI.indentLevel++;
                                        for (int i = 0; i < arguments.Count; i++)
                                        {
                                            var argument = arguments[i];
                                            argument.Value = VariableDrawer.Draw(new ObjectPickerContext(i), argument, OnOpenObjectPicker);
                                            //argument.Value = VariableDrawer.DrawIndividualVariable(null, argument, argument.VariableName, DataTypeHelper.GetSystemTypeFromWrappedDataType(argument.DataType), argument.Value, OnOpenObjectPicker);
                                        }

                                        //Rect buttonRect = GUILayoutUtility.GetRect(new GUIContent(), GUI.skin.button);
                                        //buttonRect = EditorGUI.IndentedRect(buttonRect);


                                        EditorGUI.indentLevel--;

                                        GUILayout.Space(10);
                                    }
                                }
                                else
                                {
                                    GUILayout.EndHorizontal();
                                }

                                if (method.SafeToFire == false)
                                {
                                    EditorGUI.EndDisabledGroup();
                                }
                            }
                        }
                    }
                }
                SidekickEditorGUI.DrawSplitter();
            }
            EditorGUILayout.EndScrollView();

            DrawOutputBox();
        }
Exemple #2
0
        void OnGUI()
        {
            // Frame rate tracking
            if (Event.current.type == EventType.Repaint)
            {
                AnimationHelper.UpdateTime();
            }

            current = this;
            // Make sure we have a valid set of assemblies
            if (assemblies == null || assemblies.Count == 0)
            {
                ConstructAssembliesAndTypes();
            }

            Rect windowRect = position;

            Type[]   inspectedTypes    = null;
            object[] inspectedContexts = null;

            GUILayout.Space(9);

            inspectedType = SidekickUtility.EnumToolbar(inspectedType, "LargeButton");//, GUILayout.Width(windowRect.width - 60));

            if (inspectedType == InspectedType.Selection)
            {
                object selectedObject = ActiveSelection;

                if (selectedObject == null)
                {
                    GUILayout.Space(windowRect.height / 2 - 40);
                    GUIStyle style = new GUIStyle(GUI.skin.label);
                    style.alignment = TextAnchor.MiddleCenter;
                    GUILayout.Label("No object selected", style);
                    return;
                }

                if (selectedObject is GameObject)
                {
                    List <object> components = ((GameObject)selectedObject).GetComponents <Component>().Cast <object>().ToList();
                    components.RemoveAll(item => item == null);
                    components.Insert(0, selectedObject);
                    inspectedContexts = components.ToArray();
                }
                else
                {
                    inspectedContexts = new object[] { selectedObject };
                }
                inspectedTypes = inspectedContexts.Select(x => x.GetType()).ToArray();
            }
            else if (inspectedType == InspectedType.AssemblyClass)
            {
                int newSelectedAssemblyIndex = EditorGUILayout.Popup(selectedAssemblyIndex, assemblyNames);
                if (newSelectedAssemblyIndex != selectedAssemblyIndex)
                {
                    selectedTypeIndex     = 0;
                    selectedAssemblyIndex = newSelectedAssemblyIndex;
                }

                Assembly    activeAssembly = assemblies[selectedAssemblyIndex];
                List <Type> types          = assemblyTypes[activeAssembly];
                string[]    typeNames      = new string[types.Count];
                for (int i = 0; i < types.Count; i++)
                {
                    typeNames[i] = types[i].FullName;
                }
                selectedTypeIndex = EditorGUILayout.Popup(selectedTypeIndex, typeNames);

                inspectedTypes    = new Type[] { assemblyTypes[activeAssembly][selectedTypeIndex] };
                inspectedContexts = new Type[] { null };
            }
            else if (inspectedType == InspectedType.Remote)
            {
            }
            else
            {
                throw new NotImplementedException("Unhandled InspectedType");
            }

            GUILayout.Space(5);
            EditorGUILayout.BeginHorizontal();
            GUIStyle searchStyle   = GUI.skin.FindStyle("ToolbarSeachTextField");
            GUIStyle cancelStyle   = GUI.skin.FindStyle("ToolbarSeachCancelButton");
            GUIStyle noCancelStyle = GUI.skin.FindStyle("ToolbarSeachCancelButtonEmpty");

            GUILayout.Space(10);
            settings.SearchTerm = EditorGUILayout.TextField(settings.SearchTerm, searchStyle);
            if (!string.IsNullOrEmpty(settings.SearchTerm))
            {
                if (GUILayout.Button("", cancelStyle))
                {
                    settings.SearchTerm               = "";
                    GUIUtility.hotControl             = 0;
                    EditorGUIUtility.editingTextField = false;
                }
            }
            else
            {
                GUILayout.Button("", noCancelStyle);
            }
            GUILayout.Space(10);
            EditorGUILayout.EndHorizontal();
            GUILayout.Space(5);
            mode = SidekickUtility.EnumToolbar(mode);
            //			mode = SabreGUILayout.DrawEnumGrid(mode);

            GUILayout.Space(5);
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

            for (int i = 0; i < inspectedTypes.Length; i++)
            {
                Type type = inspectedTypes[i];
                if (!typesHidden.Any(row => row.Key == type))// ContainsKey(component))
                {
                    typesHidden.Add(new KeyValuePair <Type, bool>(type, false));
                }


                int index = typesHidden.FindIndex(row => row.Key == type);

                GUIStyle style = new GUIStyle(EditorStyles.foldout);
                style.fontStyle = FontStyle.Bold;
                //				Texture2D icon = AssetPreview.GetMiniTypeThumbnail(type);
                GUIContent objectContent = EditorGUIUtility.ObjectContent(inspectedContexts[i] as UnityEngine.Object, type);
                Texture2D  icon          = objectContent.image as Texture2D;
                GUIContent content       = new GUIContent(type.Name, icon);

                bool newValue = !EditorGUILayout.Foldout(!typesHidden[index].Value, content, style);

                if (newValue != typesHidden[index].Value)
                {
                    typesHidden[index] = new KeyValuePair <Type, bool>(type, newValue);
                }
                if (!typesHidden[index].Value)
                {
                    EditorGUI.indentLevel = 1;

                    BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
                    if (!settings.IncludeInherited)
                    {
                        bindingFlags |= BindingFlags.DeclaredOnly;
                    }

                    FieldInfo[]    fields     = type.GetFields(bindingFlags);
                    PropertyInfo[] properties = type.GetProperties(bindingFlags);
                    MethodInfo[]   methods    = type.GetMethods(bindingFlags);

                    // Hide methods and backing fields that have been generated for properties
                    if (settings.HideAutoGenerated)
                    {
                        List <MethodInfo> methodList = new List <MethodInfo>(methods.Length);

                        for (int j = 0; j < methods.Length; j++)
                        {
                            if (!TypeUtility.IsPropertyMethod(methods[j], type))
                            {
                                methodList.Add(methods[j]);
                            }
                        }
                        methods = methodList.ToArray();

                        List <FieldInfo> fieldList = new List <FieldInfo>(fields.Length);

                        for (int j = 0; j < fields.Length; j++)
                        {
                            if (!TypeUtility.IsBackingField(fields[j], type))
                            {
                                fieldList.Add(fields[j]);
                            }
                        }
                        fields = fieldList.ToArray();
                    }


                    FieldInfo[] events = type.GetFields(bindingFlags);

                    if (mode == InspectorMode.Fields)
                    {
                        fieldPane.DrawFields(inspectedTypes[i], inspectedContexts[i], fields);
                    }
                    else if (mode == InspectorMode.Props)
                    {
                        propertyPane.DrawProperties(inspectedTypes[i], inspectedContexts[i], properties);
                    }
                    else if (mode == InspectorMode.Methods)
                    {
                        methodPane.DrawMethods(inspectedTypes[i], inspectedContexts[i], methods);
                    }
                    else if (mode == InspectorMode.Events)
                    {
                        eventPane.DrawEvents(inspectedTypes[i], inspectedContexts[i], events);
                    }
                    else if (mode == InspectorMode.Misc)
                    {
                        utilityPane.Draw(inspectedTypes[i], inspectedContexts[i]);
                    }

                    EditorGUI.indentLevel = 0;
                }

                Rect rect = GUILayoutUtility.GetRect(new GUIContent(), GUI.skin.label, GUILayout.ExpandWidth(true), GUILayout.Height(1));
                rect.xMin -= 10;
                rect.xMax += 10;
                GUI.color  = new Color(0.5f, 0.5f, 0.5f);
                GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
                GUI.color = Color.white;
            }

            EditorGUILayout.EndScrollView();

            if (mode == InspectorMode.Methods)
            {
                methodPane.PostDraw();
            }

            settings.RotationsAsEuler  = EditorGUILayout.Toggle("Rotations as euler", settings.RotationsAsEuler);
            settings.IncludeInherited  = EditorGUILayout.Toggle("Include inherited", settings.IncludeInherited);
            settings.HideAutoGenerated = EditorGUILayout.Toggle("Hide auto-generated", settings.HideAutoGenerated);
            settings.TreatEnumsAsInts  = EditorGUILayout.Toggle("Enums as ints", settings.TreatEnumsAsInts);

            EditorGUILayout.BeginHorizontal();
            GUI.enabled = (backStack.Count > 0);
            if (GUILayout.Button("<-") ||
                (Event.current.type == EventType.MouseDown && Event.current.button == 3) ||
                (Event.current.type == EventType.KeyDown && SidekickUtility.EventsMatch(Event.current, Event.KeyboardEvent("Backspace"), false, true)))
            {
                object backStackLast = backStack.Last();
                backStack.RemoveAt(backStack.Count - 1);
                forwardStack.Add(ActiveSelection);
                SetSelection(backStackLast, false);
            }
            GUI.enabled = (forwardStack.Count > 0);
            if (GUILayout.Button("->") ||
                (Event.current.type == EventType.MouseDown && Event.current.button == 4) ||
                (Event.current.type == EventType.KeyDown && SidekickUtility.EventsMatch(Event.current, Event.KeyboardEvent("#Backspace"), false, true)))
            {
                object forwardStackLast = forwardStack.Last();
                forwardStack.RemoveAt(forwardStack.Count - 1);
                backStack.Add(ActiveSelection);
                SetSelection(forwardStackLast, false);
            }
            GUI.enabled = true;

            if (GUILayout.Button("Pin"))
            {
                selectionOverride = ActiveSelection;
            }

            EditorGUILayout.EndHorizontal();
            //			test += currentFrameDelta;
            //			Color color = Color.Lerp(Color.white, Color.red, Mathf.PingPong(test, 1f));
            //			GUI.backgroundColor = color;
            //			GUILayout.Button(Mathf.PingPong(test, 1f).ToString());//test.ToString());

            //			if(AnimationHelper.AnimationActive)
            {
                // Cause repaint on next frame
                Repaint();
                if (Event.current.type == EventType.Repaint)
                {
                    //					AnimationHelper.ClearAnimationActive();
                }
            }
        }
        void OnGUI()
        {
            // Frame rate tracking
            if (Event.current.type == EventType.Repaint)
            {
                AnimationHelper.UpdateTime();
            }

            GUILayout.Space(9);

            SidekickSettings settings = commonContext.Settings;


            EditorGUI.BeginChangeCheck();
            InspectionConnection newConnectionMode = (InspectionConnection)GUILayout.Toolbar((int)settings.InspectionConnection, new string[] { "Local", "Remote" }, new GUIStyle("LargeButton"));

            if (EditorGUI.EndChangeCheck())
            {
                SetConnectionMode(newConnectionMode);
            }

            settings.SearchTerm = searchField2.OnGUI(settings.SearchTerm);
            GUILayout.Space(3);
            EditorGUI.BeginChangeCheck();
#if UNITY_2017_3_OR_NEWER
            // EnumMaskField became EnumFlagsField in 2017.3
            settings.GetGameObjectFlags = (InfoFlags)EditorGUILayout.EnumFlagsField("Display", settings.GetGameObjectFlags);
#else
            settings.GetGameObjectFlags = (InfoFlags)EditorGUILayout.EnumMaskField("Display", settings.GetGameObjectFlags);
#endif
            if (EditorGUI.EndChangeCheck())
            {
                if (!string.IsNullOrEmpty(commonContext.SelectionManager.SelectedPath)) // Valid path?
                {
                    commonContext.APIManager.SendToPlayers(new GetGameObjectRequest(commonContext.SelectionManager.SelectedPath, commonContext.Settings.GetGameObjectFlags, commonContext.Settings.IncludeInherited));
                }
            }

            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

            if (gameObjectResponse != null)
            {
                string activeSearchTerm = settings.SearchTerm;

                foreach (ComponentDescription component in gameObjectResponse.Components)
                {
                    SidekickEditorGUI.DrawSplitter();
                    GUIStyle style = new GUIStyle(EditorStyles.foldout);
                    style.fontStyle = FontStyle.Bold;

                    Texture    icon       = IconLookup.GetIcon(component.TypeFullName);
                    GUIContent content    = new GUIContent(component.TypeShortName, icon, "Object Map ID: " + component.Guid.ToString());
                    float      labelWidth = EditorGUIUtility.labelWidth; // Cache label width
                    // Temporarily set the label width to full width so the icon is not squashed with long strings
                    EditorGUIUtility.labelWidth = position.width / 2f;

                    bool wasComponentExpanded = !settings.CollapsedTypeNames.Contains(component.TypeFullName);
                    bool isComponentExpanded  = wasComponentExpanded;
                    if (SidekickEditorGUI.DrawHeaderWithFoldout(content, isComponentExpanded))
                    {
                        isComponentExpanded = !isComponentExpanded;
                    }
                    EditorGUIUtility.labelWidth = labelWidth; // Restore label width
                    if (isComponentExpanded != wasComponentExpanded)
                    {
                        if (isComponentExpanded == false)
                        {
                            // Not expanded, so collapse it
                            settings.CollapsedTypeNames.Add(component.TypeFullName);
                        }
                        else
                        {
                            // Expanded, remove it from collapse list
                            settings.CollapsedTypeNames.Remove(component.TypeFullName);
                        }
                    }

                    if (isComponentExpanded)
                    {
                        foreach (var field in component.Fields)
                        {
                            if (!string.IsNullOrEmpty(activeSearchTerm) && !field.VariableName.Contains(activeSearchTerm, StringComparison.InvariantCultureIgnoreCase))
                            {
                                // Active search term not matched, skip it
                                continue;
                            }

                            if (settings.IgnoreObsolete && (field.Attributes & VariableAttributes.Obsolete) == VariableAttributes.Obsolete)
                            {
                                // Skip obsolete entries if that setting is enabled
                                continue;
                            }
                            EditorGUI.BeginChangeCheck();
                            object newValue = VariableDrawer.Draw(component, field, OnOpenObjectPicker);
                            if (EditorGUI.EndChangeCheck() && (field.Attributes & VariableAttributes.ReadOnly) == VariableAttributes.None && field.DataType != DataType.Unknown)
                            {
                                if (newValue != field.Value)
                                {
                                    field.Value = newValue;
                                    commonContext.APIManager.SendToPlayers(new SetVariableRequest(component.Guid, field));
                                }

                                //Debug.Log("Value changed in " + field.VariableName);
                            }
                        }
                        foreach (var property in component.Properties)
                        {
                            if (!string.IsNullOrEmpty(activeSearchTerm) && !property.VariableName.Contains(activeSearchTerm, StringComparison.InvariantCultureIgnoreCase))
                            {
                                // Active search term not matched, skip it
                                continue;
                            }

                            if (settings.IgnoreObsolete && (property.Attributes & VariableAttributes.Obsolete) == VariableAttributes.Obsolete)
                            {
                                // Skip obsolete entries if that setting is enabled
                                continue;
                            }

                            EditorGUI.BeginChangeCheck();
                            object newValue = VariableDrawer.Draw(component, property, OnOpenObjectPicker);
                            if (EditorGUI.EndChangeCheck() && (property.Attributes & VariableAttributes.ReadOnly) == VariableAttributes.None && property.DataType != DataType.Unknown)
                            {
                                if (newValue != property.Value)
                                {
                                    property.Value = newValue;
                                    commonContext.APIManager.SendToPlayers(new SetVariableRequest(component.Guid, property));
                                }
                                //Debug.Log("Value changed in " + property.VariableName);
                            }
                        }

                        GUIStyle   expandButtonStyle = new GUIStyle(GUI.skin.button);
                        RectOffset padding           = expandButtonStyle.padding;
                        padding.left              = 0;
                        padding.right             = 1;
                        expandButtonStyle.padding = padding;

                        GUIStyle labelStyle = new GUIStyle(GUI.skin.label);
                        labelStyle.alignment = TextAnchor.MiddleRight;
                        GUIStyle normalButtonStyle = new GUIStyle(GUI.skin.button);
                        normalButtonStyle.padding   = normalButtonStyle.padding.SetLeft(100);
                        normalButtonStyle.alignment = TextAnchor.MiddleLeft;

                        foreach (var method in component.Methods)
                        {
                            if (!string.IsNullOrEmpty(activeSearchTerm) && !method.MethodName.Contains(activeSearchTerm, StringComparison.InvariantCultureIgnoreCase))
                            {
                                // Active search term not matched, skip it
                                continue;
                            }

                            if (settings.IgnoreObsolete && (method.MethodAttributes & MethodAttributes.Obsolete) == MethodAttributes.Obsolete)
                            {
                                // Skip obsolete entries if that setting is enabled
                                continue;
                            }

                            GUILayout.BeginHorizontal();
                            if (method.ReturnType == DataType.Void)
                            {
                                labelStyle.normal.textColor = Color.grey;
                            }
                            else if ((method.ReturnTypeAttributes & VariableAttributes.IsValueType) == VariableAttributes.IsValueType)
                            {
                                labelStyle.normal.textColor = new Color(0, 0, 1);
                            }
                            else
                            {
                                labelStyle.normal.textColor = new Color32(255, 130, 0, 255);
                            }

                            string displayText = method.MethodName + " (" + method.ParameterCount + ")";

                            if ((method.MethodAttributes & MethodAttributes.Static) == MethodAttributes.Static)
                            {
                                displayText += " [Static]";
                            }

                            if (GUILayout.Button(displayText, normalButtonStyle))
                            {
                                List <WrappedVariable> defaultArguments = new List <WrappedVariable>();

                                for (int i = 0; i < method.ParameterCount; i++)
                                {
                                    //Type type = DataTypeHelper.GetSystemTypeFromWrappedDataType(method.Parameters[i].DataType);

                                    WrappedParameter parameter = method.Parameters[i];
                                    defaultArguments.Add(new WrappedVariable(parameter));
                                }

                                commonContext.APIManager.SendToPlayers(new InvokeMethodRequest(component.Guid, method.MethodName, defaultArguments.ToArray()));
                            }

                            Rect lastRect = GUILayoutUtility.GetLastRect();
                            lastRect.xMax = normalButtonStyle.padding.left;
                            GUI.Label(lastRect, TypeUtility.NameForType(method.ReturnType), labelStyle);

                            if (method.ParameterCount > 0)
                            {
                                bool wasMethodExpanded = (method.Equals(expandedMethod));
                                bool isMethodExpanded  = GUILayout.Toggle(wasMethodExpanded, "▼", expandButtonStyle, GUILayout.Width(20));
                                GUILayout.EndHorizontal();

                                if (isMethodExpanded != wasMethodExpanded)                                 // has changed
                                {
                                    if (isMethodExpanded)
                                    {
                                        expandedMethod = method;
                                        arguments      = new List <WrappedVariable>(method.ParameterCount);
                                        for (int i = 0; i < method.ParameterCount; i++)
                                        {
                                            WrappedParameter parameter = method.Parameters[i];
                                            arguments.Add(new WrappedVariable(parameter));
                                        }
                                    }
                                    else
                                    {
                                        expandedMethod = null;
                                        arguments      = null;
                                    }
                                }
                                else if (isMethodExpanded)
                                {
                                    EditorGUI.indentLevel++;
                                    foreach (var argument in arguments)
                                    {
                                        argument.Value = VariableDrawer.Draw(null, argument, OnOpenObjectPicker);
                                        //argument.Value = VariableDrawer.DrawIndividualVariable(null, argument, argument.VariableName, DataTypeHelper.GetSystemTypeFromWrappedDataType(argument.DataType), argument.Value, OnOpenObjectPicker);
                                    }

                                    Rect buttonRect = GUILayoutUtility.GetRect(new GUIContent(), GUI.skin.button);
                                    buttonRect = EditorGUI.IndentedRect(buttonRect);

                                    if (GUI.Button(buttonRect, "Fire"))
                                    {
                                        commonContext.APIManager.SendToPlayers(new InvokeMethodRequest(component.Guid, method.MethodName, arguments.ToArray()));
                                    }
                                    EditorGUI.indentLevel--;

                                    GUILayout.Space(10);
                                }
                            }
                            else
                            {
                                GUILayout.EndHorizontal();
                            }
                        }
                    }
                }
                SidekickEditorGUI.DrawSplitter();
            }
            EditorGUILayout.EndScrollView();

            DrawOutputBox();
        }
        void OnGUI()
        {
            // Flexible width for the label based on overall width
            EditorGUIUtility.labelWidth = Mathf.Round(EditorGUIUtility.currentViewWidth * 0.4f);
            // Use inline controls if there is enough horizontal room
            EditorGUIUtility.wideMode = EditorGUIUtility.currentViewWidth > 400;

            // Frame rate tracking
            if (Event.current.type == EventType.Repaint)
            {
                AnimationHelper.UpdateTime();
            }

            current = this;

            CleanStacks();

            DrawToolbar();

            Type[]       inspectedTypes       = null;
            object[]     inspectedContexts    = null;
            ECSContext[] inspectedECSContexts = null;

            GUILayout.Space(9);

            string buttonPrefix = "";

#if ECS_EXISTS
            int selectionWrapWidth = 465;
#else
            int selectionWrapWidth = 400;
#endif
            if (EditorGUIUtility.currentViewWidth > selectionWrapWidth)
            {
                EditorGUILayout.BeginHorizontal();
                GUILayout.Label("Selection Helpers");
            }
            else
            {
                buttonPrefix = "Select ";
            }

            var popupRect = GUILayoutUtility.GetLastRect();
            popupRect.width = EditorGUIUtility.currentViewWidth;

            if (GUILayout.Button(new GUIContent(buttonPrefix + "Type From Assembly"), EditorStyles.miniButton))
            {
                TypeSelectDropdown dropdown = new TypeSelectDropdown(new AdvancedDropdownState(), SetSelection);
                dropdown.Show(popupRect);
            }

            if (GUILayout.Button(new GUIContent(buttonPrefix + "Loaded Unity Object"), EditorStyles.miniButton))
            {
                UnityObjectSelectDropdown dropdown = new UnityObjectSelectDropdown(new AdvancedDropdownState(), SetSelection);
                dropdown.Show(popupRect);
            }

#if ECS_EXISTS
            if (GUILayout.Button(new GUIContent(buttonPrefix + "ECS System"), EditorStyles.miniButton))
            {
                ECSSystemSelectDropdown dropdown = new ECSSystemSelectDropdown(new AdvancedDropdownState(), SetSelection);
                dropdown.Show(popupRect);
            }
#endif

            if (EditorGUIUtility.currentViewWidth > selectionWrapWidth)
            {
                EditorGUILayout.EndHorizontal();
            }

            if (activeSelection.IsEmpty)
            {
                GUILayout.FlexibleSpace();
                GUIStyle style = new GUIStyle(EditorStyles.wordWrappedLabel)
                {
                    alignment = TextAnchor.MiddleCenter
                };
                GUILayout.Label("No object selected.\n\nSelect something in Unity or use one of the selection helper buttons.", style);
                GUILayout.FlexibleSpace();
                return;
            }

            if (activeSelection.Object != null)
            {
                if (activeSelection.Object is GameObject selectedGameObject)
                {
                    List <object> components = selectedGameObject.GetComponents <Component>().Cast <object>().ToList();
                    components.RemoveAll(item => item == null);
                    components.Insert(0, selectedGameObject);
                    inspectedContexts = components.ToArray();
                }
#if ECS_EXISTS
                else if (activeSelection.Object is EntitySelectionProxy entitySelectionProxy)
                {
                    EntityManager currentEntityManager = entitySelectionProxy.World.EntityManager;
                    string        name = currentEntityManager.GetName(entitySelectionProxy.Entity);

                    if (string.IsNullOrEmpty(name))
                    {
                        name = "Entity " + entitySelectionProxy.Entity.Index;
                    }

                    inspectedContexts       = new object [1 + currentEntityManager.GetComponentCount(entitySelectionProxy.Entity)];
                    inspectedContexts[0]    = activeSelection.Object;
                    inspectedECSContexts    = new ECSContext[1 + currentEntityManager.GetComponentCount(entitySelectionProxy.Entity)];
                    inspectedECSContexts[0] = new ECSContext {
                        EntityManager = currentEntityManager, Entity = entitySelectionProxy.Entity
                    };

                    NativeArray <ComponentType> types = currentEntityManager.GetComponentTypes(entitySelectionProxy.Entity);
                    for (var index = 0; index < types.Length; index++)
                    {
                        object componentData = ECSAccess.GetComponentData(currentEntityManager, entitySelectionProxy.Entity, types[index]);

                        inspectedContexts[1 + index]    = componentData;
                        inspectedECSContexts[1 + index] = new ECSContext {
                            EntityManager = currentEntityManager, Entity = entitySelectionProxy.Entity, ComponentType = types[index]
                        };
                    }

                    types.Dispose();
                }
#endif
                else
                {
                    inspectedContexts = new[] { activeSelection.Object };
                }

                inspectedTypes = inspectedContexts.Select(x => x.GetType()).ToArray();
            }
            else
            {
                inspectedTypes = new[] { activeSelection.Type };

                inspectedContexts = new Type[] { null };
            }

            if (inspectedECSContexts == null)
            {
                inspectedECSContexts = new ECSContext[inspectedContexts.Length];
            }

            GUILayout.Space(5);
            searchTerm = searchField.OnToolbarGUI(searchTerm);

            SidekickEditorGUI.BeginLabelHighlight(searchTerm);

            mode = SidekickUtility.EnumToolbar(mode);

            GUILayout.Space(5);
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

            for (int i = 0; i < inspectedTypes.Length; i++)
            {
                Type type = inspectedTypes[i];

                var inspectedContext    = inspectedContexts[i];
                var inspectedECSContext = inspectedECSContexts[i];

                bool?activeOrEnabled = inspectedContext switch
                {
                    GameObject gameObject => gameObject.activeSelf,
                    Behaviour behaviour => behaviour.enabled,
                    _ => null
                };

                if (typesHidden.All(row => row.Key != type))
                {
                    typesHidden.Add(new KeyValuePair <Type, bool>(type, false));
                }

                int index = typesHidden.FindIndex(row => row.Key == type);

                string name;
                if (inspectedContexts[0] != null)
                {
                    if (activeOrEnabled.HasValue)
                    {
                        name = "              " + type.Name;
                    }
                    else
                    {
                        name = "       " + type.Name;
                    }

                    if (i == 0 && inspectedContexts[i] is Object unityObject)
                    {
                        name += $" ({unityObject.name})";
                    }
                }
                else
                {
                    name = type.Name + " (Class)";
                }

                GUIContent content = new GUIContent(name, $"{type.FullName}, {type.Assembly.FullName}");

                Rect foldoutRect = GUILayoutUtility.GetRect(GUIContent.none, EditorStyles.foldoutHeader);

                Rect toggleRect = foldoutRect;
                toggleRect.xMin += 36;
                toggleRect.width = 20;

                Rect iconRect = foldoutRect;
                iconRect.xMin  += 16;
                iconRect.yMin  += 1;
                iconRect.height = iconRect.width = 16;

                // Have to do this before BeginFoldoutHeaderGroup otherwise it'll consume the mouse down event
                if (activeOrEnabled.HasValue && SidekickEditorGUI.DetectClickInRect(toggleRect))
                {
                    switch (inspectedContexts[i])
                    {
                    case GameObject gameObject:
                        gameObject.SetActive(!gameObject.activeSelf);
                        break;

                    case Behaviour behaviour:
                        behaviour.enabled = !behaviour.enabled;
                        break;
                    }
                }

                bool foldout = EditorGUI.BeginFoldoutHeaderGroup(foldoutRect, !typesHidden[index].Value, content, EditorStyles.foldoutHeader, rect => ClassUtilities.GetMenu(inspectedContext, inspectedECSContext).DropDown(rect));

                Texture icon = SidekickEditorGUI.GetIcon(inspectedContexts[i], type);
                if (icon != null)
                {
                    GUI.DrawTexture(iconRect, icon);
                }

                // Right click context menu
                if (SidekickEditorGUI.DetectClickInRect(foldoutRect, 1))
                {
                    ClassUtilities.GetMenu(inspectedContext, inspectedECSContext).DropDown(new Rect(Event.current.mousePosition, Vector2.zero));
                }

                if (activeOrEnabled.HasValue)
                {
                    EditorGUI.Toggle(toggleRect, activeOrEnabled.Value);
                }

                EditorGUILayout.EndFoldoutHeaderGroup();

                typesHidden[index] = new KeyValuePair <Type, bool>(type, !foldout);

                if (!typesHidden[index].Value)
                {
                    SidekickEditorGUI.DrawSplitter(0.5f);

                    EditorGUI.indentLevel++;

                    BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly;

                    if (inspectedContext != null) // Is this an object instance?
                    {
                        bindingFlags |= BindingFlags.Instance;
                    }

                    var typeScope = type;

                    while (typeScope != null)
                    {
                        if (InspectionExclusions.GetExcludedTypes().Contains(typeScope))
                        {
                            break;
                        }

                        if (typeScope != type)
                        {
                            SidekickEditorGUI.DrawTypeChainHeader(new GUIContent(": " + typeScope.Name));
                        }

                        FieldInfo[]    fields     = typeScope.GetFields(bindingFlags);
                        PropertyInfo[] properties = typeScope.GetProperties(bindingFlags);
                        MethodInfo[]   methods    = typeScope.GetMethods(bindingFlags);

                        // Hide methods and backing fields that have been generated for properties
                        if (SidekickSettings.HideAutoGenerated)
                        {
                            List <MethodInfo> methodList = new List <MethodInfo>(methods.Length);

                            foreach (MethodInfo method in methods)
                            {
                                if (!TypeUtility.IsPropertyMethod(method, typeScope))
                                {
                                    methodList.Add(method);
                                }
                            }

                            methods = methodList.ToArray();

                            List <FieldInfo> fieldList = new List <FieldInfo>(fields.Length);

                            for (int j = 0; j < fields.Length; j++)
                            {
                                if (!TypeUtility.IsBackingField(fields[j], typeScope))
                                {
                                    fieldList.Add(fields[j]);
                                }
                            }

                            fields = fieldList.ToArray();
                        }


                        FieldInfo[] events = typeScope.GetFields(bindingFlags);

                        if (mode == InspectorMode.Fields)
                        {
                            fieldPane.DrawFields(inspectedTypes[i], inspectedContexts[i], inspectedECSContext, searchTerm, fields);
                        }
                        else if (mode == InspectorMode.Properties)
                        {
                            propertyPane.DrawProperties(inspectedTypes[i], inspectedContexts[i], searchTerm, properties);
                        }
                        else if (mode == InspectorMode.Methods)
                        {
                            methodPane.DrawMethods(inspectedTypes[i], inspectedContexts[i], searchTerm, methods);
                        }
                        else if (mode == InspectorMode.Events)
                        {
                            eventPane.DrawEvents(inspectedTypes[i], inspectedContexts[i], searchTerm, events);
                        }

                        typeScope = typeScope.BaseType;
                    }


                    EditorGUI.indentLevel--;
                }

                SidekickEditorGUI.DrawSplitter();
            }

            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();

            if (inspectedTypes[0] == typeof(GameObject)
#if ECS_EXISTS
                || inspectedTypes[0] == typeof(EntitySelectionProxy)
#endif
                )
            {
                bool pressed    = GUILayout.Button("Add Component", GUILayout.Width(230), GUILayout.Height(24));
                var  popupRect2 = GUILayoutUtility.GetLastRect();
                popupRect2.width = EditorGUIUtility.currentViewWidth;
                if (pressed)
                {
                    if (inspectedTypes[0] == typeof(GameObject))
                    {
                        TypeSelectDropdown dropdown = new TypeSelectDropdown(new AdvancedDropdownState(), type =>
                        {
                            ((GameObject)inspectedContexts[0]).AddComponent(type);
                        }, new[] { typeof(Component) });
                        dropdown.Show(popupRect2);
                    }
#if ECS_EXISTS
                    else if (inspectedTypes[0] == typeof(EntitySelectionProxy))
                    {
                        TypeSelectDropdown dropdown = new TypeSelectDropdown(new AdvancedDropdownState(), type =>
                        {
                            inspectedECSContexts[0].EntityManager.AddComponent(inspectedECSContexts[0].Entity, ComponentType.ReadWrite(type));
                        }, null, new [] { typeof(IComponentData) });
                        dropdown.Show(popupRect2);
                    }
#endif
                }
            }

            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.EndScrollView();

            if (mode == InspectorMode.Methods)
            {
                methodPane.PostDraw();
            }


            //if(AnimationHelper.AnimationActive)
            {
                // Cause repaint on next frame
                Repaint();
                if (Event.current.type == EventType.Repaint)
                {
                    //AnimationHelper.ClearAnimationActive();
                }
            }

            SidekickEditorGUI.EndLabelHighlight();
        }