public ExposedComponent[] GetComponents(ExposedGameObject go, VerticalActivitySlice slice)
        {
            if (go == null || go.components == null)
                return null;

            if (slice == null || slice.gameObjectsSnapshot == null || slice.gameObjectsSnapshot.components == null)
                return null;

            long key = vBugMathHelper.CombineInts(go.transformID, slice.header.frameNumber);
            if (componentsPerGO.ContainsKey(key)) {
                return componentsPerGO[key];
            } else {
                int i = go.components.Length;
                ExposedComponent[] allComponents = slice.gameObjectsSnapshot.components;
                ExposedComponent[] result = new ExposedComponent[i];
                while (--i > -1)
                    result[i] = allComponents[go.components[i]];

                componentsPerGO.Add(key, result);
                return result;
            }
        }
 private void SortReflectedObjectsByName(ExposedGameObject[] exposedGameObjects)
 {
     Array.Sort(exposedGameObjects, (a, b) => a.name.CompareTo(b.name) + (a.isHiddenOrDontSave.CompareTo(b.isHiddenOrDontSave) * 100000));
 }
        private void SetNextSelection(int instanceID)
        {
            string nextName = "hierarchy_" + instanceID;
            if (currentFocusControlName == nextName)
                return;

            nextSelectedID = instanceID;
            currentSelection = null;
            currentFocusControlName = nextName;
            forceFocusControll = true;
            GUI.FocusControl(currentFocusControlName);
        }
 private void ResetFocus()
 {
     currentFocusControlName = null;
     currentSelectedID = -1;
     currentSelection = null;
 }
        private void SetCurrentSlice(int frameNumber)
        {
            currentSlice = null;
            int iMin = Mathf.Max(VerticalSliceDatabase.minRange, frameNumber - vBugEditorSettings.PlaybackHierarchySearchRange);

            for (int i = frameNumber; i >= iMin; i--) {
                currentSlice = VerticalSliceDatabase.GetSlice(i);

                if (currentSlice != null && currentSlice.gameObjectsSnapshot != null && currentSlice.gameObjectsSnapshot.gameObjects != null) {
                    currentSelection = null;
                    break;
                }
            }
        }
        private ExposedGameObject FindObjectByID(ExposedGameObject[] objects, int instanceID)
        {
            if (objects == null || instanceID == -1)
                return null;

            int i = objects.Length;
            while (--i > -1) {
                if (objects[i].transformID == instanceID)
                    return objects[i];
            }
            return null;
        }
        private int FindScrollPosByID(ExposedGameObject[] gameObjects, VerticalActivitySlice slice, int instanceID, int currentScrollPos, ref ExposedGameObject selectedGO)
        {
            if (gameObjects == null || instanceID == -1) {
                selectedGO = null;
                return -1;
            }

            //--------------- Scan children second --------------------
            int offset = 0;
            int increment = 16;
            foreach (ExposedGameObject obj in gameObjects) {
                if (obj.transformID == instanceID) {
                    selectedGO = obj;
                    return currentScrollPos + offset;
                } else {
                    ExposedGameObject[] children = GetChildren(obj.transformID, slice);
                    if (children != null && children.Length > 0) {
                        increment = 18;
                        int result = FindScrollPosByID(children, slice, instanceID, currentScrollPos + offset + increment, ref selectedGO);
                        if (result != -1) {
                            if (hierarchyFoldoutStates.ContainsKey(obj.transformID)) {
                                hierarchyFoldoutStates[obj.transformID] = true;
                            } else {
                                hierarchyFoldoutStates.Add(obj.transformID, true);
                            }
                            return result;
                        }
                    } else {
                        increment = 16;
                    }
                }
                offset += increment;
            }
            //--------------- Scan children second --------------------
            return -1;
        }
        private void DrawGameObjectsRecursive(VerticalActivitySlice slice, ExposedGameObject[] gameObjects, bool parentActive, bool allowMouseClick)
        {
            EventType eventType = Event.current.type;
            GUILayout.BeginVertical();

            Rect lastRect = default(Rect);

            foreach (ExposedGameObject go in gameObjects) {
                ExposedGameObject[] children = GetChildren(go.transformID, slice);

                bool isFoldout = children != null && children.Length > 0;

                //--------------- Draw recursive --------------------
                if (!hierarchyFoldoutStates.ContainsKey(go.transformID))
                    hierarchyFoldoutStates.Add(go.transformID, false);

                bool localActive = parentActive && go.activeSelf;
                string label = go.name;
                GUI.color = localActive ? Color.white : new Color(0.6f, 0.6f, 0.6f);

                if (go.isHiddenOrDontSave && go.transformID != nextSelectedID) {
                    GUI.color = new Color(0.1f, 0.1f, 0.1f);
                    label = "[hidden]" + label;
                } else if (go.isStatic) {
                    GUI.color = new Color(0.8f, 0.8f, 0.8f);
                    label = "[static] " + label;
                } else {
                    GUI.color = Color.white;
                }

                string currentControlName = "hierarchy_" + go.transformID;
                GUI.SetNextControlName(currentControlName);
                controllIndexing.Add(currentControlName);

                bool drawInspIcon = eventType == EventType.repaint && go.components != null && go.components.Length > 0;
                bool drawEOLIcon = TestEOL(go.transformID, slice.header.frameNumber);
                bool drawBirthIcon = TestBirth(go.transformID, slice.header.frameNumber);
                int offset = 0;

                if (isFoldout) {
                    bool newState = EditorGUILayout.Foldout(hierarchyFoldoutStates[go.transformID], label, EditorHelper.styleHierarchyFoldout);
                    lastRect = GUILayoutUtility.GetLastRect();

                    if (newState != hierarchyFoldoutStates[go.transformID]) {
                        SetNextSelection(go.transformID);
                        if (newState)
                            SortReflectedObjectsByName(children);
                    }

                    hierarchyFoldoutStates[go.transformID] = newState;
                    if (newState) {
                        GUILayout.BeginHorizontal();
                        GUILayout.Space(16);
                        DrawGameObjectsRecursive(slice, children, localActive, allowMouseClick);
                        GUILayout.EndHorizontal();
                    }

                    if (hasFocus && eventType == EventType.mouseUp && GUI.GetNameOfFocusedControl() == currentControlName)
                        SetNextSelection(go.transformID);

                } else {
                    GUILayout.BeginHorizontal();
                    GUILayout.Space(18);
                    offset = 14;

                    if (GUILayout.Button(label, EditorHelper.styleHierarchyLabel, GUILayout.Height(16)))
                        SetNextSelection(go.transformID);

                    lastRect = GUILayoutUtility.GetLastRect();
                    GUILayout.EndHorizontal();
                }

                if (drawInspIcon)
                    VisualResources.DrawIcon(EditorIcon.hierarchyAndInspector, 1, new Vector2(lastRect.x - 12 - offset, lastRect.y + 2), 1f, false);

                if (drawEOLIcon)
                    VisualResources.DrawIcon(EditorIcon.hierarchyAndInspector, 3, new Vector2(lastRect.x - 24 - offset, lastRect.y + 2), 1f, false);

                if (drawBirthIcon)
                    VisualResources.DrawIcon(EditorIcon.hierarchyAndInspector, 0, new Vector2(lastRect.x - 36 - offset, lastRect.y + 2), 1f, false);
                //--------------- Draw recursive --------------------

            }

            GUILayout.EndVertical();
            GUI.color = GUI.contentColor = GUI.backgroundColor = Color.white;
        }
        private void DrawGUI()
        {
            if (EditorApplication.isPlayingOrWillChangePlaymode)
                return;

            if (!VerticalSliceDatabase.isInitialized) {
                EditorHelper.DrawNotInitializedLabel(this.position);

            } else if (currentSlice == null || currentSlice.gameObjectsSnapshot == null || currentSlice.gameObjectsSnapshot.gameObjects == null || currentSlice.gameObjectsSnapshot.gameObjects.Length == 0) {
                EditorHelper.DrawNA(new Rect(0, 0, this.position.width, this.position.height));

            } else {
                EventType eventType = Event.current.type;
                if (eventType == EventType.Layout && currentSelectedID != nextSelectedID || currentSelection == null) { //prevents gui-popping issues.
                    currentSelectedID = nextSelectedID;
                    currentFocusControlName = "hierarchy_" + nextSelectedID;
                    currentSelection = FindObjectByID(currentSlice.gameObjectsSnapshot.gameObjects, nextSelectedID);
                }

                Rect rect = new Rect(0, 0, this.position.width, dragBarRect.y);
                GUI.color = new Color(0f, 0f, 0f, 0.25f);
                VisualResources.DrawTexture(rect, VisualResources.black);
                GUI.color = Color.white;

                GUILayout.BeginArea(rect);

                hierarchyPosition = GUILayout.BeginScrollView(hierarchyPosition);

                GUILayout.BeginHorizontal();
                GUILayout.Space(32);
                GUILayout.BeginVertical();

                //int bFont = GUI.skin.label.fontSize;
                //GUI.skin.label.fontSize = 8;
                controllIndexing.Clear();

                DrawGameObjectsRecursive(currentSlice, GetRootObjects(currentSlice), true, true);
                if (forceFocusControll) {
                    GUI.FocusControl(currentFocusControlName);
                    forceFocusControll = false;
                }

                //GUI.skin.label.fontSize = bFont;

                GUILayout.EndVertical();
                GUILayout.EndHorizontal();
                GUILayout.EndScrollView();
                GUILayout.EndArea();

                EditorHelper.DrawDragBar(this, ref dragBarRect, ref dragBarResize, ref dragBarCurrentWinHeight);
                DrawSelectedGOComponents();
            }
        }
 public GameObjectsSnapshot(ExposedGameObject[] gameObjects, ExposedComponent[] components)
 {
     this.gameObjects = gameObjects;
     this.components = components;
 }
        //--------------- SERIALIZE --------------------
        public static byte[] SerializeArray(ExposedGameObject[] input)
        {
            if (input == null) return null;
            ComposedByteStream stream = ComposedByteStream.FetchStream(input.Length);
            for (int i = 0; i < input.Length; i++)
                stream.AddStream(Serialize(input[i]));

            return stream.Compose();
        }
        public static byte[] Serialize(ExposedGameObject input)
        {
            if (input == null) return null;
            //--------------- First primitives --------------------
            ComposedPrimitives prims = new ComposedPrimitives();
            prims.AddValue(input.transformID);
            prims.AddValue(input.parentID);
            prims.AddValue(input.layer);
            prims.AddValue(input.activeSelf);
            prims.AddValue(input.isStatic);
            prims.AddValue(input.isHiddenOrDontSave);
            //--------------- First primitives --------------------

            //--------------- Final stream --------------------
            ComposedByteStream stream = ComposedByteStream.FetchStream();
            stream.AddStream(prims.Compose());
            stream.AddStream(input.name);
            stream.AddStream(input.tag);
            stream.AddStream(input.matrix.GetRawData());
            stream.AddStream(input.components);
            //--------------- Final stream --------------------

            return stream.Compose();
        }
        //--------------- SERIALIZE --------------------
        //--------------- DESERIALIZE --------------------
        public static ExposedGameObject[] DeserializeArray(byte[] input)
        {
            if (input == null) return null;
            ComposedByteStream stream = ComposedByteStream.FromByteArray(input);
            if (stream == null)
                return null;

            int iMax = stream.streamCount;
            ExposedGameObject[] result = new ExposedGameObject[iMax];
            for (int i = 0; i < iMax; i++)
                result[i] = Deserialize(stream.ReadNextStream<byte>());

            stream.Dispose();
            return result;
        }
        public static ExposedGameObject Deserialize(byte[] input)
        {
            if (input == null) return null;
            ExposedGameObject result = new ExposedGameObject();
            ComposedByteStream stream = ComposedByteStream.FromByteArray(input);
            if (stream == null)
                return null;

            //--------------- First primitives --------------------
            ComposedPrimitives prims = ComposedPrimitives.FromByteArray(stream.ReadNextStream<byte>());
            result.transformID = prims.ReadNextValue<int>();
            result.parentID = prims.ReadNextValue<int>();
            result.layer = prims.ReadNextValue<int>();
            result.activeSelf = prims.ReadNextValue<bool>();
            result.isStatic = prims.ReadNextValue<bool>();
            result.isHiddenOrDontSave = prims.ReadNextValue<bool>();
            //--------------- First primitives --------------------

            result.name = stream.ReadNextStream();
            result.tag = stream.ReadNextStream();
            result.matrix = new SMatrix4x4(stream.ReadNextStream<float>());
            result.components = stream.ReadNextStream<int>();

            stream.Dispose();
            return result;
        }