精确的Prefab资源引用查找工具

2026/01 06 16:01

一般的Prefab引用查找工具,只能查找Prefb引用了,但是哪个节点引用了不知道,以下工具可以精确定位是哪个节点使用的

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.Text;
using UnityEditor.SceneManagement;
using UnityEditor.Animations;
public class PrefabRefFindTool: EditorWindow
{
    [MenuItem("Tools/打开Prefab资源查找工具", false, 3502)]
    private static void ShowWindow()
    {
        var window = GetWindow<PrefabRefFindTool>("Prefab资源查找工具");
        window.Show();
    }

    public static bool UseDebugPath = false;

    public class FilterObject
    {
        private List<string> mExcludeFilter = new List<string>();
        private List<string> mIncludeFilter = new List<string>();
        private List<string> mFileTypeFilter = new List<string>();

        public FilterObject(string excludeStr, string includeStr, string[] fileTypeFilter)
        {
            // 过滤掉Unity内置资源
            mExcludeFilter.Add("unity_builtin_extra");
            mExcludeFilter.Add("library/");
            mExcludeFilter.Add("packages/");

            var exclude = excludeStr.ToLower().Split(';');
            foreach (var item in exclude)
            {
                var txt = item.Trim();
                if (txt.Length > 0)
                {
                    mExcludeFilter.Add(txt);
                }
            }

            var include = includeStr.ToLower().Split(';');
            foreach (var item in include)
            {
                var txt = item.Trim();
                if (txt.Length > 0)
                {
                    mIncludeFilter.Add(txt);
                }
            }

            mFileTypeFilter.AddRange(fileTypeFilter);
        }
    
        public bool IsShow(string input0)
        {
            var input = input0.ToLower();
            if (mExcludeFilter.Count > 0)
            {
                foreach (var str in mExcludeFilter)
                {
                    if (input.Contains(str))
                    {
                        return false;
                    }
                }
            }

            if (mFileTypeFilter.Count > 0)
            {
                bool container = false;
                foreach (var str in mFileTypeFilter)
                {
                    if (input.Contains(str))
                    {
                        container = true;
                        break;
                    }
                }
                if (!container)
                {
                    return false;
                }
            }

            if (mIncludeFilter.Count > 0)
            {
                bool container = false;
                foreach (var str in mIncludeFilter)
                {
                    if (input.Contains(str))
                    {
                        container = true;
                        break;
                    }
                }
                if (!container)
                {
                    return false;
                }
            }

            return true;
        }
    }

    public class PrefabRefInfos
    {

        // prefabPath : List<nodePath>
        public Dictionary<string, List<(string path, string etype)>> mPrefabRefInfos = new ();
        public bool mFoldout = false;
        public bool mSelected = false;
        private string mETypes = "";
        public string ETypes => mETypes;

        public void AddRefInfo(string prefabPath, string nodePath, string eType)
        {
            if (!mPrefabRefInfos.TryGetValue(prefabPath, out var nodePaths))
            {
                nodePaths = new List<(string path, string etype)>();
                mPrefabRefInfos.Add(prefabPath, nodePaths);
            }

            bool contain = false;
            foreach(var (path, etype) in nodePaths)
            {
                if (path == nodePath)
                {
                    contain = true;
                    break;
                }
            }

            if (!mETypes.Contains(eType))
            {
                mETypes += $"{eType};";
            }

            if (!contain)
            {
                nodePaths.Add((nodePath, eType));
            }
        }

        public (string, string) Draw( (string p3, string p4) prev)
        {
            var (p1, p2) = (string.Empty, string.Empty);

            EditorGUILayout.BeginVertical("box");

            foreach (var kv in mPrefabRefInfos)
            {
                var prefabPath = kv.Key;
                var nodePaths = kv.Value;

                EditorGUILayout.BeginHorizontal();
                
                EditorGUILayout.LabelField(prefabPath);
                
                if (GUILayout.Button("全选节点", GUILayout.Width(70)))
                {
                    List<string> list = new List<string>();
                    foreach(var (nodePath, eType) in nodePaths)
                    {
                        list.Add(nodePath);
                    }
                    SelectAllNode(prefabPath, list);
                }

                DrawLocationButton(prefabPath);

                EditorGUILayout.EndHorizontal();

                foreach (var (nodePath, eType) in nodePaths)
                {
                    EditorGUILayout.BeginHorizontal();

                    var title = ">";
                    if (prev.p3 == prefabPath && prev.p4 == nodePath)
                    {
                        title = "* >";
                    }

                    if (GUILayout.Button(title, GUILayout.Width(30)))
                    {
                        var ret = SelectNodeByPath(prefabPath, nodePath);
                        if (ret != 0)
                        {
                            Log.EditorInfo($"选中{nodePath}节点失败,错误码:{ret}");
                        }
                        else
                        {
                            p1 = prefabPath;
                            p2 = nodePath;
                        }
                    }

                    EditorGUILayout.LabelField(nodePath);
                    EditorGUILayout.EndHorizontal();
                }
            
            }

            EditorGUILayout.EndVertical();

            return (p1, p2);
        }
    }

    private static void SelectAllNode(string prefabPath, List<string> nodePaths)
    {
        var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
        if (prefabStage != null)
        {
            if (prefabStage.assetPath != prefabPath)
            {
                PrefabStageUtility.OpenPrefab(prefabPath);
                prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
            }
        }
        else
        {
            PrefabStageUtility.OpenPrefab(prefabPath);
            prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
        }

        var rootNode = prefabStage.prefabContentsRoot;
        if (rootNode == null)
        {
            return;
        }

        List<GameObject> collect = new List<GameObject>();
        for(int i=0; i<nodePaths.Count; ++i)
        {
            var node = FindNodeByPath(rootNode, nodePaths[i]);
            if (node != null)
            {
                collect.Add(node.gameObject);
            }
        }

        if (collect.Count > 0)
        {
            Selection.objects = collect.ToArray();
        }
    }

    private static GameObject FindNodeByPath(GameObject parentNode, string nodePath)
    {
        var nodePaths = nodePath.Split('/');
        if (nodePaths.Length == 0)
        {
            return null;
        }

        if (nodePaths[0] != parentNode.name)
        {
            return null;
        }

        var node = parentNode.transform;
        for(int i=1; i<nodePaths.Length; i++)
        {
            node = node.transform.Find(nodePaths[i]);
            if (node == null)
            {
                break;
            }
        }

        if (node != null)
        {
            return node.gameObject;
        }

        return null;
    }

    private static int SelectNodeByPath(string prefabPath, string nodePath)
    {
        var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
        if (prefabStage != null)
        {
            if (prefabStage.assetPath != prefabPath)
            {
                PrefabStageUtility.OpenPrefab(prefabPath);
                prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
            }
        }
        else
        {
            PrefabStageUtility.OpenPrefab(prefabPath);
            prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
        }

        var nodePaths = nodePath.Split('/');
        if (nodePaths.Length == 0)
        {
            return -3;
        }

        var rootNode = prefabStage.prefabContentsRoot;
        if (rootNode == null)
        {
            return -4;
        }

        if (nodePaths[0] != rootNode.name)
        {
            return -5;
        }

        var node = rootNode.transform;
        for(int i=1; i<nodePaths.Length; i++)
        {
            node = node.transform.Find(nodePaths[i]);
            if (node == null)
            {
                break;
            }
        }
        if (node == null)
        {
            return -6;
        }

        Selection.activeTransform = node;
        return 0;
    }

    private static void DrawLocationButton(string prefabPath)
    {
        if (GUILayout.Button("定位", GUILayout.Width(40)))
        {
            var selectObj = AssetDatabase.LoadAssetAtPath<Object>(prefabPath);
            if (selectObj != null)
            {
                Selection.activeObject = selectObj;
            }
        }
    }

    private Vector2 mMainScrollPos = Vector2.zero;
    private DefaultAsset mTargetDir;
    private Dictionary<string, PrefabRefInfos> mTexturePathDict = new ();
    private string mExcludeStr = "";
    private string mIncludeStr = "";
    private string mFilterStr = "";
    private readonly string[] kShowFilters = new string[]
    {
        "全部",   // 0
        "仅图片", // 1
        "仅FBX",  // 2
        "仅材质", // 3
    };

    private readonly string[][] kShowFilterArray = new string[][]
    {
        new string[] {},
        new string[] {".png", ".jpg", ".tga"},
        new string[] {".fbx"},
        new string[] {".mat"},
    };

    private int mShowType = 0;

    private void SetAllSelectState(bool selected)
    {
        foreach (var kv in mTexturePathDict)
        {
            kv.Value.mSelected = !selected;
        }

        var filter = GetFilterObj();
        List<string> keys = new List<string>(mTexturePathDict.Keys);
        keys.Sort();
        foreach(var key in keys)
        {
            if (filter.IsShow(key))
            {
                mTexturePathDict[key].mSelected = selected;
            }
        }
    }

    private bool mUseUnityDepSys = false;

    private void OnGUI()
    {
        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("预览选中", GUILayout.Width(80)))
        {
            PreviewImages();
        }

        if (GUILayout.Button("全选", GUILayout.Width(70)))
        {
            SetAllSelectState(true);
        }
        if (GUILayout.Button("全不选", GUILayout.Width(70)))
        {
            SetAllSelectState(false);
        }

        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
                
        var newShowType = EditorGUILayout.Popup(mShowType, kShowFilters, GUILayout.Width(80));
        if (newShowType != mShowType)
        {
            mShowType = newShowType;
            
        }

        EditorGUILayout.LabelField("排除", GUILayout.Width(30));
        mExcludeStr = EditorGUILayout.TextField(mExcludeStr, GUILayout.Width(100));

        EditorGUILayout.LabelField("  ", GUILayout.Width(5));

        EditorGUILayout.LabelField("包含", GUILayout.Width(30));
        mIncludeStr = EditorGUILayout.TextField(mIncludeStr, GUILayout.Width(100));



        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("移动纹理到", GUILayout.Width(80));
        mTargetDir = (DefaultAsset)EditorGUILayout.ObjectField("", mTargetDir, typeof(DefaultAsset), false, GUILayout.Width(160));
        if (mTargetDir != null && GUILayout.Button("移动", GUILayout.Width(80)))
        {
            MoveSelectImages();
        }

        EditorGUILayout.LabelField("  ", GUILayout.Width(5));
        mUseUnityDepSys = EditorGUILayout.Toggle(mUseUnityDepSys, GUILayout.Width(20));
        EditorGUILayout.LabelField("使用Unity依赖", GUILayout.Width(80));

        UseDebugPath = EditorGUILayout.Toggle(UseDebugPath, GUILayout.Width(20));
        EditorGUILayout.LabelField("引用过滤", GUILayout.Width(50));
        if (UseDebugPath)
        {
            mFilterStr = EditorGUILayout.TextField(mFilterStr, GUILayout.Width(80));
        }

        EditorGUILayout.EndHorizontal();

        
        EditorGUILayout.BeginVertical();
        mMainScrollPos = EditorGUILayout.BeginScrollView(mMainScrollPos);

        List<string> keys = new List<string>(mTexturePathDict.Keys);
        keys.Sort();

        var filter = GetFilterObj();
        foreach(var key in keys)
        {
            if (!filter.IsShow(key))
            {
                continue;
            }
 
            var currTexInfo = mTexturePathDict[key];
            if (UseDebugPath && mFilterStr.Length > 0)
            {
                if (!currTexInfo.ETypes.Contains(mFilterStr))
                {
                    continue;
                }
            }
           
            EditorGUILayout.BeginHorizontal();
            currTexInfo.mSelected = EditorGUILayout.Toggle(currTexInfo.mSelected, GUILayout.Width(20));
            currTexInfo.mFoldout = EditorGUILayout.Foldout(currTexInfo.mFoldout, key);
            DrawLocationButton(key);
            EditorGUILayout.EndHorizontal();

            if (currTexInfo.mFoldout)
            {
                (var p0, var p1) = currTexInfo.Draw(mLastSelectInfo);
                if(p0.Length > 0 && p1.Length > 0)
                {
                    mLastSelectInfo = (p0, p1);
                }
            }
            else
            {
                if (UseDebugPath)
                {
                    EditorGUILayout.LabelField(currTexInfo.ETypes);
                }
            }
        }

        EditorGUILayout.EndScrollView();
        EditorGUILayout.EndVertical();

        if (keys.Count == 0)
        {
            EditorGUILayout.HelpBox("排除和包含,以;(分号)分隔", MessageType.Info);
        }
    }

    private (string lastP0, string lastP1) mLastSelectInfo = (string.Empty, string.Empty);

    private FilterObject GetFilterObj()
    {
        var filterArray = kShowFilterArray[mShowType];
        return new FilterObject(mExcludeStr, mIncludeStr, filterArray);
    }

    private void MoveSelectImages()
    {
        var targetDirPath = AssetDatabase.GetAssetPath(mTargetDir);
        if (!targetDirPath.StartsWith("Assets/"))
        {
            Log.EditorError("目标目录必须在Assets目录下");
            return;
        }
    
        StringBuilder sb = new StringBuilder();
        foreach (var kv in mTexturePathDict)
        {
            if (!kv.Value.mSelected)
            {
                continue;
            }

            var ret = MoveImageAsset(kv.Key, targetDirPath);
            sb.AppendLine(ret);
        }

        Log.EditorInfo(sb.ToString());
    }

    private string MoveImageAsset(string srcImagePath, string targetDirPath)
    {
        if (!System.IO.File.Exists(srcImagePath))
        {
            return $"{srcImagePath}文件不存在";
        }

        var fileName = System.IO.Path.GetFileName(srcImagePath);
        var destImagePath = System.IO.Path.Combine(targetDirPath, fileName);
        if (System.IO.File.Exists(destImagePath))
        {
            return $"{destImagePath}文件已存在";
        }

        if (srcImagePath == destImagePath)
        {
            return $"{srcImagePath}和{destImagePath}相同";
        }

        AssetDatabase.MoveAsset(srcImagePath, destImagePath);
        return $"移动成功: {srcImagePath} -> {destImagePath}";
    }


    private void PreviewImages()
    {
        mTexturePathDict.Clear();

        StringBuilder sb = new StringBuilder();

        var (type, dir) = EditorHelper.GetCurrSelectAssetPath();
        if ( type == "dir")
        {
            var files = System.IO.Directory.GetFiles(dir, "*.prefab", System.IO.SearchOption.AllDirectories);
            foreach (var assetPath in files)
            {
                sb.Append(assetPath.Replace("\\", "/"));
                sb.Append(";");
            }
        }
        else
        {
            var selectedObjs = Selection.objects;
            if (selectedObjs.Length == 0)
            {
                Log.EditorError($"请在Project中, 选择要预览的Prefab,可以多选");
                return;
            }
            foreach (var obj in selectedObjs)
            {
                var assetPath = AssetDatabase.GetAssetPath(obj);
                if (!string.IsNullOrEmpty(assetPath))
                {
                    sb.Append(assetPath);
                    sb.Append(";");
                }
            }
        }

        var str = sb.ToString();
        PreviewImages(str);
    }

    private void PreviewImages(string prefabAssetPaths)
    {
        CollectAndPreviewImages(mTexturePathDict, prefabAssetPaths, mUseUnityDepSys);
    }

    private static void CollectMatTextures(Material material, List<string> texturePaths)
    {
        var shader = material.shader;
        if (shader == null)
        {
            return;
        }

        var propCount = shader.GetPropertyCount();
        for (int i = 0; i < propCount; i++)
        {
            if (shader.GetPropertyType(i) != UnityEngine.Rendering.ShaderPropertyType.Texture)
            {
                continue;
            }

            var propName = shader.GetPropertyName(i);
            if (string.IsNullOrEmpty(propName))
            {
                continue;
            }

            var texture = material.GetTexture(propName);
            if (texture == null)
            {
                continue;
            }
        
            var texPath = AssetDatabase.GetAssetPath(texture);
            if (string.IsNullOrEmpty(texPath))
            {
                continue;
            }

            if (texturePaths.Contains(texPath))
            {
                continue;
            }

            texturePaths.Add(texPath);
        }
    }
    public delegate void CollectFunc(string prefabAssetPath, Dictionary<string, PrefabRefInfos> pool);

    // 收集所有的引用
    private static void CollectSelectPrefabAssets(string prefabAssetPath, Dictionary<string, PrefabRefInfos> pool)
    {
        var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabAssetPath);
        if (prefab == null)
        {
            return;
        }

        // 追加引用
        void AppendAssetRef(GameObject node, string newAssetPath, string reason)
        {
            if (node == null || string.IsNullOrEmpty(newAssetPath))
            {
                return;
            }

            if (!pool.TryGetValue(newAssetPath, out var info))
            {
                info = new PrefabRefInfos();
                pool.Add(newAssetPath, info);
            }
            var fullPathName = node.GetFullPathName();
            info.AddRefInfo(prefabAssetPath, fullPathName, reason);
        }

        // 收集GameObject引用的贴图
        void AppendObjRef(GameObject node, UnityEngine.Object refObj, string reason)
        {
            if (refObj == null)
            {
                return;
            }

            AppendAssetRef(node, AssetDatabase.GetAssetPath(refObj), reason);

            if (refObj is Material)
            {
                // 如果是材质,还需要收集材质中引用的贴图
                var materialObj = refObj as Material;
                List<string> texturePaths = new List<string>();
                CollectMatTextures(materialObj, texturePaths);
                foreach (var texturePath in texturePaths)
                {
                    AppendAssetRef(node, texturePath, reason);
                }
            }
        }

        // 收集Image
        var images = prefab.GetComponentsInChildren<UnityEngine.UI.Image>(true);
        foreach (var image in images)
        {
            if (image.mainTexture != null)
            {
                AppendObjRef(image.gameObject, image.mainTexture, "MainTex-Image");
            }

            if (image.material != null)
            {
                AppendObjRef(image.gameObject, image.material, "Material-Image");
                AppendObjRef(image.gameObject, image.material.mainTexture, "MainTex-ImageMaterial");
            }
        }

        // 收集RawImage
        var rawImages = prefab.GetComponentsInChildren<UnityEngine.UI.RawImage>(true);
        foreach (var rawImage in rawImages)
        {
            if (rawImage.mainTexture != null)
            {
                AppendObjRef(rawImage.gameObject, rawImage.mainTexture, "MainTex-RawImage");
            }

            if (rawImage.material != null)
            {
                AppendObjRef(rawImage.gameObject, rawImage.material, "Material-RawImage");
                AppendObjRef(rawImage.gameObject, rawImage.material.mainTexture, "Material-MainTex");
            }
        }

        // 收集SpriteRenderer
        var spriteRenderers = prefab.GetComponentsInChildren<SpriteRenderer>(true);
        foreach (var spriteRenderer in spriteRenderers)
        {
            if (spriteRenderer.sprite && spriteRenderer.sprite.texture)
            {
                AppendObjRef(spriteRenderer.gameObject, spriteRenderer.sprite.texture, "MainTex-SpriteRenderer");
            }
        }

        // 收集渲染器
        var renderers = prefab.GetComponentsInChildren<Renderer>(true);
        foreach (var renderer in renderers)
        {
            if (renderer.sharedMaterial != null)
            {
                AppendObjRef(renderer.gameObject, renderer.sharedMaterial, "Material-Renderer");
                AppendObjRef(renderer.gameObject, renderer.sharedMaterial.mainTexture, "Material-MainTex");
            }
        }

        // 收集MeshCollider中的FBX中
        var meshColliders = prefab.GetComponentsInChildren<MeshCollider>(true);
        foreach (var meshCollider in meshColliders)
        {
            if (meshCollider.sharedMesh != null)
            {
                AppendObjRef(meshCollider.gameObject, meshCollider.sharedMesh, "Mesh-MeshCollider");
            }
        }

        // 收集Animation中的Clip
        var animations = prefab.GetComponentsInChildren<Animation>(true);
        foreach (var animation in animations)
        {
            if (animation.clip != null)
            {
                AppendObjRef(animation.gameObject, animation.clip, "AnimationClip");
            }
        }

        // 收集粒子系统中的Mesh
        void AppendSharpAsset(ParticleSystem particleSystem)
        {
            
            if (particleSystem.shape.mesh == null)
            {
                return;
            }

            AppendObjRef(particleSystem.gameObject, particleSystem.shape.mesh, "Mesh-Particle");

            var fbxPath = AssetDatabase.GetAssetPath(particleSystem.shape.mesh);
            if (string.IsNullOrEmpty(fbxPath))
            {
                return;
            }
            
            var fbxDepends = AssetDatabase.GetDependencies(fbxPath, true);
            foreach (var dependAsset in fbxDepends)
            {
                var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(dependAsset);
                Log.EditorInfo(dependAsset);
                AppendObjRef(particleSystem.gameObject, obj, "ParticleDepends");
            }
        }

        // 收集粒子系统
        var particleSystems = prefab.GetComponentsInChildren<ParticleSystem>(true);
        foreach (var particleSystem in particleSystems)
        {
            var psr = particleSystem.GetComponent<ParticleSystemRenderer>();
            if (psr != null)
            {
                if (psr.sharedMaterial != null)
                {
                    AppendObjRef(particleSystem.gameObject, psr.sharedMaterial, "Material-Particle");
                    try
                    {
                        AppendObjRef(particleSystem.gameObject, psr.sharedMaterial.mainTexture, "MainTex-Particle");
                    }
                    catch
                    {
                    }
                }
    
                if (psr.trailMaterial != null)
                {
                    AppendObjRef(particleSystem.gameObject, psr.trailMaterial, "Material-Trail");
                    try
                    {
                        AppendObjRef(particleSystem.gameObject, psr.trailMaterial.mainTexture, "MainTex-Trail");
                    }
                    catch
                    {
                    }
                }

                // 收集ParticleSystemRenderMode中的Meshs
                if (psr.renderMode == ParticleSystemRenderMode.Mesh)
                {
                    Mesh[] meshes = new Mesh[psr.meshCount];
                    psr.GetMeshes(meshes);
                    for(int i=0; i<meshes.Length; ++i)
                    {
                        AppendObjRef(particleSystem.gameObject, meshes[i], "Mesh-Particle");
                    }                    
                }
            }

            AppendObjRef(particleSystem.gameObject, particleSystem.shape.texture, "MainTex-Particle");
            AppendSharpAsset(particleSystem);
        }

        // 收集Mesh
        var meshs = prefab.GetComponentsInChildren<MeshFilter>(true);
        foreach (var meshFilter in meshs)
        {
            AppendObjRef(meshFilter.gameObject, meshFilter.sharedMesh, "Mesh-MeshFilter");
        }

        // 收集VFXImage
        var vfxImages = prefab.GetComponentsInChildren<VFXImage>(true);
        foreach (var vfxImage in vfxImages)
        {
            AppendObjRef(vfxImage.gameObject, vfxImage.CustomMesh, "Mesh-VFXImage");
        }

        // 收集动画
        var animators = prefab.GetComponentsInChildren<Animator>(true);
        foreach (var animator in animators)
        {
            if (animator.runtimeAnimatorController == null)
            {
                continue;
            }

            var ac = animator.runtimeAnimatorController as AnimatorController;
            if (ac == null)
            {
                continue;
            }

            foreach (var layer in ac.layers)
            {
                foreach (var state in layer.stateMachine.states)
                {
                    if (state.state.motion == null)
                    {
                        continue;
                    }

                    // Anim动画
                    AppendObjRef(animator.gameObject, state.state.motion, "AnimMotion");
                }
            }
            
            // 控制器文件
            AppendObjRef(animator.gameObject, ac, "AnimLayerMotion");
        }
    }

    private readonly static List<string> unityDepExcludeExts = new List<string>() { ".cs", ".dll", ".shader" };

    private static void CollectSelectPrefabAllDepends(string prefabAssetPath, Dictionary<string, PrefabRefInfos> pool)
    {
        var depends = AssetDatabase.GetDependencies(prefabAssetPath);
        foreach (var dependAsset in depends)
        {
            if (prefabAssetPath == dependAsset)
            {
                continue;
            }
            
            var ext = System.IO.Path.GetExtension(dependAsset).ToLower();
            if (unityDepExcludeExts.Contains(ext))
            {
                continue;
            }
            
            if (!pool.TryGetValue(dependAsset, out var info))
            {
                info = new PrefabRefInfos();
                pool.Add(dependAsset, info);
            }

            info.AddRefInfo(prefabAssetPath, dependAsset, "Unity");
        }
    }

    public static void CollectAndPreviewImages(Dictionary<string, PrefabRefInfos> result, string prefabAssetPaths, bool useUnityDepends)
    {
        if (prefabAssetPaths.Length == 0)
        {
            return;
        }

        CollectFunc collectFunc = useUnityDepends ? CollectSelectPrefabAllDepends : CollectSelectPrefabAssets;

        result.Clear();
        var prefabAssetPathsList = prefabAssetPaths.Split(';');
        foreach (var prefabAssetPath in prefabAssetPathsList)
        {
            collectFunc(prefabAssetPath, result);
        }
    }
}