Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Showcase Search Missing Mono Script

Discussion in 'Editor & General Support' started by makaolachsiungca, Oct 11, 2023.

  1. makaolachsiungca

    makaolachsiungca

    Joined:
    Sep 27, 2019
    Posts:
    31
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.IO;
    3. using System.Linq;
    4. using System.Text.RegularExpressions;
    5. using UnityEditor;
    6. using UnityEngine;
    7. using Object = UnityEngine.Object;
    8. using UnityEditor.Build.Content;
    9.  
    10. static class GUIDValidator
    11. {
    12.     /// <summary>
    13.     /// Simple function to valid <see cref="GameObject"/> asset with missing reference <see cref="MonoBehaviour"/>.
    14.     /// </summary>
    15.     /// <param name="go">Required persistent gameObject asset which provide serialized YAML file.</param>
    16.     public static void SearchMissingMonoBehaviour(GameObject go)
    17.     {
    18.         // check missing script by official method
    19.         var invalidNum = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(go);
    20.  
    21.         if (invalidNum == 0)
    22.             return;
    23.  
    24.         // get all mono components
    25.         var monos = go.GetComponents<MonoBehaviour>();
    26.  
    27.         // create filter with existing mono script asset
    28.         var existCache = monos.Where(mono => mono != null).Select(mono => MonoScript.FromMonoBehaviour(mono).GetAssetGUID()).ToHashSet();
    29.         Debug.Log($"Exist mono count [{existCache.Count}] :\n{string.Join("\n", existCache)}");
    30.  
    31.         // cache the guid which doesn't exist in existCache
    32.         var hashCache = new HashSet<string>();
    33.  
    34.         // valid searching target that should be as serializeable presistent file in this sample, otherwise it also could be scene file
    35.         if (ObjectIdentifier.TryGetObjectIdentifier(go, out var obj_id))
    36.         {
    37.             Debug.Log($"[{obj_id.fileType}] - {obj_id.localIdentifierInFile}");
    38.  
    39.             if (obj_id.fileType == FileType.MetaAssetType)
    40.             {
    41.                 var path = AssetDatabase.GUIDToAssetPath(obj_id.guid);
    42.                 var metaFile = File.OpenText(path).ReadToEnd();
    43.                 var guids = GetMonoBehaviourGUIDs(metaFile);
    44.  
    45.                 if (guids!=null && guids.Length>0)
    46.                 {
    47.                     foreach (var guid in guids)
    48.                     {
    49.                         if (existCache.Contains(guid))
    50.                             continue;
    51.  
    52.                         hashCache.Add(guid);
    53.                     }
    54.  
    55.                     Debug.Log($"Missing reference guids :\n" + string.Join("\n", hashCache));
    56.                 }
    57.             }
    58.             else if (obj_id.fileType == FileType.SerializedAssetType)
    59.             {
    60.                 // native asset like texture or anim
    61.                 Debug.Log(go);
    62.             }
    63.             else
    64.                 Debug.LogError($"NotImplemented asset tpye [{obj_id.fileType}].");
    65.         }
    66.         else
    67.             Debug.LogError($"Failure to find target [{go}] on disk");
    68.     }
    69.  
    70.     /// <summary>
    71.     /// Get asset guid.
    72.     /// </summary>
    73.     public static string GetAssetGUID<T>(this T asset, AssetPathToGUIDOptions options = AssetPathToGUIDOptions.OnlyExistingAssets) where T : Object
    74.     {
    75.         string guid;
    76.  
    77.         if (ObjectIdentifier.TryGetObjectIdentifier(asset, out var id))
    78.         {
    79.             guid = id.guid.ToString();
    80.             //Debug.Log($"Get guid from : {id.fileType}.");
    81.         }
    82.         else
    83.         {
    84.             Debug.LogError("Failure to get asset identifier.");
    85.             var path = AssetDatabase.GetAssetPath(asset);
    86.             guid = AssetDatabase.AssetPathToGUID(path, options);
    87.         }
    88.  
    89.         return guid;
    90.     }
    91.  
    92.     /// <summary>
    93.     /// Get mono script binding from serialize file.
    94.     /// </summary>
    95.     static string[] GetMonoBehaviourGUIDs(string context)
    96.     {
    97.         var regex = new Regex(@"m_Script:\s*{fileID:\s*(\d+),\s*guid:\s*([a-fA-F0-9]+),\s*type:\s*[0-9]}");
    98.         var matches = regex.Matches(context);
    99.  
    100.         Debug.Log($"Find [{matches.Count}] mono script.");
    101.  
    102.         HashSet<string> guids = new(matches.Count);
    103.  
    104.         foreach (Match match in matches)
    105.         {
    106.             if (match.Success)
    107.             {
    108.                 string fileId = match.Groups[1].Value;
    109.                 string guid = match.Groups[2].Value;
    110.                 string type = match.Groups[3].Value;
    111.  
    112.                 guids.Add(guid);
    113.             }
    114.         }
    115.  
    116.         return guids.ToArray();
    117.     }
    118. }