Unity Editor traverses all prefabs in the specified folder

Applicable scene:

                 Search all prefabs in the specified folder and find all referenced images and paths.

Step analysis:

                1. Obtain the resource path through guid

                ​ ​ ​ ​ 2. Get the path containing the suffix .prefab in the folder

                Load the resource (if you edit the resource, you need to add Start resource editing AssetDatabase.StartAssetEditing() before loading the resource and add End resource editing AssetDatabase.StopAssetEditing() after the operation is completed)

                ​ ​ ​ ​ 4. Traverse the prefab to find the object with the Image component on it, and obtain the path and image size information of iamge.sprite

                5. Write this information locally to facilitate resource packaging and management

Implementation code:

[MenuItem("UnityTools/GetComponentTools/获取预制件图片路径及大小")]
    public static void GetTexturePathOfSize()
    {
        //通过guid获取资源路径
        string guid = Selection.assetGUIDs[0];
        var selectPath = AssetDatabase.GUIDToAssetPath(guid);
        List<string> dirs = new List<string>();
        GetPrefabsDirs(selectPath, ref dirs);
    }

    private static void GetPrefabsDirs(string dirPath, ref List<string> dirs)
    {
        //开始资源编辑
        AssetDatabase.StartAssetEditing();
        
        foreach (string path in Directory.GetFiles(dirPath))
        {
            //获取所有文件夹中包含后缀为 .prefab 的路径
            if (System.IO.Path.GetExtension(path) == ".prefab" && path.IndexOf(@"UI\Slots") == -1)
            {
                dirs.Add(path.Substring(path.IndexOf("Asset")));
                string final_path = path.Substring(path.IndexOf("Asset")).Replace(@"\", "/");
                GameObject prefab = AssetDatabase.LoadAssetAtPath(final_path, typeof(System.Object)) as GameObject;
                
                foreach(Transform child in prefab.GetComponentsInChildren<Transform>(true))
                {
                    if (child.GetComponent<Image>() && child.GetComponent<Image>().sprite != null)
                    {
                        var sp = child.GetComponent<Image>().sprite;
                        
                        var assetPath = AssetDatabase.GetAssetPath(sp);
                        
                        WriteMcImagePath($"预制件路径:{GetChildPaht(child)}, 图片路径:{assetPath}, 图片大小:{GetTxtureSize(assetPath)}Mb");
                    }
                }
            }
        }         
        if (Directory.GetDirectories(dirPath).Length > 0)  //遍历所有文件夹
        {
            foreach (string path in Directory.GetDirectories(dirPath))
            {
                GetDirsImageSprite(path, ref dirs);
            }
        }
        //结束资源编辑
        AssetDatabase.StopAssetEditing();
    }

    /// <summary>
    /// 获取文件大小
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static double GetTxtureSize(string path)
    {
        FileInfo fileInfo = new FileInfo(path);
        double length = Convert.ToDouble(fileInfo.Length);
        double Size = length / 2048;
        return Size;
    }

    /// <summary>
    /// 获取当前子物体在父物体中的路径
    /// </summary>
    /// <param name="_target"></param>
    /// <returns></returns>
    public static string GetChildPaht(Transform _target)
    {
        List<Transform> listPath = new List<Transform>();
        listPath.Add(_target);
        bool isCheck = false;
        string path = "";
        while (!isCheck)
        {
            if (listPath[0].parent != null)
            {
                Transform currentTarget = listPath[0].parent;
                listPath.Insert(0,currentTarget);
            }
            else
            {
                isCheck = true;
            }
        }

        for (int i = 0; i < listPath.Count; i++)
        {
            path += listPath[i].name + (i ==  listPath.Count - 1 ? "" : "/");
        }
        return path;
    }

    /// <summary>
    /// 将信息写入到桌面指定文件
    /// </summary>
    /// <param name="_str"></param>
    /// <returns></returns>
    private static void WriteMcImagePath(string _str)
    {
        var path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "/McImagePath.txt";
        FileStream fs = null;
        StreamWriter sw = null;
        //创建文本
        if (!File.Exists(path))
        {
            fs = new FileStream(path,FileMode.Create,FileAccess.ReadWrite);
            sw = new StreamWriter(fs);
        }
        else
        {
            fs = new FileStream(path, FileMode.Append, FileAccess.Write);
            sw = new StreamWriter(fs);
        }

        sw.WriteLine(_str);
        
        sw.Flush();
        sw.Close();
        fs.Close();
    }

Additional notes:               

        When editing resources, you need to note that UGUI inherits Graphic. If the UI that inherits Graphic is referenced by other UIs without using the editor, the reference will be lost, so we need to add one step when editing (remember the UI Quote, restore after editing is complete)

        

    private class ComponentSetImageInfo
    {
        public FieldInfo Fileld;
        public PropertyInfo Property;
        public Object Obj;
        public Image RefImage;
    }

    private static void createPrefabRefImageInof(GameObject go,List<ComponentSetImageInfo> infos){
        foreach (var component in go.transform.GetComponentsInChildren<Component>(true))
        {   
            var filelds = component.GetType()
                .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            filelds = filelds.Where((o) => o.FieldType == typeof(Image) ||(o.FieldType == typeof(Graphic) && o.GetValue(component) is Image)).ToArray();
            foreach (var fileld in filelds)
            {
                var image = fileld.GetValue(component) as Image;
                if (image != null)
                {
                    infos.Add(new ComponentSetImageInfo()
                        {Fileld = fileld, Obj = component, RefImage = image});
                }
                //Debug.LogError(fileld.Name + fileld.FieldType.FullName);
                //fileld.SetValue(component,);
            }
            
            var propertys = component.GetType()
                .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            propertys = propertys.Where((o) => (o.PropertyType == typeof(Image)) || (o.PropertyType == typeof(Graphic) && o.GetValue(component) is Image)).ToArray();
            foreach (var property in propertys)
            {
                var image = property.GetValue(component) as Image;
                if (image != null)
                {
                    infos.Add(new ComponentSetImageInfo()
                        {Property = property, Obj = component, RefImage = image});
                }
            }
        }
    }

Specific usage:

        

[MenuItem("UnityTools/GetComponentTools/替换Image为McImage")]
    static void CheckImageFolder()
    {
        string guid = Selection.assetGUIDs[0];
        var selectPath = AssetDatabase.GUIDToAssetPath(guid);
        List<string> dirs = new List<string>();
        GetDirsImage(selectPath, ref dirs);
    }
    
    //参数1 为要查找的总路径, 参数2 保存路径
    private static void GetDirsImage(string dirPath, ref List<string> dirs)
    {
        List<ComponentSetImageInfo> infos = new List<ComponentSetImageInfo>();
        foreach (string path in Directory.GetFiles(dirPath))
        {
            // Debug.Log(path);
            //获取所有文件夹中包含后缀为 .prefab 的路径
            if (System.IO.Path.GetExtension(path) == ".prefab" && path.IndexOf(@"UI\Slots") == -1)
            {
                dirs.Add(path.Substring(path.IndexOf("Asset")));
                string final_path = path.Substring(path.IndexOf("Asset")).Replace(@"\", "/");
                GameObject prefab = AssetDatabase.LoadAssetAtPath(final_path, typeof(System.Object)) as GameObject;

                var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
                createPrefabRefImageInof(instance,infos);
                foreach(Image child in instance.GetComponentsInChildren<Image>(true))
                {
                    UpdateImageByMcImage(child,infos);
                }
                PrefabUtility.ApplyPrefabInstance(instance, InteractionMode.UserAction);
                GameObject.DestroyImmediate(instance);
            }
        }         
        if (Directory.GetDirectories(dirPath).Length > 0)  //遍历所有文件夹
        {
            foreach (string path in Directory.GetDirectories(dirPath))
            {
                GetDirsImage(path, ref dirs);
            }
        }
    }

    static void UpdateImageByMcImage(Image image, List<ComponentSetImageInfo> refsObjs)
    {
        var targets = image.transform;

        var fillMethod = Image.FillMethod.Radial90;
        var fillOrigin = 1;
        var fillAmount = 0.0f;
        var clockwise = true;
        if (image.type == Image.Type.Filled)
        {
            fillMethod = image.fillMethod;
            fillOrigin = image.fillOrigin;
            fillAmount = image.fillAmount;
            clockwise = image.fillClockwise;
        }
        var enable = image.enabled;
        var spr = image.sprite;
        var color = image.color;
        var mat = image.material;
        var rayTarget = image.raycastTarget;
        var maskable = image.maskable;
        var type = image.type;
        
        //step1 找到所有引用自己的组件
        List<ComponentSetImageInfo> refSelfComponents = refsObjs.Where((o) => o.RefImage == image).ToList();

        DestroyImmediate(image,true);
        
        //Debug.LogError($"组件:{image},组件名:{targets.name}");
        var mcImage = targets.gameObject.AddComponent<MCImage>();
        mcImage.sprite = spr;
        //设置key
        string path = Application.streamingAssetsPath + "/rename.txt";
        string[] txt = File.ReadAllLines(path);
        Dictionary<string, string> keyDics = new Dictionary<string, string>();
        
        for (int i = 0; i < txt.Length; i++)
        {
            keyDics.Add(txt[i].Split(',')[0],txt[i].Split(',')[1]);
        }
        
        var assetPath = AssetDatabase.GetAssetPath(spr);
        
        if (!string.IsNullOrEmpty(assetPath))
        {
            var imageKey = "";
            if (keyDics.ContainsKey(assetPath))
            {
                foreach (var item in keyDics)
                {
                    if (assetPath == item.Key)
                    {
                        imageKey = item.Value;
                    }
                }
            }
            else
            {
                imageKey = spr.name;
            }
            
            //去除key带点的特殊符号
            if(imageKey.Contains('.'))
            {
                imageKey = imageKey.Replace('.','_');
            }
            
            string path1 = Application.streamingAssetsPath + "/rename1.txt";
            
            string[] txt1 = File.ReadAllLines(path1);
            
            Dictionary<string, string> keyDics1 = new Dictionary<string, string>();
        
            for (int i = 0; i < txt1.Length; i++)
            {
                keyDics1.Add(txt1[i].Split(',')[0],txt1[i].Split(',')[1]);
            }
            
            if (keyDics1.ContainsKey(imageKey))
            {
                foreach (var item in keyDics1)
                {
                    if (imageKey == item.Key)
                    {
                        imageKey = item.Value;
                    }
                }
            }
            
            //unity自带图片过滤
            if(!assetPath.Contains("Assets"))
            {
                imageKey = null;
            }

            mcImage.spriteKey = imageKey;
        }

        mcImage.enabled = enable;
        mcImage.color = color;
        mcImage.material = mat;
        mcImage.raycastTarget = rayTarget;
        mcImage.maskable = maskable;
        mcImage.type = type;
        if (mcImage.type == Image.Type.Filled)
        {
            mcImage.fillMethod = fillMethod;
            mcImage.fillOrigin = fillOrigin;
            mcImage.fillAmount = fillAmount;
            mcImage.fillClockwise = clockwise;
        }
        
        foreach (var refObj in refSelfComponents)
        {
            //Debug.LogError($"refobj:{refObj.Obj}");
            if(refObj.Fileld != null)
                refObj.Fileld.SetValue(refObj.Obj,mcImage);
            if (refObj.Property != null)
            {
                try
                {
                    refObj.Property.SetValue(refObj.Obj,mcImage);
                }
                catch (Exception e)
                {
                    
                }
            }
        }
    }

At this point, the unity editor has completed the operation of all prefabs under the specified file. If you don’t understand, please leave a message.

Guess you like

Origin blog.csdn.net/ThreePointsHeat/article/details/133945058