Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rich-wan/8632811979fd0f00bc8ca9d5e1aafaa7 to your computer and use it in GitHub Desktop.
Save rich-wan/8632811979fd0f00bc8ca9d5e1aafaa7 to your computer and use it in GitHub Desktop.
Remove missing MonoBehaviour script components in Unity 2019.1 including visiting prefafab assets.
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
public static class FindMissingScriptsRecursively
{
[MenuItem("Auto/Remove Missing Scripts Recursively Visit Prefabs")]
private static void FindAndRemoveMissingInSelected()
{
// EditorUtility.CollectDeepHierarchy does not include inactive children
var deeperSelection = Selection.gameObjects.SelectMany(go => go.GetComponentsInChildren<Transform>(true))
.Select(t => t.gameObject);
var prefabs = new HashSet<Object>();
int compCount = 0;
int goCount = 0;
foreach (var go in deeperSelection)
{
int count = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(go);
if (count > 0)
{
if (PrefabUtility.IsPartOfAnyPrefab(go))
{
RecursivePrefabSource(go, prefabs, ref compCount, ref goCount);
count = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(go);
// if count == 0 the missing scripts has been removed from prefabs
if (count == 0)
continue;
// if not the missing scripts must be prefab overrides on this instance
}
Undo.RegisterCompleteObjectUndo(go, "Remove missing scripts");
GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go);
compCount += count;
goCount++;
}
}
Debug.Log($"Found and removed {compCount} missing scripts from {goCount} GameObjects");
}
// Prefabs can both be nested or variants, so best way to clean all is to go through them all
// rather than jumping straight to the original prefab source.
private static void RecursivePrefabSource(GameObject instance, HashSet<Object> prefabs, ref int compCount,
ref int goCount)
{
var source = PrefabUtility.GetCorrespondingObjectFromSource(instance);
// Only visit if source is valid, and hasn't been visited before
if (source == null || !prefabs.Add(source))
return;
// go deep before removing, to differantiate local overrides from missing in source
RecursivePrefabSource(source, prefabs, ref compCount, ref goCount);
int count = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(source);
if (count > 0)
{
Undo.RegisterCompleteObjectUndo(source, "Remove missing scripts");
GameObjectUtility.RemoveMonoBehavioursWithMissingScript(source);
compCount += count;
goCount++;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment