Skip to content

Instantly share code, notes, and snippets.

@restush
Forked from to-osaki/FindMissingEditor.cs
Last active August 17, 2024 18:58
Show Gist options
  • Save restush/e551ec57ae47084e78b7b5f6be705c6a to your computer and use it in GitHub Desktop.
Save restush/e551ec57ae47084e78b7b5f6be705c6a to your computer and use it in GitHub Desktop.
Unity Find missing references

image

How to open: On Unity menu bar -> Tools -> Find Missing References
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
public class FindMissingEditor : EditorWindow
{
private float _progress = 0f;
private bool _canceled;
private List<GameObject> _errorGameObjects = new List<GameObject>();
[MenuItem(itemName: "Tools/Find Missing References")]
public static void Open()
{
FindMissingEditor window = GetWindow<FindMissingEditor>("Find Missing Editor");
Rect main = EditorGUIUtility.GetMainWindowPosition();
Rect pos = window.position;
float centerWidth = (main.width - pos.width) * 0.5f;
float centerHeight = (main.height - pos.height) * 0.3f;
pos.x = main.x + centerWidth;
pos.y = main.y + centerHeight;
window.position = new Rect(pos.position.x, pos.position.y, pos.width, window._errorGameObjects.Count > 0 ? Mathf.Max(50, pos.height) : 50);
window.Show();
}
private void CreateGUI()
{
var hierarchyBtn = new Button()
{
name = "Hierarchy-Button",
text = "Missing in Hierarchy...",
};
var prefabBtn = new Button()
{
name = "Prefab-Button",
text = "Missing in Prefabs..."
};
var listView = new ListView()
{
makeNoneElement = () => new VisualElement(),
makeItem = () =>
{
var objectField = new ObjectField();
var selector = objectField.Q(className: "unity-object-field__selector");
selector.RemoveFromClassList("unity-object-field__selector");
return objectField;
},
bindItem = (v, i) =>
{
var objectField = (v as ObjectField);
objectField.name = _errorGameObjects[i].name;
objectField.value = _errorGameObjects[i];
},
itemsSource = _errorGameObjects,
selectionType = SelectionType.None,
};
listView.style.minHeight = 0;
listView.style.maxHeight = 1000;
hierarchyBtn.clicked += () =>
{
_errorGameObjects.Clear();
int sceneCount = UnityEngine.SceneManagement.SceneManager.sceneCount;
_progress = 0f;
EditorUtility.DisplayProgressBar("Finding Missing References", "Searching in Hierarchy...", _progress);
listView.Q("unity-content-container").Clear();
_canceled = false;
int totalIterator = sceneCount;
int currentIterator = 0;
for (int i = 0; i < sceneCount; ++i)
{
var scene = UnityEngine.SceneManagement.SceneManager.GetSceneAt(i);
var roots = scene.GetRootGameObjects();
var rootLength = roots.Length;
totalIterator += rootLength;
foreach (var go in roots)
{
currentIterator++;
FindMissing(go, Iterator, AddToList, AddToList);
void AddToList(GameObject go)
{
_errorGameObjects.Add(go);
}
void Iterator(GameObject gameObject)
{
_progress = (float)currentIterator / totalIterator;
_canceled = EditorUtility.DisplayCancelableProgressBar("Finding Missing References", $"Searching in Hierarchy...`{gameObject.name}`", _progress);
}
if (_canceled)
break;
}
if (_canceled)
break;
currentIterator++;
}
EditorUtility.ClearProgressBar();
UpdateUIAndAdjustWindowSize(listView);
};
rootVisualElement.Add(listView);
rootVisualElement.Add(hierarchyBtn);
prefabBtn.clicked += () =>
{
_errorGameObjects.Clear();
string[] guids = AssetDatabase.FindAssets("t:prefab");
_progress = 0f;
_canceled = false;
EditorUtility.DisplayProgressBar("Finding Missing References", "Searching in Prefabs...", _progress);
var totalIterator = guids.Length;
var currentIterator = 0;
for (int i = 0; i < guids.Length; ++i)
{
var path = AssetDatabase.GUIDToAssetPath(guids[i]);
var go = AssetDatabase.LoadAssetAtPath<GameObject>(path);
currentIterator++;
FindMissing(go, Iterator, AddToList, AddToList);
void AddToList(GameObject go)
{
_errorGameObjects.Add(go);
}
void Iterator(GameObject gameObject)
{
_progress = (float)currentIterator / totalIterator;
_canceled = EditorUtility.DisplayCancelableProgressBar("Finding Missing References", $"Searching in Prefabs...`{gameObject.name}`", _progress);
}
if (_canceled)
break;
}
EditorUtility.ClearProgressBar();
UpdateUIAndAdjustWindowSize(listView);
};
rootVisualElement.Add(prefabBtn);
}
private void FindMissing(GameObject go, System.Action<GameObject> iterator, System.Action<GameObject> missingScript, System.Action<GameObject> missingReference)
{
var transforms = go.GetComponentsInChildren<Transform>();
foreach (var t in transforms)
{
iterator?.Invoke(t.gameObject);
int missingScripts = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(t.gameObject);
if (missingScripts > 0)
{
Debug.LogError($"{t.gameObject.name} has missing script(s)", t.gameObject);
missingScript?.Invoke(t.gameObject);
}
var components = t.gameObject.GetComponents<MonoBehaviour>();
foreach (var c in components)
{
if (c == null) { continue; }
var serializedObject = new SerializedObject(c);
var it = serializedObject.GetIterator();
while (it.NextVisible(true))
{
if (it.propertyType == SerializedPropertyType.ObjectReference)
{
if (it.objectReferenceValue == null && it.objectReferenceInstanceIDValue != 0)
{
Debug.LogError($"{t.gameObject.name}.{c.GetType().Name}.{it.displayName} has missing reference", c);
missingReference?.Invoke(t.gameObject);
}
}
}
}
}
}
private void UpdateUIAndAdjustWindowSize(ListView listView)
{
var hasError = _errorGameObjects.Count > 0;
if (hasError)
{
listView.style.minHeight = new StyleLength(Length.Auto());
listView.style.paddingBottom = 8;
listView.style.paddingTop = 8;
listView.style.paddingLeft = 8;
listView.style.paddingRight = 8;
}
else
{
listView.style.minHeight = 0;
listView.style.paddingBottom = 0;
listView.style.paddingTop = 0;
listView.style.paddingLeft = 0;
listView.style.paddingRight = 0;
}
listView.Rebuild();
if (hasError)
{
var listViewCurrentHeight = _errorGameObjects.Count * 20;
var maxWindowHeight = 200;
listViewCurrentHeight = Mathf.Clamp(listViewCurrentHeight, 0, maxWindowHeight);
position = new Rect(position.x, position.y, position.width, height: Mathf.Max(listViewCurrentHeight + 50, position.height));
}
else
{
position = new Rect(position.x, position.y, position.width, Mathf.Max(50, position.height));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment