前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Unity-工具-查找丢失资源的Objects

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

作者头像
祝你万事顺利
发布2019-07-15 14:36:51
1.5K0
发布2019-07-15 14:36:51
举报
文章被收录于专栏:Unity游戏开发Unity游戏开发
  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

代码语言:javascript
复制
/// <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;
        }
    }
}
代码语言:javascript
复制
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方法,拿到全部资产,将全部资产遍历,使用序列化的方式遍历每个资产。

代码语言:javascript
复制
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);
        }
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.07.13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • AssetDatabase-FindAssets
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档