Unity-工具-查找丢失资源的Objects

  1. Resources.FindObjectsOfTypeAll
    This function can return any type of Unity object that is loaded, including game objects, prefabs, materials, meshes, textures, etc. It will also list internal stuff, therefore please be extra careful the way you handle the returned objects. Contrary to Object.FindObjectsOfType this function will also list disabled objects.

public SerializedProperty GetIterator();
返回SerializedProperty类
objectReferenceValue 参数:Object索引的相关obj

/// <summary>
/// 检查项目中Missing的Component
/// 如果Component的某些引用丢失,打印报错信息,打印丢失引用GameObject的路径
/// </summary>
public class ReferenceCheck {
    [MenuItem("Tool/CheckLoseReferenceObj")]
    static void CheckLoseRefObj()
    {
        GameObject[] Gos = GetSceneObjects();
        foreach (GameObject item in Gos)
        {
            List<Component> components = new List<Component>();
            item.GetComponents(components);
            foreach (var component in components)
            {
                if (!component)
                {
                    Debug.LogError("Missing Component:" + FullPath(item));
                    continue;
                }
                SerializedObject so = new SerializedObject(component);
                var iter = so.GetIterator();
                while (iter.NextVisible(true))
                {
                    if(iter.propertyType == SerializedPropertyType.ObjectReference)
                    {
                        //引用对象是null并且引用ID不是0 说明丢失了引用
                        if (iter.objectReferenceValue == null && iter.objectReferenceInstanceIDValue != 0)
                        {
                            Debug.LogError("Component miss property:" + FullPath(item));
                        }
                    }
                }
            }
        }
    }


    private static GameObject[] GetSceneObjects()
    {
        return Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[];//遍历整个场景
    }

    private static string FullPath(GameObject go)
    {
        if (go.transform.parent != null)
        {
            return FullPath(go.transform.parent.gameObject) + "/" + go.name;
        }
        else
        {
            return go.name;
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class RefTool : EditorWindow
{
    [MenuItem("Tools/检查/检查MissingReference资源")]
    public static void FindMissing()
    {
        Find();
        foreach (var item in refPaths)
        {
            Debug.Log(item);
        }
    }
    private static Dictionary<UnityEngine.Object, List<UnityEngine.Object>> prefabs = new Dictionary<UnityEngine.Object, List<UnityEngine.Object>>();
    private static Dictionary<UnityEngine.Object, string> refPaths = new Dictionary<UnityEngine.Object, string>();
    private static void Find()
    {
        prefabs.Clear();
        string[] allassetpaths = AssetDatabase.GetAllAssetPaths();
        //获取所有资源路径 
        var gos = allassetpaths
            .Where(a => a.EndsWith("prefab"))//筛选 是以prefab为后缀的 预设体资源 
            .Select(a => AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(a));//加载这个预设体
                                                                               //gos拿到的是所有加载好的预设体 

        foreach (var item in gos) {
            GameObject go = item as GameObject;
            if (go) {
                Component[] cps = go.GetComponentsInChildren<Component>(true);//获取这个物体身上所有的组件 
                foreach (var cp in cps)//遍历每一个组件 
                {
                    if (!cp)
                    {
                        if (!prefabs.ContainsKey(go))
                        { prefabs.Add(go, new List<UnityEngine.Object>() { cp });
                        } else
                        { prefabs[go].Add(cp);
                        } continue;
                    }
                    SerializedObject so = new SerializedObject(cp);//生成一个组件对应的S俄日阿里则对Object对象 用于遍历这个组件的所有属性 
                    var iter = so.GetIterator();//拿到迭代器 
                    while (iter.NextVisible(true))//如果有下一个属性 
                    { //如果这个属性类型是引用类型的 
                        if (iter.propertyType == SerializedPropertyType.ObjectReference)
                        { //引用对象是null 并且 引用ID不是0 说明丢失了引用 
                            if (iter.objectReferenceValue == null && iter.objectReferenceInstanceIDValue != 0)
                            {
                                if (!refPaths.ContainsKey(cp)) refPaths.Add(cp, iter.propertyPath);
                                else refPaths[cp] += " | " + iter.propertyPath;
                                if (prefabs.ContainsKey(go))
                                {
                                    if (!prefabs[go].Contains(cp)) prefabs[go].Add(cp);
                                }
                                else
                                {
                                    prefabs.Add(go, new List<UnityEngine.Object>() { cp });
                                }
                            }
                        }
                    }
                }
            }
        }
        EditorUtility.DisplayDialog("", "就绪", "OK");
    }
}
AssetDatabase-FindAssets

filter中可以包括名称、标签或者类型(类名称)
Name:
名称通过空格隔开当成一个独立的名字来搜索。比如"Texture Player",隔开的字段可以用来筛选,Texture和Player都可以进行查找
Labels:Assets可以通过labels附加来进行查找,Assets可以通过关键字'l:'加一个label来进行查找。
Types:在资源类型前加关键字't:',来过滤字符串中包含多个类型。

Types(包括以下):
Prefab
Object
Shader
Material
Texture
Font
Flare
Cubemap

public static string[] FindAssets(string filter);
public static string[] FindAssets(string filter, string[] searchInFolders);
当使用带路径的重载的时候,路径是一个字符串数组,并且这个路径是"Assets"这样的相对路径,此方法会遍历路径下全部文件包括,目标文件下的全部子文件。


SerializedObject and SerializedProperty are classes for editing properties on objects in a completely generic way that automatically handles undo and styling UI for prefabs.

SerializedObject is used in conjunction with SerializedProperty and Editor classes.


这个版本将原本的函数进一步抽象,将简单的方法暴露,方便编程人员的使用
提高资源检查的和复用性,在Match方法中,如果是场景,通过EditorSceneManager.OpenScene打开场景,通过此方法的返回值scene,调用方法GetRootGameObjects,拿到场景中的根GameObjects,在遍历Root下面的全部GameObjects
如果不是Scene文件,是其他类型的资产,直接使用AssetDatabase.LoadAllAssetsAtPath方法,拿到全部资产,将全部资产遍历,使用序列化的方式遍历每个资产。

using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;

using System.IO;
using System.Linq;
using System.Collections;

namespace SPGF.Tools
{
    public static class FindMissingReferences
    {
        [MenuItem("Tools/Find Missing References (UI)", false, 200)]
        static private void RunUI()
        {
            var artsPath = Path.Combine(Utils.GetArtsPath(), "Canvases");
            Run("t:Prefab", new string[] { artsPath });
        }

        [MenuItem("Tools/Find Missing References (Efxs)", false, 201)]
        static private void RunEfxs()
        {
            var artsPath = Path.Combine(Utils.GetArtsPath(), "Effects");
            Run("t:Prefab", new string[] { artsPath });
        }

        [MenuItem("Tools/Find Missing References (Scene)", false, 202)]
        static private void RunScenes()
        {
            var artsPath = Path.Combine(Utils.GetArtsPath(), "Scenes");
            Run("t:Scene", new string[] { artsPath });
        }

        static void Run(string pattern, string[] paths)
        {
            var iterator = Match(pattern, paths).GetEnumerator();
            EditorApplication.update = delegate ()
            {
                if (!iterator.MoveNext())
                {
                    EditorUtility.ClearProgressBar();
                    EditorApplication.update = null;
                }
            };
        }

        private static IEnumerable Match(string pattern, string[] paths)
        {
            var files = AssetDatabase.FindAssets(pattern, paths)
                .Select(item => AssetDatabase.GUIDToAssetPath(item))
                .ToArray();

            for (var i = 0; i < files.Length; i++)
            {
                var file = files[i];
                var ctx = AssetDatabase.LoadAssetAtPath<Object>(file);

                var sceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(file);
                if (sceneAsset != null)
                {
                    var scene = EditorSceneManager.OpenScene(file, OpenSceneMode.Additive);
                    foreach (var go in scene.GetRootGameObjects())
                        CheckGameObjectReferences(go, ctx, file);
                    EditorSceneManager.CloseScene(scene, true);
                }
                else if(AssetDatabase.LoadAssetAtPath<GameObject>(file) != null)
                {
                    var loadPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(file);
                    var instanceGo = PrefabUtility.InstantiatePrefab(loadPrefab) as GameObject;
                    CheckGameObjectReferences(instanceGo,ctx,file);
                }
                else
                {
                    foreach (var obj in AssetDatabase.LoadAllAssetsAtPath(file))
                    {
                        var fullname = file;
                        if (obj is GameObject)
                            fullname = Utils.GetPathInHierachy((obj as GameObject).transform);
                        else if (obj is Component)
                            fullname = Utils.GetPathInHierachy((obj as Component).transform);

                        if (obj != null)
                        {
                            CheckReferences(obj, ctx, fullname);
                        }
                    }
                }

                if (EditorUtility.DisplayCancelableProgressBar("Searching...", file, (float)i / (float)files.Length))
                    yield break;

                yield return null;
            }
        }

        static void CheckReferences(Object obj, Object ctx, string fullname)
        {
            //change
            SerializedObject so = new SerializedObject(obj);
            var iter = so.GetIterator();
            //Next
            while (iter.Next(true))
            {
                if (iter.propertyType == SerializedPropertyType.ObjectReference)
                {
                    if (iter.objectReferenceValue == null && iter.objectReferenceInstanceIDValue != 0)
                        Debug.LogWarning(string.Format("{0}: Found missing references {1}", fullname, iter.name), ctx);

                    //iter.
                }
            }
        }

        static void CheckGameObjectReferences(GameObject go, Object ctx, string fullname)
        {
            fullname = Path.Combine(fullname, go.name);
            CheckReferences(go, ctx, fullname);

            foreach (var component in go.GetComponents<Component>())
            {
                if (component != null)
                    CheckReferences(component, ctx, fullname);
                else
                    Debug.LogWarning(string.Format("{0}: Found missing references {1}", fullname, go), ctx);
            }

            foreach (Transform child in go.transform)
                CheckGameObjectReferences(child.gameObject, ctx, fullname);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值