179 lines
5.8 KiB
C#
179 lines
5.8 KiB
C#
#if UNITY_EDITOR
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using UnityEditor;
|
|
using UnityEditor.SceneManagement;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
public static class MissingScriptUtility
|
|
{
|
|
[MenuItem("Tools/Diagnostics/Find Missing Scripts in Open Scenes")]
|
|
public static void FindMissingScriptsInOpenScenes()
|
|
{
|
|
int missingCount = 0;
|
|
var reported = new HashSet<GameObject>();
|
|
|
|
foreach (var scene in GetLoadedScenes())
|
|
{
|
|
foreach (var root in scene.GetRootGameObjects())
|
|
ScanHierarchy(root, ref missingCount, reported);
|
|
}
|
|
|
|
Debug.Log($"[MissingScriptUtility] Missing scripts found: {missingCount}");
|
|
}
|
|
|
|
[MenuItem("Tools/Diagnostics/Find Missing Scripts in Prefabs")]
|
|
public static void FindMissingScriptsInPrefabs()
|
|
{
|
|
var prefabGuids = AssetDatabase.FindAssets("t:Prefab");
|
|
int missingCount = 0;
|
|
|
|
for (int i = 0; i < prefabGuids.Length; i++)
|
|
{
|
|
var path = AssetDatabase.GUIDToAssetPath(prefabGuids[i]);
|
|
EditorUtility.DisplayProgressBar("Scanning Prefabs", path, (float)i / prefabGuids.Length);
|
|
|
|
var root = PrefabUtility.LoadPrefabContents(path);
|
|
if (root == null)
|
|
continue;
|
|
|
|
ScanHierarchy(root, ref missingCount, null, path);
|
|
PrefabUtility.UnloadPrefabContents(root);
|
|
}
|
|
|
|
EditorUtility.ClearProgressBar();
|
|
Debug.Log($"[MissingScriptUtility] Missing scripts found in prefabs: {missingCount}");
|
|
}
|
|
|
|
[MenuItem("Tools/Diagnostics/Find Missing Scripts in ScriptableObjects")]
|
|
public static void FindMissingScriptsInScriptableObjects()
|
|
{
|
|
var assetGuids = AssetDatabase.FindAssets("t:ScriptableObject");
|
|
int missingCount = 0;
|
|
|
|
for (int i = 0; i < assetGuids.Length; i++)
|
|
{
|
|
var path = AssetDatabase.GUIDToAssetPath(assetGuids[i]);
|
|
EditorUtility.DisplayProgressBar("Scanning ScriptableObjects", path, (float)i / assetGuids.Length);
|
|
|
|
if (string.IsNullOrWhiteSpace(path) || !path.EndsWith(".asset", StringComparison.OrdinalIgnoreCase))
|
|
continue;
|
|
|
|
if (!File.Exists(path))
|
|
continue;
|
|
|
|
string contents;
|
|
try
|
|
{
|
|
contents = File.ReadAllText(path);
|
|
}
|
|
catch
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (contents.Contains("m_Script: {fileID: 0}"))
|
|
{
|
|
missingCount++;
|
|
Debug.LogWarning($"[MissingScriptUtility] Missing script reference in asset: {path}");
|
|
}
|
|
}
|
|
|
|
EditorUtility.ClearProgressBar();
|
|
Debug.Log($"[MissingScriptUtility] Missing scripts found in scriptable objects: {missingCount}");
|
|
}
|
|
|
|
[MenuItem("Tools/Diagnostics/Remove Missing Scripts in Open Scenes")]
|
|
public static void RemoveMissingScriptsInOpenScenes()
|
|
{
|
|
int removed = 0;
|
|
|
|
foreach (var scene in GetLoadedScenes())
|
|
{
|
|
foreach (var root in scene.GetRootGameObjects())
|
|
removed += GameObjectUtility.RemoveMonoBehavioursWithMissingScript(root);
|
|
}
|
|
|
|
if (removed > 0)
|
|
EditorSceneManager.MarkAllScenesDirty();
|
|
|
|
Debug.Log($"[MissingScriptUtility] Removed missing scripts: {removed}");
|
|
}
|
|
|
|
[MenuItem("Tools/Diagnostics/Remove Missing Scripts in Prefabs")]
|
|
public static void RemoveMissingScriptsInPrefabs()
|
|
{
|
|
var prefabGuids = AssetDatabase.FindAssets("t:Prefab");
|
|
int removed = 0;
|
|
|
|
for (int i = 0; i < prefabGuids.Length; i++)
|
|
{
|
|
var path = AssetDatabase.GUIDToAssetPath(prefabGuids[i]);
|
|
EditorUtility.DisplayProgressBar("Cleaning Prefabs", path, (float)i / prefabGuids.Length);
|
|
|
|
var root = PrefabUtility.LoadPrefabContents(path);
|
|
if (root == null)
|
|
continue;
|
|
|
|
int removedInPrefab = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(root);
|
|
if (removedInPrefab > 0)
|
|
PrefabUtility.SaveAsPrefabAsset(root, path);
|
|
|
|
removed += removedInPrefab;
|
|
PrefabUtility.UnloadPrefabContents(root);
|
|
}
|
|
|
|
EditorUtility.ClearProgressBar();
|
|
if (removed > 0)
|
|
AssetDatabase.SaveAssets();
|
|
|
|
Debug.Log($"[MissingScriptUtility] Removed missing scripts in prefabs: {removed}");
|
|
}
|
|
|
|
private static IEnumerable<Scene> GetLoadedScenes()
|
|
{
|
|
for (int i = 0; i < SceneManager.sceneCount; i++)
|
|
{
|
|
var scene = SceneManager.GetSceneAt(i);
|
|
if (scene.isLoaded)
|
|
yield return scene;
|
|
}
|
|
}
|
|
|
|
private static void ScanHierarchy(GameObject go, ref int missingCount, HashSet<GameObject> reported, string assetPath = null)
|
|
{
|
|
var components = go.GetComponents<Component>();
|
|
for (int i = 0; i < components.Length; i++)
|
|
{
|
|
if (components[i] == null)
|
|
{
|
|
missingCount++;
|
|
if (reported == null || reported.Add(go))
|
|
{
|
|
var label = string.IsNullOrWhiteSpace(assetPath) ? "scene object" : $"prefab {assetPath}";
|
|
Debug.LogWarning($"[MissingScriptUtility] Missing script on {label}: {GetHierarchyPath(go.transform)}");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
foreach (Transform child in go.transform)
|
|
ScanHierarchy(child.gameObject, ref missingCount, reported);
|
|
}
|
|
|
|
private static string GetHierarchyPath(Transform transform)
|
|
{
|
|
var sb = new StringBuilder(transform.name);
|
|
while (transform.parent != null)
|
|
{
|
|
transform = transform.parent;
|
|
sb.Insert(0, transform.name + "/");
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
#endif
|