Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using UnityEditor;
- using UnityEditor.SceneManagement;
- /// <summary>
- /// Controls things that happen in the editor at every tick or when scene changes.
- /// Fix for crash when hitting run or unloading scene if a child is activeInHierarchy but some parent is !activeSelf.
- /// Issue #828408
- /// https://issuetracker.unity3d.com/issues/active-child-of-disabled-parent-crashes-editor-when-creating-new-scene
- /// </summary>
- ///
- [InitializeOnLoad]
- public class EditorManager {
- private static double lastUpdateTime = -1;
- private static float updateFrequencySeconds = 60f;
- private static System.DateTime startTime = System.DateTime.UtcNow;
- private static string currentScene;
- /// <summary>
- /// Runs on Unity editor start, on compile, and on play in editor.
- /// </summary>
- static EditorManager() {
- // fix after scene changes (crash still occurs when leaving buggy scene)
- EditorApplication.hierarchyWindowChanged += HierarchyWindowChanged;
- // and when hitting play before crash would occur
- EditorApplication.playmodeStateChanged += FixInvalidActiveChildren;
- // and once a minute for good measure
- EditorApplication.update += Update;
- }
- /// <summary>
- /// Runs every frame while in edit mode and in play mode while in editor.
- /// Runs more often and reliably than Update on MonoBehaviors with [ExecuteInEditMode]
- /// </summary>
- static void Update() {
- if (!isUnityEditMode) return;
- // perform check every minute
- double currentTime = (System.DateTime.UtcNow - startTime).TotalSeconds;
- if (currentTime > lastUpdateTime + updateFrequencySeconds) {
- lastUpdateTime = currentTime;
- FixInvalidActiveChildren();
- }
- }
- /// <summary>
- /// When object created, renamed, moved or destroyed in scene hierarchy,
- /// including when scene changes and on compile.
- /// </summary>
- static void HierarchyWindowChanged() {
- if (!isUnityEditMode) return;
- // scene changed
- if (currentScene != EditorSceneManager.GetActiveScene().path) {
- currentScene = EditorSceneManager.GetActiveScene().path;
- FixInvalidActiveChildren();
- }
- }
- /// <summary>
- /// Runs once a minute while in edit mode.
- /// </summary>
- static void FixInvalidActiveChildren() {
- GameObject[] parents = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
- foreach (GameObject parent in parents) {
- GameObject invalidActiveChild = FindInvalidActiveChild(parent, !parent.activeSelf);
- if (invalidActiveChild != null) {
- Debug.LogWarning("EditorBugFixer found invalid active child, fixing... " + invalidActiveChild.GetPath());
- // twiddle root parent activeSelf to force child to become !activeInHierarchy
- bool parentWasActive = parent.activeSelf;
- parent.SetActive(false);
- parent.SetActive(true);
- parent.SetActive(false);
- parent.SetActive(parentWasActive);
- }
- }
- }
- static GameObject FindInvalidActiveChild(GameObject parent, bool someParentInactive) {
- foreach (Transform child in parent.transform) {
- if (someParentInactive && child.gameObject.activeInHierarchy) {
- // only need one per root, twiddling root should fix any others
- return child.gameObject;
- } else {
- bool someInactive = someParentInactive || !child.gameObject.activeSelf;
- GameObject invalidGrandchild = FindInvalidActiveChild(child.gameObject, someInactive);
- if (invalidGrandchild != null) {
- return invalidGrandchild;
- }
- }
- }
- return null;
- }
- /// <summary>
- /// Are we in the editor and not playing?
- /// </summary>
- public static bool isUnityEditMode {
- get {
- #if UNITY_EDITOR
- if (!UnityEditor.EditorApplication.isPlaying) return true;
- #endif
- return false;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement