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是对应的,如果不对应会报以上错误。

posted @ 2020-02-17 19:30  小·糊涂仙  阅读(4249)  评论(1编辑  收藏  举报