Skip to content

Instantly share code, notes, and snippets.

@marcelschmidtdev
Created December 18, 2017 14:49
Show Gist options
  • Save marcelschmidtdev/70037fd36e3a9be1c4808891e8cdf537 to your computer and use it in GitHub Desktop.
Save marcelschmidtdev/70037fd36e3a9be1c4808891e8cdf537 to your computer and use it in GitHub Desktop.
Searching for components with missing scripts and removes them
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
public class RemoveMissingScriptComponents
{
[MenuItem ("TOOLS/Remove Missing Scripts")]
public static void Run ()
{
try
{
FindAndRemoveMissingScripts ();
}
catch (Exception e)
{
EditorUtility.ClearProgressBar ();
Debug.LogError (e.Message);
throw e;
}
}
private static void FindAndRemoveMissingScripts ()
{
Debug.Log ("Scenes: " + EditorBuildSettings.scenes.Length);
EditorUtility.DisplayProgressBar ("Find Missing Script Components", "Loading scenes from build settings...", 0.2f);
for (int i = 0; i < EditorBuildSettings.scenes.Length; i++)
{
EditorSceneManager.OpenScene (EditorBuildSettings.scenes[i].path, OpenSceneMode.Additive);
}
GameObject[] sceneObjects = GetAllHierarchyObjects ();
EditorUtility.DisplayProgressBar ("Find Missing Script Components", "Searching for missing MonoBehaviours...", 0.4f);
StringBuilder sb = new StringBuilder ();
List<SerializedObject> missingComponents = FindObjectsWithMissingComponents (sceneObjects, sb);
EditorUtility.DisplayProgressBar ("Find Missing Script Components", "Searching for missing MonoBehaviours...", 0.5f);
if (missingComponents.Count > 0)
{
sb.Insert (0, "Scenes will be modified and saved:\n\n");
if (EditorUtility.DisplayDialog ("Remove missing script components?", sb.ToString (), "Remove All", "Cancel"))
{
foreach (SerializedObject serializedObject in missingComponents)
{
SerializedProperty serializedProperty = serializedObject.GetIterator ();
while (serializedProperty.Next (true))
{
RemoveMissingScriptComponentProperty (serializedProperty, serializedObject.context);
}
serializedObject.ApplyModifiedProperties ();
serializedObject.Update ();
EditorSceneManager.MarkSceneDirty ((serializedObject.targetObject as GameObject).scene);
}
SaveScenes ();
}
}
else
{
EditorUtility.DisplayDialog ("No missing script components found!", "Nothing to do here :)", "Ok, cool!");
}
EditorUtility.ClearProgressBar ();
}
private static GameObject[] GetAllHierarchyObjects ()
{
// Filter out hidden GOs and referenced prefabs
return Resources.FindObjectsOfTypeAll<GameObject> ()
.Where (o => string.IsNullOrEmpty (AssetDatabase.GetAssetPath (o)) && o.hideFlags == HideFlags.None)
.ToArray ();
}
private static List<SerializedObject> FindObjectsWithMissingComponents (GameObject[] sceneObjects, StringBuilder sb)
{
List<SerializedObject> missingComponents = new List<SerializedObject> ();
for (int i = 0; i < sceneObjects.Length; i++)
{
Component[] components = sceneObjects[i].GetComponents<Component> ();
for (int j = 0; j < components.Length; j++)
{
if (components[j] == null)
{
missingComponents.Add (new SerializedObject (sceneObjects[i]));
sb.AppendLine (sceneObjects[i].transform.root.name + " -> " + sceneObjects[i].name);
}
}
}
return missingComponents;
}
private static void RemoveMissingScriptComponentProperty (SerializedProperty serializedProperty, UnityEngine.Object context)
{
if (serializedProperty.propertyType == SerializedPropertyType.ObjectReference &&
serializedProperty.objectReferenceValue == null &&
serializedProperty.objectReferenceInstanceIDValue != 0)
{
bool success = serializedProperty.DeleteCommand ();
if (success == false)
{
Debug.LogError ("Missing component could not be deleted!", context);
throw new Exception ();
}
}
}
private static void SaveScenes ()
{
bool success = EditorSceneManager.SaveOpenScenes ();
if (success == false)
{
Debug.LogError ("Error saving scenes!");
throw new Exception ();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment