using System.Collections.Generic; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; namespace RunlevelSystems.DevPlus1.EditorTools { public static class RLSceneAnalyzer { public static List AnalyzeOpenScenes() { List results = new List(); for (int i = 0; i < SceneManager.sceneCount; i++) { Scene scene = SceneManager.GetSceneAt(i); if (scene.IsValid() && scene.isLoaded) { results.Add(AnalyzeLoadedScene(scene)); } } return results; } public static List AnalyzeBuildSettingsScenes() { List paths = new List(); foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes) { if (scene.enabled) { paths.Add(scene.path); } } return AnalyzeScenePaths(paths); } public static List AnalyzeAllAssetScenes() { List paths = new List(); foreach (string guid in AssetDatabase.FindAssets("t:Scene")) { paths.Add(AssetDatabase.GUIDToAssetPath(guid)); } return AnalyzeScenePaths(paths); } private static List AnalyzeScenePaths(List paths) { List results = new List(); if (HasDirtyOpenScenes()) { RLSceneInfo skipped = new RLSceneInfo(); skipped.sceneName = "Scene analysis skipped"; skipped.scenePath = "Open scenes contain unsaved changes"; skipped.notes = "The analyzer does not save scenes. Save or discard changes manually, then run scene analysis again."; results.Add(skipped); return results; } SceneSetup[] setup = EditorSceneManager.GetSceneManagerSetup(); try { foreach (string path in paths) { if (string.IsNullOrEmpty(path)) { continue; } Scene scene = EditorSceneManager.OpenScene(path, OpenSceneMode.Single); results.Add(AnalyzeLoadedScene(scene)); } } finally { if (setup != null && setup.Length > 0) { EditorSceneManager.RestoreSceneManagerSetup(setup); } } return results; } private static bool HasDirtyOpenScenes() { for (int i = 0; i < SceneManager.sceneCount; i++) { Scene scene = SceneManager.GetSceneAt(i); if (scene.isDirty) { return true; } } return false; } private static RLSceneInfo AnalyzeLoadedScene(Scene scene) { RLSceneInfo info = new RLSceneInfo(); info.scenePath = scene.path; info.sceneName = scene.name; info.buildIndex = scene.buildIndex; GameObject[] roots = scene.GetRootGameObjects(); info.rootGameObjectCount = roots.Length; foreach (GameObject root in roots) { info.rootGameObjects.Add(root.name); AnalyzeGameObjectRecursive(root, root.name, scene.path, info); } return info; } public static void AnalyzeGameObjectRecursive(GameObject gameObject, string hierarchyPath, string sourcePath, RLSceneInfo sceneInfo) { RLGameObjectInfo goInfo = AnalyzeGameObject(gameObject, hierarchyPath); sceneInfo.gameObjects.Add(goInfo); sceneInfo.totalGameObjects++; if (gameObject.activeSelf) sceneInfo.activeGameObjects++; else sceneInfo.inactiveGameObjects++; sceneInfo.missingScriptCount += goInfo.missingScriptCount; sceneInfo.missingReferenceCount += goInfo.missingReferenceCount; sceneInfo.unityEvents.AddRange(RLUnityEventAnalyzer.ExtractUnityEvents(gameObject, sourcePath, hierarchyPath)); foreach (Transform child in gameObject.transform) { AnalyzeGameObjectRecursive(child.gameObject, hierarchyPath + "/" + child.name, sourcePath, sceneInfo); } } public static RLGameObjectInfo AnalyzeGameObject(GameObject gameObject, string hierarchyPath) { RLGameObjectInfo info = new RLGameObjectInfo(); info.hierarchyPath = hierarchyPath; info.activeSelf = gameObject.activeSelf; info.tag = gameObject.tag; info.layer = gameObject.layer; info.missingScriptCount = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(gameObject); Component[] components = gameObject.GetComponents(); foreach (Component component in components) { if (component == null) { info.components.Add("Missing Script"); continue; } info.components.Add(component.GetType().Name); MonoBehaviour monoBehaviour = component as MonoBehaviour; if (monoBehaviour != null) { info.attachedScripts.Add(component.GetType().Name); } CollectSerializedReferences(component, info); } return info; } private static void CollectSerializedReferences(Component component, RLGameObjectInfo info) { SerializedObject serializedObject = new SerializedObject(component); SerializedProperty property = serializedObject.GetIterator(); bool enterChildren = true; while (property.NextVisible(enterChildren)) { enterChildren = false; if (property.propertyType != SerializedPropertyType.ObjectReference) { continue; } if (property.objectReferenceValue != null) { string referenceName = property.displayName + " -> " + property.objectReferenceValue.name; if (!info.referencedObjects.Contains(referenceName)) { info.referencedObjects.Add(referenceName); } } else if (property.objectReferenceInstanceIDValue != 0) { info.missingReferenceCount++; } } } } }