unity實現批量刪除Prefab上Miss的腳本組件


感謝:https://www.cnblogs.com/AaronBlogs/p/7976054.html 

我的unity版本: unity2017.2.0p4

本篇文章將根據我個人的實踐進行記錄,有些情況也許沒有考慮進去。隨着unity版本的提升,也許會有現成的api可以直接實現(像unity2019中的GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go),具體沒有測試)

實現目標:

     到       ,並且在后續的操作中圖一的情況不會恢復。

先說明一下,miss腳本的兩種情況:

   在Inpsector面板中看起來是這樣的,打開對應的prefab文件,繼續往下看內在的區別。

執行工具后,prefab文件的變化成了下面的結構:

下面貼上代碼:

 

  1 using System;
  2 using System.IO;
  3 using System.Collections;
  4 using System.Collections.Generic;
  5 using UnityEngine;
  6 using UnityEditor;
  7 using System.Text.RegularExpressions;
  8 
  9 namespace LgsProject
 10 {
 11     public partial class LgsTools_Optimization
 12     {
 13         [MenuItem("LgsTools/智能檢測/Remove Missing-MonoBehavior Component")]
 14         static public void RemoveMissComponent()
 15         {
 16             string fullPath = Application.dataPath + "/Art/Prefabs";
 17             fullPath = fullPath.Replace("/", @"\");
 18             //List<string> pathList = GetAssetsPathByFullPath(fullPath, "*.prefab", SearchOption.AllDirectories);
 19             List<string> pathList = GetAssetsPathByRelativePath(new string[] { "Assets/Art/Prefabs" }, "t:Prefab", SearchOption.AllDirectories);
 20             int counter = 0;
 21             for (int i = 0, iMax = pathList.Count; i < iMax; i++)
 22             {
 23                 EditorUtility.DisplayProgressBar("處理進度", string.Format("{0}/{1}", i + 1, iMax), (i + 1f) / iMax);
 24                 if (CheckMissMonoBehavior(pathList[i]))
 25                     ++counter;
 26             }
 27             EditorUtility.ClearProgressBar();
 28             EditorUtility.DisplayDialog("處理結果", "完成修改,修改數量 : " + counter, "確定");
 29             AssetDatabase.Refresh();
 30         }
 31 
 32         /// <summary>
 33         /// 獲取項目中某種資源的路徑
 34         /// </summary>
 35         /// <param name="fullPath">win的路徑格式,以 "\"為分隔符</param>
 36         /// <param name="filter">win的資源過濾模式 例如 : *.prefab</param>
 37         /// <param name="searchOption">目錄的搜索方式</param>
 38         /// <returns></returns>
 39         static List<string> GetAssetsPathByFullPath(string fullPath, string filter, SearchOption searchOption)
 40         {
 41             List<string> pathList = new List<string>();
 42             string[] files = Directory.GetFiles(fullPath, filter, searchOption);
 43             for (int i = 0; i < files.Length; i++)
 44             {
 45                 string path = files[i];
 46                 path = "Assets" + path.Substring(Application.dataPath.Length, path.Length - Application.dataPath.Length);
 47                 pathList.Add(path);
 48             }
 49 
 50             return pathList;
 51         }
 52 
 53 
 54         /// <summary>
 55         /// 獲取項目中某種資源的路徑
 56         /// </summary>
 57         /// <param name="relativePath">unity路徑格式,以 "/" 為分隔符</param>
 58         /// <param name="filter">unity的資源過濾模式 https://docs.unity3d.com/ScriptReference/AssetDatabase.FindAssets.html </param>
 59         /// <param name="searchOption"></param>
 60         /// <returns></returns>
 61         static List<string> GetAssetsPathByRelativePath(string[] relativePath, string filter, SearchOption searchOption)
 62         {
 63             List<string> pathList = new List<string>();
 64             string[] guids = AssetDatabase.FindAssets(filter, relativePath);
 65             for (int i = 0; i < guids.Length; i++)
 66             {
 67                 string path = AssetDatabase.GUIDToAssetPath(guids[i]);
 68                 pathList.Add(path);
 69             }
 70 
 71             return pathList;
 72         }
 73 
 74         /// <summary>  
 75         /// 刪除一個Prefab上的空腳本  
 76         /// </summary>  
 77         /// <param name="path">prefab路徑 例Assets/Resources/FriendInfo.prefab</param>  
 78         static bool CheckMissMonoBehavior(string path)
 79         {
 80             bool isNull = false;
 81             string textContent = File.ReadAllText(path);
 82             Regex regBlock = new Regex("MonoBehaviour");
 83             // 以"---"划分組件  
 84             string[] strArray = textContent.Split(new string[] { "---" }, StringSplitOptions.RemoveEmptyEntries);
 85             for (int i = 0; i < strArray.Length; i++)
 86             {
 87                 string blockStr = strArray[i];
 88                 if (regBlock.IsMatch(blockStr))
 89                 {
 90                     // 模塊是 MonoBehavior  
 91                     //(?<名稱>子表達式)  含義:將匹配的子表達式捕獲到一個命名組中
 92                     Match guidMatch = Regex.Match(blockStr, "m_Script: {fileID: (.*), guid: (?<GuidValue>.*?), type: [0-9]}");
 93                     if (guidMatch.Success)
 94                     {
 95                         string guid = guidMatch.Groups["GuidValue"].Value;
 96                         if (!File.Exists(AssetDatabase.GUIDToAssetPath(guid)))
 97                         {
 98                             isNull = true;
 99                             textContent = DeleteContent(textContent, blockStr);
100                         }
101                     }
102 
103                     Match fileIdMatch = Regex.Match(blockStr, @"m_Script: {fileID: (?<IdValue>\d+)}");
104                     if (fileIdMatch.Success)
105                     {
106                         string idValue = fileIdMatch.Groups["IdValue"].Value;
107                         if (idValue.Equals("0"))
108                         {
109                             isNull = true;
110                             textContent = DeleteContent(textContent, blockStr);
111                         }
112                     }
113                 }
114             }
115             if (isNull)
116             {
117                 // 有空腳本 寫回prefab  
118                 File.WriteAllText(path, textContent);
119             }
120             return isNull;
121         }
122 
123         // 刪除操作  
124         static string DeleteContent(string input, string blockStr)
125         {
126             input = input.Replace("---" + blockStr, "");
127             Match idMatch = Regex.Match(blockStr, "!u!(.*) &(?<idValue>.*?)\n");
128             if (idMatch.Success)
129             {
130                 // 獲取 MonoBehavior的fileID 
131                 string fileID = idMatch.Groups["idValue"].Value;
132                 Regex regex = new Regex("  - (.*): {fileID: " + fileID + "}\n");
133                 input = regex.Replace(input, "");
134             }
135 
136             return input;
137         }
138     }
139 }

 

另外,在實踐的過程中遇到了一個報錯,順便記錄一下:

CheckConsistency: GameObject does not reference component MonoBehaviour. Fixing.

看下圖,正常情況下prefab文件中區域1和區域2是對應的,如果不對應會報以上錯誤。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM