Last active
April 16, 2018 15:37
-
-
Save marcgpuig/86c76004c3ec6f12d21a246025f0d43c to your computer and use it in GitHub Desktop.
Basic Unity script for searching missing scripts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Copyright (c) 2017, Marc Garcia Puig | |
/// | |
/// This work is licensed under the terms of the MIT license. | |
/// For a copy, see <https://opensource.org/licenses/MIT>. | |
/// | |
/// This script provides you the ability to check all your | |
/// prefabs in the Assets folder and see if any of them have | |
/// missing scripts. You can spawn them with a single click | |
/// and clear all the containing missing scripts. | |
/// Remember to apply the changes to each prefab. | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEditor; | |
public class ScriptFixer : EditorWindow | |
{ | |
public Dictionary<string, GameObject> output = new Dictionary<string, GameObject>(); | |
public Dictionary<string, GameObject> spawned = new Dictionary<string, GameObject>(); | |
public string contains = ""; | |
public bool autoSearch = false; | |
public bool showOnlyMissing = true; | |
private string extension = "prefab"; | |
private Vector2 outputScroll; | |
[MenuItem("Synthia/ScriptFixer")] | |
static void ShowWindow() | |
{ | |
ScriptFixer window = (ScriptFixer)EditorWindow.GetWindow(typeof(ScriptFixer)); | |
window.Show(); | |
} | |
/// <summary> | |
/// Check if a GameObject have a missing component. | |
/// </summary> | |
/// <param name="go">The GameObject that we want to analyse</param> | |
/// <returns></returns> | |
private bool HasMissingComponent(GameObject go) | |
{ | |
if (go == null) return false; | |
Component[] com = go.GetComponentsInChildren<Component>(); | |
foreach (Component c in com) if (c == null) return true; | |
return false; | |
} | |
/// <summary> | |
/// Search for all prefabs inside the Assets folder. | |
/// </summary> | |
private void Search() | |
{ | |
output.Clear(); | |
string[] assets = AssetDatabase.GetAllAssetPaths(); | |
foreach (string asset in assets) | |
{ | |
if (asset.Contains(".") && asset.Split('.')[0].Contains(contains)) | |
{ | |
if (extension == "" || asset.Split('.')[1].Contains(extension)) | |
{ | |
output.Add(asset, (GameObject)AssetDatabase.LoadAssetAtPath(asset, typeof(GameObject))); | |
} | |
} | |
} | |
} | |
/// <summary> | |
/// Deletes all the missing scripts from the given game objects. | |
/// Thanks to https://answers.unity.com/answers/863155/view.html | |
/// </summary> | |
/// <param name="objects">List of GameObjects that we want to clean</param> | |
static void CleanupMissingScripts(GameObject[] objects) | |
{ | |
for (int i = 0; i < objects.Length; i++) | |
{ | |
// We must use the GetComponents array to actually detect missing components | |
Component[] components = objects[i].GetComponents<Component>(); | |
// Create a serialized object so that we can edit the component list | |
SerializedObject serializedObject = new SerializedObject(objects[i]); | |
// Find the component list property | |
SerializedProperty prop = serializedObject.FindProperty("m_Component"); | |
// Track how many components we've removed | |
int r = 0; | |
// Iterate over all components | |
for (int j = 0; j < components.Length; j++) | |
{ | |
// Check if the ref is null | |
if (components[j] == null) | |
{ | |
// If so, remove from the serialized component array | |
prop.DeleteArrayElementAtIndex(j - r); | |
// Increment removed count | |
r++; | |
} | |
} | |
// Apply our changes to the game object | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
private void OnGUI() | |
{ | |
EditorGUIUtility.labelWidth = 70; | |
GUILayout.Space(5); | |
contains = EditorGUILayout.TextField("Contains:", contains); | |
EditorGUILayout.BeginHorizontal(); | |
{ | |
EditorGUIUtility.labelWidth = 80; | |
autoSearch = EditorGUILayout.Toggle("AutoSearch", autoSearch); | |
EditorGUIUtility.labelWidth = 120; | |
GUILayout.FlexibleSpace(); | |
showOnlyMissing = EditorGUILayout.Toggle("Show Only Missing", showOnlyMissing); | |
EditorGUIUtility.labelWidth = 70; | |
} | |
EditorGUILayout.EndHorizontal(); | |
if (!autoSearch) | |
GUILayout.Space(10); | |
// Search | |
if (!autoSearch && GUILayout.Button("Search", GUILayout.Height(20)) || (autoSearch && GUI.changed)) | |
{ | |
Search(); | |
} | |
// Remove all spawned GameObjects | |
if (GUILayout.Button("Remove all spawned GameObjects", GUILayout.Height(20))) | |
{ | |
foreach (KeyValuePair<string, GameObject> s in spawned) | |
{ | |
DestroyImmediate(s.Value); | |
} | |
spawned.Clear(); | |
} | |
GUILayout.Space(10); | |
EditorGUILayout.BeginVertical(GUI.skin.box); | |
{ | |
// Object List | |
outputScroll = EditorGUILayout.BeginScrollView(outputScroll); | |
{ | |
foreach (KeyValuePair<string, GameObject> s in output) | |
{ | |
Color oldColor = GUI.color; | |
bool lostComp = HasMissingComponent(s.Value); | |
if (!lostComp) | |
{ | |
if (showOnlyMissing) continue; | |
} | |
else | |
{ | |
GUI.color = Color.red; | |
} | |
EditorGUILayout.BeginHorizontal(GUI.skin.box); | |
{ | |
GUI.color = oldColor; | |
if (!spawned.ContainsKey(s.Key)) | |
{ | |
if (GUILayout.Button("+", GUILayout.Width(19))) | |
{ | |
if (s.Value.GetComponent<Transform>()) | |
{ | |
spawned.Add(s.Key, (GameObject)(Selection.activeObject = PrefabUtility.InstantiatePrefab(s.Value))); | |
} | |
} | |
} | |
else | |
{ | |
GUI.color = new Color(0.75f,0.75f,1f); | |
if (GUILayout.Button("-", GUILayout.Width(19))) | |
{ | |
if (s.Value.GetComponent<Transform>()) | |
{ | |
GameObject.DestroyImmediate(spawned[s.Key]); | |
spawned.Remove(s.Key); | |
} | |
} | |
GUI.color = oldColor; | |
if (lostComp && GUILayout.Button("Clear Missing Components", GUILayout.Width(170))) | |
{ | |
GameObject[] objs = new GameObject[spawned[s.Key].transform.childCount + 1]; | |
int i = 0; | |
foreach (Transform child in spawned[s.Key].transform) | |
{ | |
objs[i] = child.gameObject; | |
i++; | |
} | |
objs[i] = spawned[s.Key]; | |
CleanupMissingScripts(objs); | |
} | |
} | |
EditorGUILayout.LabelField(new GUIContent(s.Key.Split('/')[s.Key.Split('/').Length - 1], s.Key)); | |
} | |
EditorGUILayout.EndHorizontal(); | |
} | |
GUILayout.FlexibleSpace(); | |
} | |
EditorGUILayout.EndScrollView(); | |
} | |
EditorGUILayout.EndVertical(); | |
EditorGUILayout.LabelField(output.Count.ToString() + " found."); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment