Search Unity

Remove all missing reference Behaviours

Discussion in 'Editor & General Support' started by thienhaflash, Dec 21, 2014.

  1. thienhaflash

    thienhaflash

    Joined:
    Jun 16, 2012
    Posts:
    513
    Hello everyone,

    Does anyone know how to remove all missing monobehaviours in the scene and all prefabs by editor script ? I did do some search but still not find a way to do. Is it doable ? Can anyone point me to the right direction ?

    Thanks a lot.
     
  2. fffMalzbier

    fffMalzbier

    Joined:
    Jun 14, 2011
    Posts:
    3,276
  3. thienhaflash

    thienhaflash

    Joined:
    Jun 16, 2012
    Posts:
    513
    I can find it, actually. Just don't know a way to remove those missing behaviours but manually do it one by one.

    Thanks for your help anyway
     
  4. fffMalzbier

    fffMalzbier

    Joined:
    Jun 14, 2011
    Posts:
    3,276
    You could add somting like DestroyImmediate(components); to line 51 of the script , that should delete the missing component entry (NOT TESTED USE WITH CAUTION)
     
  5. thienhaflash

    thienhaflash

    Joined:
    Jun 16, 2012
    Posts:
    513
    Tried that before, but those components are already null, you can not destroy them :(
     
    CloudyVR likes this.
  6. Danny_HoW

    Danny_HoW

    Joined:
    May 4, 2012
    Posts:
    47
  7. ferretnt

    ferretnt

    Joined:
    Apr 10, 2012
    Posts:
    412
    Even after removing the interpolated strings so I can run it on the version of Mono we're using, that didn't work for me in 2017.3. It does clearly remove many behaviours (reading the diff of the scene), but quite a few then get added back when you hit play with the message:

    CheckConsistency: GameObject does not reference component MonoBehaviour. Fixing.
     
  8. Brogan89

    Brogan89

    Joined:
    Jul 10, 2014
    Posts:
    244
    Capture.PNG

    Looks like I have to go through them all manually :(
    Don't change Nested Prefab library mid project people. It makes for a long day.

    Edit:
    It actually did delete them, it just didn't print properly. Thanks for the code mate :)
     
    Last edited: Feb 10, 2018
    Beloudest likes this.
  9. Danny_HoW

    Danny_HoW

    Joined:
    May 4, 2012
    Posts:
    47
    hehe no problem, glad it helped :)
     
    wbarteck likes this.
  10. Saeleas

    Saeleas

    Joined:
    Sep 23, 2017
    Posts:
    11
    Did you find any way to fix that error? I'm having the same issue.
     
  11. ferretnt

    ferretnt

    Joined:
    Apr 10, 2012
    Posts:
    412
    No, it's on the very long list of things we've just learned not to care too much about. There are many such things in the life of an app developer. Our iTunes Connect console is filled with dead apps that we have no way to remove. Our older codebases are filled with zombie monobehaviours. Xcode likes to make a new provisioning profile every time you breathe. The only way forward is just to not care and keep on shipping stuff.
     
    chriszul and fffMalzbier like this.
  12. IgorAherne

    IgorAherne

    Joined:
    May 15, 2013
    Posts:
    393
    Last edited: Dec 29, 2019
  13. Schmaggis

    Schmaggis

    Joined:
    Sep 2, 2017
    Posts:
    2
    Hello!
    Sadly the Code does not find any Missing Scripts :-/

    int count = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(gameObject);
    Debug.Log($"Found {count} missing scripts");
    count = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(gameObject);
    Debug.Log($"Removed {count} missing scripts");

    Count is always 0 even if gameObject does have "null-scripts".

    With the old method it still finds the missing scripts but the "prop.DeleteArrayElementAtIndex" ist nit supported any more in Unity 2019... Is there another way to delete missing scripts from the serializedObject-Property "m_Component"?
    Thanks!
     
  14. chechoggomez

    chechoggomez

    Unity Technologies

    Joined:
    Feb 25, 2013
    Posts:
    91
    Hi @Schmaggis, which version of Unity are you using?
    I just tried the code you are using and this is the result I am getting with 2019.2.15f1:

     
  15. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Do you mind to share the script? this new Prefab workflow API confused me
     
  16. Brogan89

    Brogan89

    Joined:
    Jul 10, 2014
    Posts:
    244
    Code (CSharp):
    1.     public class RemoveMissingScripts : Editor
    2.     {
    3.         [MenuItem("GameObject/Remove Missing Scripts")]
    4.         public static void Remove()
    5.         {
    6.             var objs = Resources.FindObjectsOfTypeAll<GameObject>();
    7.             int count = objs.Sum(GameObjectUtility.RemoveMonoBehavioursWithMissingScript);
    8.             Debug.Log($"Removed {count} missing scripts");
    9.         }
    10.     }
     
  17. MurphyMurph_21

    MurphyMurph_21

    Joined:
    Jul 3, 2020
    Posts:
    73

    Thank you so much Brogan89, you are a lifesaver, I've seen so many complicated methods that just couldn't get the job done and you have found the simplest solution. Thanks again and God bless!
     
    Brogan89 likes this.
  18. Muchaszewski

    Muchaszewski

    Joined:
    Sep 23, 2015
    Posts:
    15
    FYI, non of those presented options here works in some edge cases.

    This is the result of Brogan89 script, nothing helps in my case :(
    I think I need to go through 600 missing references manually :/
    yyy.gif
     
  19. Brogan89

    Brogan89

    Joined:
    Jul 10, 2014
    Posts:
    244
    Yeah I just had this happen as well. It removed the scripts from the prefabs but once I saved it reverted all the missing scripts back o_O

    However, I have another window I made which may be of worth to you. It just helps find the prefabs or whatever with missing scripts.

    Code (CSharp):
    1.  
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using UnityEditor;
    5. using UnityEngine;
    6.  
    7. public class FindMissingScriptsWindow : EditorWindow
    8. {
    9.    [MenuItem("Window/Missing Script Window")]
    10.    private static void Init()
    11.    {
    12.       GetWindow<FindMissingScriptsWindow>("Missing Script Finder").Show();
    13.    }
    14.  
    15.    public List<GameObject> results = new List<GameObject>();
    16.  
    17.    private void OnGUI()
    18.    {
    19.       if (GUILayout.Button("Search Project"))
    20.          SearchProject();
    21.       if (GUILayout.Button("Search scene"))
    22.          SearchScene();
    23.       if (GUILayout.Button("Search Selected Objects"))
    24.          SearchSelected();
    25.    
    26.       // src: https://answers.unity.com/questions/859554/editorwindow-display-array-dropdown.html
    27.       var so = new SerializedObject(this);
    28.       var resultsProperty = so.FindProperty(nameof(results));
    29.       EditorGUILayout.PropertyField(resultsProperty, true);
    30.       so.ApplyModifiedProperties();
    31.    }
    32.  
    33.    private void SearchProject()
    34.    {
    35.       results = AssetDatabase.FindAssets("t:Prefab")
    36.          .Select(AssetDatabase.GUIDToAssetPath)
    37.          .Select(AssetDatabase.LoadAssetAtPath<GameObject>)
    38.          .Where(x => IsMissing(x, true))
    39.          .Distinct()
    40.          .ToList();
    41.    }
    42.  
    43.    private void SearchScene()
    44.    {
    45.       results = FindObjectsOfType<GameObject>()
    46.          .Where(x => IsMissing(x, false))
    47.          .Distinct()
    48.          .ToList();
    49.    }
    50.  
    51.    private void SearchSelected()
    52.    {
    53.       results = Selection.gameObjects
    54.          .Where(x => IsMissing(x, false))
    55.          .Distinct()
    56.          .ToList();
    57.    }
    58.  
    59.    private static bool IsMissing(GameObject go, bool includeChildren)
    60.    {
    61.       var components = includeChildren
    62.          ? go.GetComponentsInChildren<Component>()
    63.          : go.GetComponents<Component>();
    64.    
    65.       return components.Any(x => x == null);
    66.    }
    67. }
    68.  
     
    Jamez0r likes this.
  20. dcomptonambrose

    dcomptonambrose

    Joined:
    May 9, 2020
    Posts:
    8
    I have an error message that just lists the missing script, "Error while saving prefab: 'Assets/XXXX/XXXXX/etc'" and says "You are trying to save a Prefab with a missing script. This is not allowed." Well, I found its folder. Couldn't I just go into the asset folder and delete its file? (Edit: All I've done so far is try importing it, beyond that I haven't done anything with the asset except download it from the assetstore)
     
  21. euivtui4h

    euivtui4h

    Joined:
    Aug 28, 2017
    Posts:
    4
    Wrote a fix that works Unity 2020.1 NOTE : Works for Prefabs found at a given Path, but can be easily adapted for gameobjects in a scene. Heavilly inspired from https://www.programmersought.com/article/431675062/ (thanks!)

    Code (CSharp):
    1. Wrote a fix that works Unity 2020.1
    2. NOTE : Works for Prefabs found at a given Path, but can be easily adapted for gameobjects in a scene.
    3. Heavilly inspired from https://www.programmersought.com/article/431675062/ (thanks!)
    4.  
    5.     using UnityEngine;
    6.     #if UNITY_EDITOR
    7.     using UnityEditor;
    8.     public static class Tool_RemoveMissingComponent
    9.     {
    10.         /// <summary>
    11.         /// DOES :
    12.         /// Remove missing scripts in prefabs found at PATH, then save prefab.
    13.         /// Saved prefab will have no missing scripts left.
    14.         /// Will not mod prefabs that dont have missing scripts.
    15.         ///
    16.         /// NOTE :
    17.         /// If prefab has another prefab#2 that is not in PATH, that prefab#2 will still have missing scripts.
    18.         /// The instance of the prefab#2 in prefab will not have missing scripts (thus counted has override of prefab#2)
    19.         ///
    20.         /// HOW TO USE :
    21.         /// Copy code in script anywhere in project.
    22.         /// Set the PATH var in method <see cref="RemoveMissingScripstsInPrefabsAtPath"/>.
    23.         /// Clik the button.
    24.         /// </summary>
    25.    
    26.         [MenuItem("Tools/FixingStuff/Remove MissingComponents in Prefabs at Path")]
    27.         public static void RemoveMissingScripstsInPrefabsAtPath()
    28.         {
    29.             string PATH = "Assets/Prefabs";
    30.    
    31.             EditorUtility.DisplayProgressBar("Modify Prefab", "Please wait...", 0);
    32.             string[] ids = AssetDatabase.FindAssets("t:Prefab", new string[] { PATH});
    33.             for (int i = 0; i < ids.Length; i++)
    34.             {
    35.                 string path = AssetDatabase.GUIDToAssetPath(ids[i]);
    36.                 GameObject prefab = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject;
    37.                 GameObject instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
    38.    
    39.                 int delCount = 0;
    40.                 RecursivelyModifyPrefabChilds(instance, ref delCount);
    41.    
    42.                 if (delCount > 0)
    43.                 {
    44.                     Debug.Log($"Removed({delCount}) on {path}", prefab);
    45.                     PrefabUtility.SaveAsPrefabAssetAndConnect(instance, path, InteractionMode.AutomatedAction);
    46.                 }
    47.    
    48.                 UnityEngine.Object.DestroyImmediate(instance);
    49.                 EditorUtility.DisplayProgressBar("Modify Prefab", "Please wait...", i / (float)ids.Length);
    50.             }
    51.             AssetDatabase.SaveAssets();
    52.             EditorUtility.ClearProgressBar();
    53.         }
    54.    
    55.         private static void RecursivelyModifyPrefabChilds(GameObject obj, ref int delCount)
    56.         {
    57.             if (obj.transform.childCount > 0)
    58.             {
    59.                 for (int i = 0; i < obj.transform.childCount; i++)
    60.                 {
    61.                     var _childObj = obj.transform.GetChild(i).gameObject;
    62.                     RecursivelyModifyPrefabChilds(_childObj, ref delCount);
    63.                 }
    64.             }
    65.    
    66.             int innerDelCount = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(obj);
    67.             delCount += innerDelCount;
    68.         }
    69.    
    70.     }
    71.    
    72.     #endif
    73.  
    74.  
    75.  
     
    Pnvanol, megame_dev, pverflow and 5 others like this.
  22. Jamez0r

    Jamez0r

    Joined:
    Jul 29, 2019
    Posts:
    205
    This thread saved my butt, thanks you guys! Wish Unity would have something built-in for this...
     
  23. ngfilms

    ngfilms

    Joined:
    Nov 18, 2015
    Posts:
    30
    works great thank you
    public class RemoveMissingScripts : Editor (Window)
     
  24. angryabdullah0003

    angryabdullah0003

    Joined:
    Jan 19, 2022
    Posts:
    1
    using UnityEditor;
    using UnityEngine;

    namespace FLGCoreEditor.Utilities
    {
    public class FindMissingScriptsRecursivelyAndRemove : EditorWindow
    {
    private static int _goCount;
    private static int _componentsCount;
    private static int _missingCount;

    private static bool _bHaveRun;

    [MenuItem("FLGCore/Editor/Utility/FindMissingScriptsRecursivelyAndRemove")]
    public static void ShowWindow()
    {
    GetWindow(typeof(FindMissingScriptsRecursivelyAndRemove));
    }

    public void OnGUI()
    {
    if (GUILayout.Button("Find Missing Scripts in selected GameObjects"))
    {
    FindInSelected();
    }

    if (!_bHaveRun) return;

    EditorGUILayout.TextField($"{_goCount} GameObjects Selected");
    if (_goCount > 0) EditorGUILayout.TextField($"{_componentsCount} Components");
    if (_goCount > 0) EditorGUILayout.TextField($"{_missingCount} Deleted");
    }

    private static void FindInSelected()
    {
    var go = Selection.gameObjects;
    _goCount = 0;
    _componentsCount = 0;
    _missingCount = 0;
    foreach (var g in go)
    {
    FindInGo(g);
    }

    _bHaveRun = true;
    Debug.Log($"Searched {_goCount} GameObjects, {_componentsCount} components, found {_missingCount} missing");

    AssetDatabase.SaveAssets();
    }

    private static void FindInGo(GameObject g)
    {

    _goCount++;
    var components = g.GetComponents<Component>();
    GameObjectUtility.RemoveMonoBehavioursWithMissingScript(g);

    var r = 0;

    for (var i = 0; i < components.Length; i++)
    {
    _componentsCount++;
    if (components != null) continue;
    _missingCount++;
    var s = g.name;
    var t = g.transform;
    while (t.parent != null)
    {
    s = t.parent.name + "/" + s;
    t = t.parent;
    }

    Debug.Log($"{s} has a missing script at {i}", g);
    }

    foreach (Transform childT in g.transform)
    {
    FindInGo(childT.gameObject);
    }
    }
    }
    }
     
  25. zezba9000

    zezba9000

    Joined:
    Sep 28, 2010
    Posts:
    985
    Correct way that works for open Prefabs as well.

    Code (CSharp):
    1. #if UNITY_EDITOR
    2. using UnityEditor;
    3. using UnityEngine;
    4. using System.Linq;
    5.  
    6. public class EditorHelpers : Editor
    7. {
    8.     [MenuItem("GameObject/Missing Scripts/Remove", true, 0)]
    9.     private static bool RemoveMissingScripts_OnPrefabs_Validate()
    10.     {
    11.         return Selection.objects != null && Selection.objects.All(x => x.GetType() == typeof(GameObject));
    12.     }
    13.  
    14.     [MenuItem("GameObject/Missing Scripts/Remove", false, 0)]
    15.     private static void RemoveMissingScripts_OnPrefabs()
    16.     {
    17.         foreach (var obj in Selection.gameObjects)
    18.         {
    19.             RemoveMissingScripts_OnPrefabs_Recursive(obj);
    20.         }
    21.     }
    22.  
    23.     private static void RemoveMissingScripts_OnPrefabs_Recursive(GameObject obj)
    24.     {
    25.         // list missing on this object
    26.         if (GameObjectUtility.RemoveMonoBehavioursWithMissingScript(obj) != 0)
    27.         {
    28.             Debug.Log($"REMOVED: Missing Scripts on object '{obj.name}'");
    29.         }
    30.  
    31.         // scan childeren
    32.         foreach (Transform transform in obj.transform)
    33.         {
    34.             RemoveMissingScripts_OnPrefabs_Recursive(transform.gameObject);
    35.         }
    36.     }
    37.  
    38.     [MenuItem("GameObject/Missing Scripts/List", true, 0)]
    39.     private static bool ListMissingScripts_OnPrefabs_Validate()
    40.     {
    41.         return Selection.objects != null && Selection.objects.All(x => x.GetType() == typeof(GameObject));
    42.     }
    43.  
    44.     [MenuItem("GameObject/Missing Scripts/List", false, 0)]
    45.     private static void ListMissingScripts_OnPrefabs()
    46.     {
    47.         foreach (var obj in Selection.gameObjects)
    48.         {
    49.             ListMissingScripts_OnPrefabs_Recursive(obj);
    50.         }
    51.     }
    52.  
    53.     private static void ListMissingScripts_OnPrefabs_Recursive(GameObject obj)
    54.     {
    55.         // list missing on this object
    56.         if (GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(obj) != 0)
    57.         {
    58.             Debug.Log($"Missing Script on object '{obj.name}'");
    59.         }
    60.  
    61.         // scan childeren
    62.         foreach (Transform transform in obj.transform)
    63.         {
    64.             ListMissingScripts_OnPrefabs_Recursive(transform.gameObject);
    65.         }
    66.     }
    67. }
    68. #endif
     
  26. awaisnaseer0313

    awaisnaseer0313

    Joined:
    May 21, 2022
    Posts:
    1
    This worked for me. thank you
     
  27. Petricevic

    Petricevic

    Joined:
    May 28, 2021
    Posts:
    7
    This worked well in my case. Thank you.
     
  28. Jefflinzer

    Jefflinzer

    Joined:
    Mar 16, 2023
    Posts:
    4
    Do you have any video tutorial on where to place this script?
     
  29. zezba9000

    zezba9000

    Joined:
    Sep 28, 2010
    Posts:
    985
    The script can live anywhere in your project.
     
  30. Nicokam

    Nicokam

    Joined:
    May 28, 2020
    Posts:
    64
    This worked for me too. Thanks!
     
  31. talhakhan9

    talhakhan9

    Joined:
    Sep 6, 2021
    Posts:
    1
    Maybe this would help. This script will find the missing scripts and you can remove them too.
     

    Attached Files:

    EkzekutQr, mxxxxxs and marsilo90 like this.
  32. stigmamax

    stigmamax

    Joined:
    Jun 30, 2014
    Posts:
    310
    Don't forget to delete the script after the operation otherwise Unity refuses to compile the project.
     
  33. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,819
    It's an editor script. You're meant to put it in an folder named Editor, or in an editor-only assembly.
     
  34. stigmamax

    stigmamax

    Joined:
    Jun 30, 2014
    Posts:
    310
    Je le mets juste dans mon dossier Scripts et ça marche !