generated from DevPlus1/Unity-Customer-Template
193 lines
6.9 KiB
C#
193 lines
6.9 KiB
C#
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<RLSceneInfo> AnalyzeOpenScenes()
|
|
{
|
|
List<RLSceneInfo> results = new List<RLSceneInfo>();
|
|
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<RLSceneInfo> AnalyzeBuildSettingsScenes()
|
|
{
|
|
List<string> paths = new List<string>();
|
|
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
|
|
{
|
|
if (scene.enabled)
|
|
{
|
|
paths.Add(scene.path);
|
|
}
|
|
}
|
|
return AnalyzeScenePaths(paths);
|
|
}
|
|
|
|
public static List<RLSceneInfo> AnalyzeAllAssetScenes()
|
|
{
|
|
List<string> paths = new List<string>();
|
|
foreach (string guid in AssetDatabase.FindAssets("t:Scene"))
|
|
{
|
|
paths.Add(AssetDatabase.GUIDToAssetPath(guid));
|
|
}
|
|
return AnalyzeScenePaths(paths);
|
|
}
|
|
|
|
private static List<RLSceneInfo> AnalyzeScenePaths(List<string> paths)
|
|
{
|
|
List<RLSceneInfo> results = new List<RLSceneInfo>();
|
|
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<Component>();
|
|
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++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|