清理工程目录下所有prefab中丢失的脚本

感谢吴蕴泽的部分代码Unity批处理修改prefab
感谢林新发的部分代码Unity3D编辑器:删掉MissingScirpt脚本

问题:使用其他地方的到的prefab,但是又丢弃了他们的脚本(他们的脚本不适合自己),实例化这个Prefab的时候,会在Editor下打印很多warning消息,这消息会影响加载效率,拖慢加载速度,甚至引起崩溃(在打包出来通过UnityWebRequest加载Bundle没问题,实例化的时候直接崩溃),有的同学会说,我手动删掉就是了呀,但是产品化的prefab往往数量相对庞大,结构相对复杂,一查可能有成百上千个丢失脚本的节点。

需求:将指定目录下所有prefab中丢失的脚本清理掉(递归清理,包括隐藏的节点,清理完成写回prefab)

建立测试环境:
第一步,建立空场景,添加根节点G1,添加两个子节点Child1 Child2 并分别附加一个新建的C#脚本 NewBehaviourScript.cs ,再将Child1隐藏,存储G1存为Prefab
清理工程目录下所有prefab中丢失的脚本_第1张图片

第二步,删掉NewBehaviourScript.cs Apply Prefab:G1
清理工程目录下所有prefab中丢失的脚本_第2张图片

好,这里已经建立起环境了,下面是Editor代码

  [MenuItem("Tools/清理prefab中丢失的脚本")]
    public static void RMLosedComponentInPrefab()
    {
        EditorUtility.DisplayProgressBar("Modify Prefab", "Please wait...", 0);
        string[] ids = AssetDatabase.FindAssets("t:Prefab", new string[] { "Assets/data/testLoseScript" });
        for (int i = 0; i < ids.Length; i++)
        {
            string path = AssetDatabase.GUIDToAssetPath(ids[i]);
            GameObject prefab = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject;
            GameObject instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;

            int delCount = 0;
            RecersiceModifyGameObject(instance, ref delCount);

            if (delCount > 0)
            {
                Debug.Log(instance.name + " remove losed:---- " + delCount);
                // save 
                PrefabUtility.ReplacePrefab(instance, prefab, ReplacePrefabOptions.ConnectToPrefab);
            }
            UnityEngine.Object.DestroyImmediate(instance);
            EditorUtility.DisplayProgressBar("Modify Prefab", "Please wait...", i / (float)ids.Length);
        }
        AssetDatabase.SaveAssets();
        EditorUtility.ClearProgressBar();
    }

    private static void RecersiceModifyGameObject(GameObject obj, ref int delCount)
    {
        //find child
        if (obj.transform.childCount > 0)
        {
            for (int i = 0; i < obj.transform.childCount; i++)
            {
                var _childObj = obj.transform.GetChild(i).gameObject;
                // modify this GameObject
                RecersiceModifyGameObject(_childObj, ref delCount);
            }
        }
        // change instance 
        SerializedObject so = new SerializedObject(obj);
        var soProperties = so.FindProperty("m_Component");
        var components = obj.GetComponents();
        int propertyIndex = 0;
        int innerDelCount = 0;
        foreach (var c in components)
        {
            if (c == null)
            {
                ++delCount;
                ++innerDelCount;
                soProperties.DeleteArrayElementAtIndex(propertyIndex);
            }
            ++propertyIndex;
        }

        if (innerDelCount > 0)
            so.ApplyModifiedProperties();
    }

结果:
清理完成之后是这样的
清理工程目录下所有prefab中丢失的脚本_第3张图片

你可能感兴趣的:(Unity)