• 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>.*?)
    ");
    128             if (idMatch.Success)
    129             {
    130                 // 获取 MonoBehavior的fileID 
    131                 string fileID = idMatch.Groups["idValue"].Value;
    132                 Regex regex = new Regex("  - (.*): {fileID: " + fileID + "}
    ");
    133                 input = regex.Replace(input, "");
    134             }
    135 
    136             return input;
    137         }
    138     }
    139 }

    另外,在实践的过程中遇到了一个报错,顺便记录一下:

    CheckConsistency: GameObject does not reference component MonoBehaviour. Fixing.

    看下图,正常情况下prefab文件中区域1和区域2是对应的,如果不对应会报以上错误。

  • 相关阅读:
    vim实用技巧
    《C程序设计语言》学习笔记
    《鸟哥的Linux私房菜:服务器搭建篇》第一部分学习笔记
    入职培训学习心得
    [NOI2013]树的计数
    bzoj1779 [Usaco2010 Hol]Cowwar 奶牛战争(网络流)
    P2944 [USACO09MAR]地震损失2Earthquake Damage 2(网络流)
    bzoj3218 a + b Problem(网络流+主席树)
    P4542 [ZJOI2011]营救皮卡丘(Floyd+网络流)
    P4843 清理雪道(上下界网络流)
  • 原文地址:https://www.cnblogs.com/luguoshuai/p/12323186.html
Copyright © 2020-2023  润新知