少年修仙传客户端基础资源
client_Wu Xijin
2019-04-16 afd53f6b3c0583e74c783c7c0653aa7d0588b1b9
Assets/Editor/Tool/SpriteManageTool.cs
@@ -1,1515 +1,1516 @@
using Snxxz.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using TableConfig;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
public class SpriteManageTool : EditorWindow
{
    enum SpriteManageType
    {
        RepeatSprite,
        UnUseResource,
        Reference,
        PrefabEnglishLabel,
        FormatPrefab,
        ButtonArea,
        ExtractChsLabel,
        ImageMiss,
        UIStyle,
    }
    private Vector2 m_ScrollPosition;
    private Texture2D m_DeleteTexture;
    private List<IconConfig> m_IconCfgs;
    [SerializeField]
    SpriteManageType m_SpriteManageType;
    private static readonly Regex Directory_Regex = new Regex(@"/([0-9a-zA-Z_]+)$");
    private static readonly Regex Name_Regex = new Regex(@"\\([0-9a-zA-Z_\.]+)");
    private static bool m_FindReference = false;
    #region 风格
    private GUIStyle m_ButtonStyle;
    private void InitStyle()
    {
        m_ButtonStyle = new GUIStyle();
    }
    #endregion
    [MenuItem("策划工具/图片资源")]
    public static void OpenWindow()
    {
        m_FindReference = false;
        SpriteManageTool _window = GetWindow(typeof(SpriteManageTool), false, "图片资源") as SpriteManageTool;
        _window.Show();
        _window.autoRepaintOnSceneChange = true;
    }
    [MenuItem("Assets/查找引用")]
    private static void FindReference()
    {
        m_FindReference = true;
        SpriteManageTool _window = GetWindow(typeof(SpriteManageTool), false, "图片资源") as SpriteManageTool;
        _window.Show();
        _window.autoRepaintOnSceneChange = true;
    }
    [MenuItem("Assets/查找引用", true)]
    private static bool FindReferenceValid()
    {
        string _path = AssetDatabase.GetAssetPath(Selection.activeObject);
        return (!string.IsNullOrEmpty(_path));
    }
    private void OnGUI()
    {
        GUI.skin.button.normal.textColor = Color.white;
        DisplayFuncToggle();
        UnityEngine.Object[] _objectArray = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets);
        var _selectPath = (_objectArray == null || _objectArray.Length == 0) ? string.Empty : Application.dataPath.Substring(0, Application.dataPath.LastIndexOf('/')) + "/" + AssetDatabase.GetAssetPath(_objectArray[0]);
        if (!ToolsHelper.lockFolderPath)
        {
            ToolsHelper.folderPath = _selectPath;
        }
        if (!m_LockPrefabPath)
        {
            m_ReplacePrefabPath = _selectPath;
        }
        GUI.skin.button.normal.textColor = m_ButtonTxtColor;
        switch (m_SpriteManageType)
        {
            case SpriteManageType.RepeatSprite:
                DisplayRepeat();
                break;
            case SpriteManageType.UnUseResource:
                DisplayUnUse();
                break;
            case SpriteManageType.Reference:
                DisplayReference();
                break;
            case SpriteManageType.PrefabEnglishLabel:
                DisplayFindPrefabLabel();
                break;
            case SpriteManageType.FormatPrefab:
                FormatPrefabTool.OnGUI();
                break;
            case SpriteManageType.ButtonArea:
                ButtonAreaTool.OnGUI();
                break;
            case SpriteManageType.ExtractChsLabel:
                DisplayExtractChsLabel();
                break;
            case SpriteManageType.ImageMiss:
                ImageMissTool.OnGUI();
                break;
            case SpriteManageType.UIStyle:
                DisplayUIStyle();
                break;
        }
    }
    private void OnEnable()
    {
        ConfigManager.Instance.SyncLoadConfigs();
        m_IconCfgs = ConfigManager.Instance.GetAllValues<IconConfig>();
        m_DeleteTexture = EditorGUIUtility.FindTexture("TreeEditor.Trash");
        InitStyle();
        m_SpriteManageType = m_FindReference ? SpriteManageType.Reference : SpriteManageType.RepeatSprite;
        if (m_FindReference)
        {
            m_ReferenceSource = Selection.activeObject;
        }
    }
    private void DisplayFuncToggle()
    {
        GUILayout.BeginHorizontal();
        string[] labels = new string[9] { "重复图片资源", "未引用的资源(图片)", "查找引用", "界面英文", "格式化预制体", "按钮监听区域", "提取界面中文","缺失图片组件", "UI风格" };
        m_SpriteManageType = (SpriteManageType)GUILayout.Toolbar((int)m_SpriteManageType, labels, "LargeButton", GUILayout.Width(labels.Length * 130));
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    #region 重复图片资源
    private Dictionary<string, RepeatSprite> m_RepeatSprites = new Dictionary<string, RepeatSprite>();
    private Dictionary<string, string> m_PrefabDict = new Dictionary<string, string>();
    private string m_ReplacePrefabPath = string.Empty;
    private bool m_LockPrefabPath = false;
    private void DisplayRepeat()
    {
        ToolsHelper.DisplayFolderPath();
        DisplayPrefabPath();
        GUILayout.BeginHorizontal();
        if (GUILayout.Button("查找", GUILayout.Width(50), GUILayout.Height(25)))
        {
            StartFindRepeat();
            StartFindPrefabsGuid();
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        foreach (var _key in m_RepeatSprites.Keys)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label(StringUtility.Contact("MD5:", _key));
            if (GUILayout.Button("合并"))
            {
                MergeSprite(m_RepeatSprites[_key]);
            }
            if (GUILayout.Button("合并并删除"))
            {
                MergeSprite(m_RepeatSprites[_key]);
                m_RepeatSprites[_key].DeleteOther();
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            var _repeat = m_RepeatSprites[_key];
            for (int i = 0; i < _repeat.repeats.Count; i++)
            {
                GUILayout.BeginHorizontal();
                EditorGUILayout.ObjectField(_repeat.repeats[i], typeof(Sprite), false);
                if (GUILayout.Toggle(_repeat.select == i, ""))
                {
                    _repeat.select = i;
                }
                if (_repeat.exitInCfgs[i] != -1)
                {
                    var _index = _repeat.exitInCfgs[i];
                    GUILayout.Label(StringUtility.Contact("key:", m_IconCfgs[_index].id, "    folder:",
                        m_IconCfgs[_index].folder));
                }
                if (_repeat.select != i && GUILayout.Button(m_DeleteTexture))
                {
                    _repeat.Delete(i);
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
            }
            GUILayout.Space(10);
        }
        GUILayout.EndScrollView();
    }
    private void StartFindRepeat()
    {
        if (Regex.IsMatch(ToolsHelper.folderPath, @".*\..*"))
        {
            Debug.LogError("该路径不是文件夹路径");
            return;
        }
        var _files = Directory.GetFiles(ToolsHelper.folderPath, "*.png", SearchOption.AllDirectories);
        if (_files == null || _files.Length == 0)
        {
            Debug.LogError("没找到图片");
            return;
        }
        m_RepeatSprites.Clear();
        int _index = 0;
        EditorApplication.update = () =>
        {
            var _md5 = GetFileMD5(_files[_index]);
            if (m_RepeatSprites.ContainsKey(_md5))
            {
                var _sprite = GetSpriteByAssetPath(_files[_index]);
                if (_sprite != null)
                {
                    var _existIndex = m_IconCfgs.FindIndex((x) =>
                    {
                        return x.sprite == _sprite.name;
                    });
                    m_RepeatSprites[_md5].Add(_sprite, _existIndex);
                }
            }
            else
            {
                var _repeat = new RepeatSprite();
                m_RepeatSprites.Add(_md5, _repeat);
                var _sprite = GetSpriteByAssetPath(_files[_index]);
                if (_sprite != null)
                {
                    var _existIndex = m_IconCfgs.FindIndex((x) =>
                    {
                        return x.sprite == _sprite.name;
                    });
                    _repeat.Add(_sprite, _existIndex);
                }
            }
            bool isCancel = EditorUtility.DisplayCancelableProgressBar("查找重复资源", "", (float)_index / (float)_files.Length);
            _index++;
            if (isCancel || _index >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                _index = 0;
                var _keys = m_RepeatSprites.Keys.ToList();
                if (_keys != null)
                {
                    for (int i = 0; i < _keys.Count; i++)
                    {
                        if (m_RepeatSprites[_keys[i]].Count < 2)
                        {
                            m_RepeatSprites.Remove(_keys[i]);
                        }
                    }
                }
                _keys = null;
            }
        };
    }
    private void StartFindPrefabsGuid()
    {
        if (Regex.IsMatch(m_ReplacePrefabPath, @".*\..*"))
        {
            Debug.LogError("该路径不是文件夹路径");
            return;
        }
        m_PrefabDict.Clear();
        string[] _prefabFiles = Directory.GetFiles(m_ReplacePrefabPath, "*.prefab", SearchOption.AllDirectories);
        if (_prefabFiles == null || _prefabFiles.Length == 0)
        {
            return;
        }
        for (int i = 0; i < _prefabFiles.Length; i++)
        {
            m_PrefabDict.Add(_prefabFiles[i], File.ReadAllText(_prefabFiles[i]));
        }
    }
    private void MergeSprite(RepeatSprite _repeat)
    {
        if (m_PrefabDict.Count == 0)
        {
            Debug.LogError("没找到预制体");
            return;
        }
        var _nGuid = GetGUIDByAssets(_repeat.repeats[_repeat.select]);
        for (int i = 0; i < _repeat.repeats.Count; i++)
        {
            if (i == _repeat.select)
            {
                continue;
            }
            var _guid = GetGUIDByAssets(_repeat.repeats[i]);
            var _list = m_PrefabDict.Keys.ToList();
            for (int j = 0; j < _list.Count; j++)
            {
                var _key = _list[j];
                if (Regex.IsMatch(m_PrefabDict[_key], _guid))
                {
                    string _file = Regex.Replace(m_PrefabDict[_key], _guid, _nGuid);
                    File.WriteAllText(_key, _file);
                    m_PrefabDict[_key] = _file;
                    AssetDatabase.SaveAssets();
                }
            }
        }
        AssetDatabase.Refresh();
    }
    private string GetFileMD5(string _filePath)
    {
        var _fileMd5 = string.Empty;
        using (FileStream fs = new FileStream(_filePath, FileMode.Open))
        {
            System.Security.Cryptography.MD5 _md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] _bytes = _md5.ComputeHash(fs);
            for (int i = 0; i < _bytes.Length; i++)
            {
                _fileMd5 += _bytes[i].ToString("x2");
            }
        }
        return _fileMd5;
    }
    public class RepeatSprite
    {
        public List<Sprite> repeats = new List<Sprite>();
        public List<int> exitInCfgs = new List<int>();
        public int select = 0;
        public void Add(Sprite _sprite, int _index)
        {
            repeats.Add(_sprite);
            exitInCfgs.Add(_index);
        }
        public void Delete(int _index)
        {
            var _sprite = repeats[_index];
            if (select > _index)
            {
                select--;
            }
            repeats.RemoveAt(_index);
            exitInCfgs.RemoveAt(_index);
            AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(_sprite));
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        public void DeleteOther()
        {
            while (repeats.Count > 1)
            {
                Delete(select == 0 ? 1 : 0);
            }
        }
        public int Count
        {
            get
            {
                return repeats.Count;
            }
        }
    }
    #endregion
    #region 未引用资源
    private Dictionary<string, List<Sprite>> m_UnUseSpriteDict = new Dictionary<string, List<Sprite>>();
    private List<string> m_UnUseSpritePaths = new List<string>();
    [SerializeField] string m_RemoveSpritePath = string.Empty;
    private void DisplayUnUse()
    {
        ToolsHelper.DisplayFolderPath();
        DisplayPrefabPath();
        GUILayout.BeginHorizontal();
        if (GUILayout.Button("查找", GUILayout.Width(50), GUILayout.Height(25)))
        {
            StartFindPrefabsGuid();
            StartFindUnUse();
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        foreach (var _key in m_UnUseSpriteDict.Keys)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label(StringUtility.Contact("Folder:", _key));
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            var _sprites = m_UnUseSpriteDict[_key];
            for (int i = 0; i < _sprites.Count; i++)
            {
                GUILayout.BeginHorizontal();
                EditorGUILayout.ObjectField(_sprites[i], typeof(Sprite), false);
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
            }
            GUILayout.Space(10);
        }
        GUILayout.EndScrollView();
        GUILayout.BeginHorizontal();
        GUILayout.Label(StringUtility.Contact("移除路径:", m_RemoveSpritePath));
        if (GUILayout.Button("选择移出的文件根路径"))
        {
            var _path = EditorUtility.OpenFolderPanel("根路径", "", "");
            m_RemoveSpritePath = _path;
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        if (GUILayout.Button("开始移除"))
        {
            StartRemoveSprite();
        }
        GUILayout.Space(20);
    }
    private void StartFindUnUse()
    {
        m_UnUseSpriteDict.Clear();
        m_UnUseSpritePaths.Clear();
        if (Regex.IsMatch(ToolsHelper.folderPath, @".*\..*"))
        {
            Debug.LogError("该路径不是文件夹路径");
            return;
        }
        var _files = Directory.GetFiles(ToolsHelper.folderPath, "*.png", SearchOption.AllDirectories);
        if (_files == null || _files.Length == 0)
        {
            Debug.LogError("没找到图片");
            return;
        }
        var _list = m_PrefabDict.Values.ToList();
        int i = 0;
        EditorApplication.update = delegate ()
        {
            var _guid = AssetDatabase.AssetPathToGUID(GetRelativeAssetsPath(_files[i]));
            FileInfo _fileInfo = new FileInfo(_files[i]);
            bool isCancel = EditorUtility.DisplayCancelableProgressBar("查找未引用资源",
                StringUtility.Contact(i, "/", _files.Length), (float)i / _files.Length);
            var _spriteName = Regex.Replace(_fileInfo.Name, @"\.png", string.Empty, RegexOptions.IgnoreCase);
            var _index = m_IconCfgs.FindIndex((x) =>
            {
                return x.sprite == _spriteName && x.folder == _fileInfo.Directory.Name;
            });
            if (_index == -1)
            {
                bool _unUse = true;
                for (int k = 0; k < _list.Count; k++)
                {
                    if (Regex.IsMatch(_list[k], _guid))
                    {
                        _unUse = false;
                        break;
                    }
                }
                if (_unUse)
                {
                    var _sprite = GetSpriteByAssetPath(_files[i]);
                    List<Sprite> _sprites = null;
                    if (!m_UnUseSpriteDict.TryGetValue(_fileInfo.Directory.Name, out _sprites))
                    {
                        _sprites = new List<Sprite>();
                        m_UnUseSpriteDict.Add(_fileInfo.Directory.Name, _sprites);
                    }
                    _sprites.Add(_sprite);
                    m_UnUseSpritePaths.Add(_files[i]);
                }
            }
            i++;
            if (isCancel || i >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                i = 0;
            }
        };
    }
    private void StartRemoveSprite()
    {
        if (m_UnUseSpriteDict.Count == 0)
        {
            return;
        }
        if (!Directory_Regex.IsMatch(m_RemoveSpritePath))
        {
            return;
        }
        var _directory = Directory_Regex.Match(m_RemoveSpritePath).Groups[1].Value;
        var _path = StringUtility.Contact(m_RemoveSpritePath, "/", _directory);
        if (!Directory.Exists(_path))
        {
            Directory.CreateDirectory(_path);
        }
        StartRecordRemoveSprite(_path);
        for (int i = 0; i < m_UnUseSpritePaths.Count; i++)
        {
            var _extention = Name_Regex.Match(m_UnUseSpritePaths[i]).Groups[1].Value;
            File.Move(m_UnUseSpritePaths[i], StringUtility.Contact(_path, @"\", _extention));
        }
        m_UnUseSpriteDict.Clear();
        m_UnUseSpritePaths.Clear();
        AssetDatabase.Refresh();
    }
    private void StartRecordRemoveSprite(string _path)
    {
        using (FileStream fs = new FileStream(StringUtility.Contact(_path, "/logger.txt"), FileMode.Create, FileAccess.Write))
        {
            using (StreamWriter sw = new StreamWriter(fs))
            {
                for (int i = 0; i < m_UnUseSpritePaths.Count; i++)
                {
                    sw.WriteLine(m_UnUseSpritePaths[i]);
                }
            }
        }
    }
    #endregion
    #region 引用资源
    private UnityEngine.Object m_ReferenceSource;
    private UnityEngine.Object m_ReferenceReplace;
    private static string[] m_ReferenceDisplays = new string[] { "Material", "Prefab", "Asset", "Scene" };
    private Dictionary<UnityEngine.Object, string> m_ReferenceObjectDict = new Dictionary<UnityEngine.Object, string>();
    private Dictionary<UnityEngine.Object, bool> m_ReferenceReplaceDict = new Dictionary<UnityEngine.Object, bool>();
    private Dictionary<UnityEngine.Object, List<RefDetail>> m_ReferenceDetailDict = new Dictionary<UnityEngine.Object, List<RefDetail>>();
    private List<RefDetail> m_PrefabDetails = new List<RefDetail>();
    private string m_ReferenceGUID = string.Empty;
    [SerializeField] bool m_GlobalSearch = false;
    [SerializeField] int m_ReferenceType = 1 << (int)ReferenceType.Prefab;
    public enum ReferenceType
    {
        Material,
        Prefab,
        Asset,
        Scene,
    }
    private void DisplayReference()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("被引用的资源");
        m_ReferenceSource = EditorGUILayout.ObjectField(m_ReferenceSource, typeof(UnityEngine.Object), false);
        m_GlobalSearch = GUILayout.Toggle(m_GlobalSearch, "全局搜索");
        if (m_ReferenceSource != null && GUILayout.Button("显示GUID"))
        {
            m_ReferenceGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferenceSource));
        }
        if (m_ReferenceSource != null && m_ReferenceSource is GameObject && GUILayout.Button("分析Prefab"))
        {
            m_PrefabDetails.Clear();
            GetReferenceDetail(File.ReadAllText(AssetDatabase.GetAssetPath(m_ReferenceSource)), string.Empty, m_PrefabDetails);
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        GUILayout.Label("GUID:");
        EditorGUILayout.TextField(m_ReferenceGUID);
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        if (m_ReferenceSource != null && m_ReferenceSource is GameObject)
        {
            DisplayPrefabDetail();
            return;
        }
        if (!m_GlobalSearch)
        {
            ToolsHelper.DisplayFolderPath();
        }
        GUILayout.BeginHorizontal();
        GUILayout.Label("引用资源的类型");
        m_ReferenceType = EditorGUILayout.MaskField((int)m_ReferenceType, m_ReferenceDisplays);
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        if (m_ReferenceSource != null && m_ReferenceSource is Texture2D)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("替换资源");
            m_ReferenceReplace = EditorGUILayout.ObjectField(m_ReferenceReplace, typeof(UnityEngine.Object), false);
            if (!(m_ReferenceReplace is Texture2D))
            {
                m_ReferenceReplace = null;
            }
            if (m_ReferenceObjectDict.Count > 0 && m_ReferenceReplace != null)
            {
                if (GUILayout.Button("一键替换"))
                {
                    var _replaceGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferenceReplace));
                    m_ReferenceGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferenceSource));
                    foreach (var _object in m_ReferenceReplaceDict.Keys)
                    {
                        if (m_ReferenceReplaceDict[_object] && m_ReferenceObjectDict.ContainsKey(_object))
                        {
                            var _allText = m_ReferenceObjectDict[_object];
                            var _path = AssetDatabase.GetAssetPath(_object);
                            if (Regex.IsMatch(_allText, m_ReferenceGUID))
                            {
                                string _file = Regex.Replace(_allText, m_ReferenceGUID, _replaceGuid);
                                File.WriteAllText(_path, _file);
                                AssetDatabase.SaveAssets();
                                AssetDatabase.Refresh();
                            }
                            m_ReferenceObjectDict.Remove(_object);
                        }
                    }
                }
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
        }
        if (GUILayout.Button("查找"))
        {
            if (m_ReferenceSource == null)
            {
                Debug.LogError("未指定所引用的资源");
                return;
            }
            if (!m_GlobalSearch && Regex.IsMatch(ToolsHelper.folderPath, @".*\..*"))
            {
                Debug.LogError("必须为文件夹路径");
                return;
            }
            string _path = AssetDatabase.GetAssetPath(m_ReferenceSource);
            if (!string.IsNullOrEmpty(_path))
            {
                string _guid = AssetDatabase.AssetPathToGUID(_path);
                StartFindReference(_guid);
            }
        }
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        foreach (var _object in m_ReferenceObjectDict.Keys)
        {
            GUILayout.BeginHorizontal();
            EditorGUILayout.ObjectField(_object, typeof(UnityEngine.Object), false);
            if (_object is GameObject &&
                GUILayout.Button("显示详细信息"))
            {
                if (!m_ReferenceDetailDict.ContainsKey(_object))
                {
                    List<RefDetail> _details = new List<RefDetail>();
                    GetReferenceDetail(m_ReferenceObjectDict[_object], AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferenceSource)), _details);
                    m_ReferenceDetailDict.Add(_object, _details);
                }
            }
            if (_object is GameObject)
            {
                m_ReferenceReplaceDict[_object] = EditorGUILayout.Toggle(m_ReferenceReplaceDict[_object]);
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            if (m_ReferenceDetailDict.ContainsKey(_object))
            {
                var _list = m_ReferenceDetailDict[_object];
                for (int i = 0; i < _list.Count; i++)
                {
                    var _detail = _list[i];
                    var _fatherDetail = _detail.fatherDetail;
                    GUILayout.BeginHorizontal();
                    GUILayout.Label(StringUtility.Contact(i + 1, ".", "Path: "));
                    var _path = StringUtility.Contact(_detail.fatherDetail, _fatherDetail == string.Empty ? string.Empty : "/", _detail.name);
                    GUILayout.TextField(_path);
                    if (_fatherDetail != string.Empty && GUILayout.Button("Goto"))
                    {
                        var _go = GameObject.Find(_path);
                        if (_go != null)
                        {
                            Selection.activeGameObject = _go;
                        }
                    }
                    if (_fatherDetail == string.Empty && GUILayout.Button("FindFather"))
                    {
                        _detail.fatherDetail = GetFatherDetail(_detail.fatherId);
                    }
                    GUILayout.FlexibleSpace();
                    GUILayout.EndHorizontal();
                }
            }
            GUILayout.Space(5);
        }
        GUILayout.EndScrollView();
    }
    private void DisplayPrefabDetail()
    {
        if (m_PrefabDetails.Count > 0 && GUILayout.Button("一键转换"))
        {
            for (int i = 0; i < m_PrefabDetails.Count; i++)
            {
                m_PrefabDetails[i].GuidToObjects();
            }
        }
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        for (int i = 0; i < m_PrefabDetails.Count; i++)
        {
            var _detail = m_PrefabDetails[i];
            if (_detail.guids.Count == 0)
            {
                continue;
            }
            GUILayout.BeginHorizontal();
            var _fatherDetail = _detail.fatherDetail;
            GUILayout.Label(StringUtility.Contact(i + 1, ".", "Path: "));
            var _path = StringUtility.Contact(_detail.fatherDetail, _fatherDetail == string.Empty ? string.Empty : "/", _detail.name);
            GUILayout.TextField(_path);
            if (_fatherDetail != string.Empty && GUILayout.Button("Goto"))
            {
                var _go = GameObject.Find(_path);
                if (_go != null)
                {
                    Selection.activeGameObject = _go;
                }
            }
            if (_fatherDetail == string.Empty && GUILayout.Button("FindFather"))
            {
                _detail.fatherDetail = GetFatherDetail(_detail.fatherId);
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            for (int k = 0; k < _detail.guids.Count; k++)
            {
                var _guid = _detail.guids[k];
                if (_detail.objectDict.ContainsKey(_guid))
                {
                    EditorGUILayout.ObjectField(_detail.objectDict[_guid], typeof(UnityEngine.Object), false);
                    continue;
                }
                GUILayout.BeginHorizontal();
                GUILayout.Label("Guid:");
                GUILayout.Label(_guid);
                if (GUILayout.Button("GUID To 资源"))
                {
                    if (!_detail.GuidToObject(k))
                    {
                        k--;
                    }
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
            }
            GUILayout.Space(10);
        }
        GUILayout.EndScrollView();
    }
    private void StartFindReference(string _guid)
    {
        m_ReferenceObjectDict.Clear();
        m_ReferenceReplaceDict.Clear();
        m_ReferenceDetailDict.Clear();
        m_RefDetailDict.Clear();
        var _referenceExtentions = GetReferenceExtention();
        if (_referenceExtentions.Count == 0)
        {
            Debug.LogError("未指定任意一种引用资源类型");
            return;
        }
        string[] _files = Directory.GetFiles(m_GlobalSearch ? Application.dataPath : ToolsHelper.folderPath, "*.*", SearchOption.AllDirectories)
            .Where(s => _referenceExtentions.Contains(Path.GetExtension(s).ToLower())).ToArray();
        int _index = 0;
        if (_files == null || _files.Length == 0)
        {
            EditorUtility.DisplayDialog("提示", "未找到任意文件", "确定");
            return;
        }
        EditorApplication.update = delegate ()
        {
            string _file = _files[_index];
            bool isCancel = EditorUtility.DisplayCancelableProgressBar("查找引用资源", _file, (float)_index / (float)_files.Length);
            var _allTxt = File.ReadAllText(_file);
            if (Regex.IsMatch(_allTxt, _guid))
            {
                UnityEngine.Object _object = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(GetRelativeAssetsPath(_file));
                m_ReferenceObjectDict.Add(_object, _allTxt);
                m_ReferenceReplaceDict.Add(_object, false);
            }
            _index++;
            if (isCancel || _index >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                _index = 0;
            }
        };
    }
    private List<string> GetReferenceExtention()
    {
        var _list = new List<string>();
        for (int i = 0; i < m_ReferenceDisplays.Length; i++)
        {
            if ((m_ReferenceType & (1 << i)) != 0)
            {
                switch ((ReferenceType)i)
                {
                    case ReferenceType.Material:
                        _list.Add(".mat");
                        break;
                    case ReferenceType.Prefab:
                        _list.Add(".prefab");
                        break;
                    case ReferenceType.Asset:
                        _list.Add(".asset");
                        break;
                    case ReferenceType.Scene:
                        _list.Add(".unity");
                        break;
                }
            }
        }
        return _list;
    }
    private readonly Regex s_PrefabRegex = new Regex(@"--- !u![0-9]+ \&([0-9]+)");
    private readonly Regex s_GameObjectRegex = new Regex(@"m_GameObject\: \{fileID\: ([0-9]+)\}");
    private readonly Regex s_GameObjectNameRegex = new Regex(@"m_Name\: ([a-zA-Z0-9_]+)");
    private readonly Regex s_GuidRegex = new Regex(@"guid\: ([a-z0-9]+)");
    private readonly Regex s_GameObjectFatherRegex = new Regex(@"m_Father\: \{fileID\: ([0-9]+)\}");
    private Dictionary<string, RefDetail> m_RefDetailDict = new Dictionary<string, RefDetail>();
    private void GetReferenceDetail(string _data, string _guid, List<RefDetail> _details)
    {
        var _strArray = s_PrefabRegex.Split(_data);
        MatchCollection _matchs = s_PrefabRegex.Matches(_data);
        List<string> _list = new List<string>(_strArray);
        m_RefDetailDict.Clear();
        if (_strArray != null)
        {
            _list.RemoveAll((x) =>
            {
                return Regex.IsMatch(x, "^[0-9]+$");
            });
            var _index = 1;
            EditorApplication.update = delegate ()
            {
                var _match = _matchs[_index - 1];
                GetRefComponent(_list[_index], _list[_index].Split('\n'), _match.Groups[1].Value);
                bool isCancel = EditorUtility.DisplayCancelableProgressBar("查找引用资源",
                    StringUtility.Contact(_index, "/", _list.Count), (float)_index / (float)_list.Count);
                _index++;
                if (isCancel || _index >= _list.Count)
                {
                    _index = 0;
                    if (_guid == string.Empty)
                    {
                        _details.AddRange(m_RefDetailDict.Values.ToList());
                        EditorUtility.ClearProgressBar();
                        EditorApplication.update = null;
                        System.GC.Collect();
                        return;
                    }
                    var _keys = m_RefDetailDict.Keys.ToList();
                    EditorApplication.update = delegate ()
                    {
                        var _detail = m_RefDetailDict[_keys[_index]];
                        if (_detail.guids.Contains(_guid))
                        {
                            _details.Add(_detail);
                        }
                        isCancel = EditorUtility.DisplayCancelableProgressBar("查找引用资源",
                            StringUtility.Contact(_index, "/", _keys.Count), (float)_index / (float)_keys.Count);
                        _index++;
                        if (isCancel || _index >= _keys.Count)
                        {
                            EditorUtility.ClearProgressBar();
                            _index = 0;
                            EditorApplication.update = null;
                            System.GC.Collect();
                        }
                    };
                }
            };
        }
    }
    private void GetRefComponent(string _source, string[] _msgs, string _fileId)
    {
        if (_msgs != null)
        {
            switch (_msgs[1])
            {
                case "GameObject:":
                    {
                        RefDetail _detail = new RefDetail();
                        m_RefDetailDict.Add(_fileId, _detail);
                        var _match = s_GameObjectNameRegex.Match(_source);
                        _detail.name = _match != null ? _match.Groups[1].Value : string.Empty;
                        _detail.fileId = _fileId;
                    }
                    break;
                case "MonoBehaviour:":
                    {
                        var _match = s_GameObjectRegex.Match(_source);
                        if (_match != null)
                        {
                            var _id = _match.Groups[1].Value;
                            var _refDetail = m_RefDetailDict.ContainsKey(_id) ? m_RefDetailDict[_id] : null;
                            if (_refDetail != null)
                            {
                                var _guidMatchs = s_GuidRegex.Matches(_source);
                                if (_guidMatchs != null)
                                {
                                    foreach (Match _guidMatch in _guidMatchs)
                                    {
                                        _refDetail.guids.Add(_guidMatch.Groups[1].Value);
                                    }
                                }
                            }
                        }
                    }
                    break;
                case "RectTransform:":
                    {
                        var _match = s_GameObjectRegex.Match(_source);
                        if (_match != null)
                        {
                            var _id = _match.Groups[1].Value;
                            var _refDetail = m_RefDetailDict.ContainsKey(_id) ? m_RefDetailDict[_id] : null;
                            if (_refDetail != null)
                            {
                                _refDetail.rectId = _fileId;
                                var _fatherMatch = s_GameObjectFatherRegex.Match(_source);
                                _refDetail.fatherId = _fatherMatch != null ? _fatherMatch.Groups[1].Value : string.Empty;
                            }
                        }
                    }
                    break;
            }
        }
    }
    public class RefDetail
    {
        public string fileId = string.Empty;
        public string name = string.Empty;
        public string fatherId = string.Empty;
        public string rectId = string.Empty;
        public string fatherDetail = string.Empty;
        public List<string> guids = new List<string>();
        public Dictionary<string, UnityEngine.Object> objectDict = new Dictionary<string, UnityEngine.Object>();
        public void GuidToObjects()
        {
            if (objectDict.Count >= guids.Count)
            {
                return;
            }
            for (int i = 0; i < guids.Count; i++)
            {
                if (objectDict.ContainsKey(guids[i]))
                {
                    continue;
                }
                if (!GuidToObject(i))
                {
                    i--;
                }
            }
        }
        public bool GuidToObject(int _index)
        {
            var _objectPath = AssetDatabase.GUIDToAssetPath(guids[_index]);
            var _object = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(_objectPath);
            if (_object == null || (_object != null && _object.name == "UnityEngine.UI"))
            {
                guids.RemoveAt(_index);
                return false;
            }
            else
            {
                objectDict.Add(guids[_index], _object);
                return true;
            }
        }
    }
    public string GetFatherDetail(string _fatherId)
    {
        if (_fatherId == string.Empty)
        {
            return string.Empty;
        }
        foreach (var _detail in m_RefDetailDict.Values)
        {
            if (_detail.rectId == _fatherId)
            {
                var _father = GetFatherDetail(_detail.fatherId);
                return StringUtility.Contact(GetFatherDetail(_detail.fatherId), _father == string.Empty ? string.Empty : "/", _detail.name);
            }
        }
        return string.Empty;
    }
    #endregion
    #region 查找界面上的指定文字
    [SerializeField] string m_RegexPattern = ".*[a-zA-Z]+.*";
    [SerializeField] bool m_IgnoreCaps = true;
    [SerializeField] string m_ReplaceLabelPath = string.Empty;
    private Dictionary<GameObject, List<string>> m_PrefabLabels = new Dictionary<GameObject, List<string>>();
    private List<Text> m_PrefabTexts = new List<Text>();
    private List<Text> m_PrefabCopyTexts = new List<Text>();
    private Dictionary<string, string> m_ReplaceLabelDict = new Dictionary<string, string>();
    protected string[] lineStep = new string[] { "\r\n" }; //行间隔体
    private void DisplayFindPrefabLabel()
    {
        DisplayPrefabPath();
        GUILayout.BeginHorizontal();
        GUILayout.Label("正则表达式:");
        m_RegexPattern = EditorGUILayout.TextField(m_RegexPattern);
        GUILayout.Label("忽略大小写");
        m_IgnoreCaps = EditorGUILayout.Toggle(m_IgnoreCaps);
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        GUILayout.Label("替换的文本文件:");
        GUILayout.Label(m_ReplaceLabelPath);
        if (GUILayout.Button("Broswer"))
        {
            m_ReplaceLabelPath = EditorUtility.OpenFilePanel("替换文本文件", "", "txt");
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        if (GUILayout.Button("查找"))
        {
            m_PrefabLabels.Clear();
            m_ReplaceLabelDict.Clear();
            if (ToolsHelper.folderPath == string.Empty)
            {
                return;
            }
            StartFindPrefabLabel();
        }
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        foreach (var _object in m_PrefabLabels.Keys)
        {
            var _list = m_PrefabLabels[_object];
            EditorGUILayout.ObjectField(_object, typeof(GameObject), false);
            for (int i = 0; i < _list.Count; i++)
            {
                EditorGUILayout.TextField(_list[i]);
            }
            GUILayout.Space(10);
        }
        GUILayout.EndScrollView();
    }
    private void StartFindPrefabLabel()
    {
        if (File.Exists(m_ReplaceLabelPath))
        {
            var _fileInfo = new FileInfo(m_ReplaceLabelPath);
            var _fs = _fileInfo.OpenRead();
            var _sr = new StreamReader(_fs, Encoding.UTF8);
            var lines = _sr.ReadToEnd().Split(lineStep, StringSplitOptions.None);
            m_ReplaceLabelDict.Clear();
            for (int i = 0; i < lines.Length; i++)
            {
                var _line = lines[i].Split('\t');
                if (_line.Length > 1 && _line[1] != string.Empty)
                {
                    var _key = _line[0].ToLower();
                    if (!m_ReplaceLabelDict.ContainsKey(_key))
                    {
                        m_ReplaceLabelDict.Add(_key, _line[1]);
                    }
                }
            }
            _fs.Dispose();
            _fs.Close();
        }
        string[] _files = Directory.GetFiles(ToolsHelper.folderPath, "*.prefab", SearchOption.AllDirectories);
        if (_files == null || _files.Length == 0)
        {
            return;
        }
        var _index = 0;
        EditorApplication.update = delegate ()
        {
            var _file = _files[_index];
            var _prefab = AssetDatabase.LoadAssetAtPath<GameObject>(GetRelativeAssetsPath(_file));
            if (_prefab != null)
            {
                FindAllText(_prefab, null);
                bool _change = false;
                if (m_PrefabTexts != null && m_PrefabTexts.Count > 0)
                {
                    for (int i = 0; i < m_PrefabTexts.Count; i++)
                    {
                        var _text = m_PrefabTexts[i];
                        TextEx _textEx = _text as TextEx;
                        if (_textEx != null && _textEx.isKey)
                        {
                            continue;
                        }
                        if (Regex.IsMatch(_text.text, m_RegexPattern, m_IgnoreCaps ? RegexOptions.IgnoreCase : RegexOptions.None))
                        {
                            List<string> _list = null;
                            if (!m_PrefabLabels.TryGetValue(_prefab, out _list))
                            {
                                _list = new List<string>();
                                m_PrefabLabels.Add(_prefab, _list);
                            }
                            _list.Add(GetParentName(_text.transform));
                            if (m_ReplaceLabelDict.Count > 0)
                            {
                                var _collections = Regex.Matches(_text.text, m_RegexPattern);
                                for (int k = 0; k < _collections.Count; k++)
                                {
                                    var _match = _collections[k] as Match;
                                    var _key = _match.Groups[1].Value;
                                    if (m_ReplaceLabelDict.ContainsKey(_key.ToLower()))
                                    {
                                        _text.text = Regex.Replace(_text.text, _key, m_ReplaceLabelDict[_key.ToLower()]);
                                        _change = true;
                                    }
                                }
                            }
                        }
                    }
                }
                if (_change)
                {
                    EditorUtility.SetDirty(_prefab);
                }
            }
            bool _isCancel = EditorUtility.DisplayCancelableProgressBar("查找界面文字",
               StringUtility.Contact(_index, "/", _files.Length), (float)_index / _files.Length);
            _index++;
            if (_isCancel || _index >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
                _index = 0;
            }
        };
    }
    void FindAllText(GameObject _prefab,GameObject _copy)
    {
        m_PrefabTexts.Clear();
        m_PrefabCopyTexts.Clear();
        FindChildText(_prefab.transform, ref m_PrefabTexts);
        if (_copy != null)
        {
            FindChildText(_copy.transform, ref m_PrefabCopyTexts);
        }
    }
    void FindChildText(Transform _transform, ref List<Text> _allTexts)
    {
        if (_transform != null)
        {
            var text = _transform.GetComponent<Text>();
            if (text != null)
            {
                _allTexts.Add(text);
            }
            for (int i = 0; i < _transform.childCount; i++)
            {
                FindChildText(_transform.GetChild(i), ref _allTexts);
            }
        }
    }
    string GetParentName(Transform _parent)
    {
        if (_parent.parent != null && _parent.GetComponent<WindowInfo>() == null)
        {
            return StringUtility.Contact(GetParentName(_parent.parent), "/", _parent.name);
        }
        return _parent.name;
    }
    #endregion
    #region 提取界面中文
    private Dictionary<string, string> m_ExtractChsDict = new Dictionary<string, string>();
    private Dictionary<string, bool> m_ExtractSerializedDict = new Dictionary<string, bool>();
    private void DisplayExtractChsLabel()
    {
        ToolsHelper.DisplayFolderPath();
        ToolsHelper.DisplayExternalPath();
        if (GUILayout.Button("开始查找", GUILayout.Width(200)))
        {
            m_ExtractChsDict.Clear();
            m_ExtractSerializedDict.Clear();
            if (ToolsHelper.folderPath.Equals(string.Empty))
            {
                return;
            }
            if (ToolsHelper.m_ExternalFilePath.Equals(string.Empty))
            {
                return;
            }
            StartExtractLabel();
        }
    }
    private void StartExtractLabel()
    {
        string[] _files = Directory.GetFiles(ToolsHelper.folderPath, "*.prefab", SearchOption.AllDirectories);
        if (_files == null || _files.Length == 0)
        {
            return;
        }
        var _index = 0;
        var inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance);
        EditorApplication.update = delegate ()
        {
            var _file = _files[_index];
            var _prefab = AssetDatabase.LoadAssetAtPath<GameObject>(GetRelativeAssetsPath(_file));
            if (_prefab != null)
            {
                var all_text = File.ReadAllText(_file);
                var _copy = PrefabUtility.InstantiatePrefab(_prefab) as GameObject;
                if (_copy != null)
                {
                    FindAllText(_prefab, _copy);
                    bool _change = false;
                    if (m_PrefabCopyTexts != null && m_PrefabCopyTexts.Count > 0)
                    {
                        for (int i = 0; i < m_PrefabCopyTexts.Count; i++)
                        {
                            var _text = m_PrefabCopyTexts[i];
                            var serializedObject = new SerializedObject(m_PrefabTexts[i]);
                            inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);
                            var localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile");
                            var fieldId = localIdProp.longValue;
                            bool isSerialized = ContainGuid(all_text, fieldId.ToString());
                            TextEx _textEx = _text as TextEx;
                            if (_textEx != null && _textEx.isKey)
                            {
                                continue;
                            }
                            RichText _richText = _text as RichText;
                            if (_richText != null && _richText.language)
                            {
                                continue;
                            }
                            if (Regex.IsMatch(_text.text, ".*[\u4e00-\u9fa5]+.*"))
                            {
                                _change = true;
                                var _name = GetParentName(_text.transform);
                                var _key = _name.Replace('/', '_');
                                _key = GetUnRepetitionKey(_key);
                                var _value = _text.text;
                                if (_textEx != null && !isSerialized)
                                {
                                    _textEx.text = _key;
                                    _textEx.isKey = true;
                                }
                                else if (_richText != null && !isSerialized)
                                {
                                    _richText.language = true;
                                    _richText.enableDisplay = _key;
                                }
                                else if (!isSerialized)
                                {
                                    var nTextEx = ToolsHelper.PasteText(_text);
                                    nTextEx.isKey = true;
                                    nTextEx.text = _key;
                                }
                                m_ExtractChsDict.Add(_key, _value);
                                m_ExtractSerializedDict.Add(_key, isSerialized);
                            }
                        }
                    }
                    if (_change)
                    {
                        PrefabUtility.ReplacePrefab(_copy, _prefab, ReplacePrefabOptions.ConnectToPrefab);
                    }
                    GameObject.DestroyImmediate(_copy);
                }
            }
            bool _isCancel = EditorUtility.DisplayCancelableProgressBar("提取界面中文",
               StringUtility.Contact(_index, "/", _files.Length), (float)_index / _files.Length);
            _index++;
            if (_isCancel || _index >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
                StartRecordExtract(ToolsHelper.m_ExternalFilePath);
                _index = 0;
            }
        };
    }
    static bool ContainGuid(string _serializedFile, string _guid)
    {
        if (string.IsNullOrEmpty(_serializedFile))
        {
            return false;
        }
        else
        {
            var matches = Regex.Matches(_serializedFile, _guid);
            return matches.Count > 2;
        }
    }
    private void StartRecordExtract(string _path)
    {
        using (FileStream fs = new FileStream(StringUtility.Contact(_path, "/logger.txt"), FileMode.Create, FileAccess.Write))
        {
            using (StreamWriter sw = new StreamWriter(fs))
            {
                foreach (var _key in m_ExtractChsDict.Keys)
                {
                    sw.WriteLine(StringUtility.Contact(_key, '\t', m_ExtractChsDict[_key], "\t", m_ExtractSerializedDict[_key]));
                }
            }
        }
    }
    static Regex m_TrimNumberRegex = new Regex(@"\d+$", RegexOptions.Singleline);
    private string GetUnRepetitionKey(string _key)
    {
        if (m_ExtractChsDict.ContainsKey(_key))
        {
            var _index = 0;
            if (m_TrimNumberRegex.IsMatch(_key))
            {
                var _match = m_TrimNumberRegex.Match(_key);
                int.TryParse(_match.Value, out _index);
                _index++;
                _key = m_TrimNumberRegex.Replace(_key, string.Empty);
            }
            _key = StringUtility.Contact(_key, _index);
            _key = GetUnRepetitionKey(_key);
        }
        return _key;
    }
    #endregion
    #region UI风格
    [SerializeField] Color m_ButtonTxtColor = Color.gray;
    private void DisplayUIStyle()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("按钮字色");
        m_ButtonTxtColor = EditorGUILayout.ColorField(m_ButtonTxtColor);
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    #endregion
    private void DisplayPrefabPath()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("预制体路径");
        m_ReplacePrefabPath = GUILayout.TextField(m_ReplacePrefabPath);
        m_LockPrefabPath = GUILayout.Toggle(m_LockPrefabPath, "Lock");
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    private Sprite GetSpriteByAssetPath(string _path)
    {
        return AssetDatabase.LoadAssetAtPath<Sprite>(GetRelativeAssetsPath(_path));
    }
    private string GetRelativeAssetsPath(string _path)
    {
        return "Assets" + Path.GetFullPath(_path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');
    }
    private string GetGUIDByAssets(UnityEngine.Object _object)
    {
        if (_object == null)
        {
            return string.Empty;
        }
        return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(_object));
    }
}
public static class ToolsHelper
{
    [SerializeField] public static string folderPath = string.Empty;
    [SerializeField] public static bool lockFolderPath = false;
    [SerializeField] public static string m_ExternalFilePath = string.Empty;
    public static void DisplayFolderPath()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("文件路径");
        folderPath = GUILayout.TextField(folderPath);
        lockFolderPath = GUILayout.Toggle(lockFolderPath, "Lock");
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    public static string GetRelativeAssetsPath(string _path)
    {
        return "Assets" + Path.GetFullPath(_path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');
    }
    public static string GetGUIDByAssets(UnityEngine.Object _object)
    {
        if (_object == null)
        {
            return string.Empty;
        }
        return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(_object));
    }
    public static void DisplayExternalPath()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label(StringUtility.Contact("文件夹路径:", m_ExternalFilePath));
        if (GUILayout.Button("选择文件根路径"))
        {
            var _path = EditorUtility.OpenFolderPanel("根路径", "", "");
            m_ExternalFilePath = _path;
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    static string content = string.Empty;
    static Font fontData = null;
    static FontStyle fontStyle;
    static int fontSize = 14;
    static float lineSpacing = 0f;
    static bool richText = true;
    static TextAnchor alignment;
    static HorizontalWrapMode hwmode;
    static VerticalWrapMode vwmode;
    static Color m_Color;
    static Material m_Material;
    static bool raycastTarget;
    public static TextEx PasteText(Text text)
    {
        content = text.text;
        fontData = text.font;
        fontStyle = text.fontStyle;
        fontSize = text.fontSize;
        lineSpacing = text.lineSpacing;
        richText = text.supportRichText;
        alignment = text.alignment;
        hwmode = text.horizontalOverflow;
        vwmode = text.verticalOverflow;
        m_Color = text.color;
        m_Material = text.material;
        raycastTarget = text.raycastTarget;
        var gameObject = text.gameObject;
        Component.DestroyImmediate(text);
        TextEx textex = gameObject.AddMissingComponent<TextEx>();
        textex.text = content;
        textex.font = fontData;
        textex.fontStyle = fontStyle;
        textex.fontSize = fontSize;
        textex.lineSpacing = lineSpacing;
        textex.supportRichText = richText;
        textex.alignment = alignment;
        textex.horizontalOverflow = hwmode;
        textex.verticalOverflow = vwmode;
        textex.color = m_Color;
        textex.material = m_Material;
        textex.raycastTarget = raycastTarget;
        return textex;
    }
}
using Snxxz.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
public class SpriteManageTool : EditorWindow
{
    enum SpriteManageType
    {
        RepeatSprite,
        UnUseResource,
        Reference,
        PrefabEnglishLabel,
        FormatPrefab,
        ButtonArea,
        ExtractChsLabel,
        ImageMiss,
        UIStyle,
    }
    private Vector2 m_ScrollPosition;
    private Texture2D m_DeleteTexture;
    private List<IconConfig> m_IconCfgs;
    [SerializeField]
    SpriteManageType m_SpriteManageType;
    private static readonly Regex Directory_Regex = new Regex(@"/([0-9a-zA-Z_]+)$");
    private static readonly Regex Name_Regex = new Regex(@"\\([0-9a-zA-Z_\.]+)");
    private static bool m_FindReference = false;
    #region 风格
    private GUIStyle m_ButtonStyle;
    private void InitStyle()
    {
        m_ButtonStyle = new GUIStyle();
    }
    #endregion
    [MenuItem("策划工具/图片资源")]
    public static void OpenWindow()
    {
        m_FindReference = false;
        SpriteManageTool _window = GetWindow(typeof(SpriteManageTool), false, "图片资源") as SpriteManageTool;
        _window.Show();
        _window.autoRepaintOnSceneChange = true;
    }
    [MenuItem("Assets/查找引用")]
    private static void FindReference()
    {
        m_FindReference = true;
        SpriteManageTool _window = GetWindow(typeof(SpriteManageTool), false, "图片资源") as SpriteManageTool;
        _window.Show();
        _window.autoRepaintOnSceneChange = true;
    }
    [MenuItem("Assets/查找引用", true)]
    private static bool FindReferenceValid()
    {
        string _path = AssetDatabase.GetAssetPath(Selection.activeObject);
        return (!string.IsNullOrEmpty(_path));
    }
    private void OnGUI()
    {
        GUI.skin.button.normal.textColor = Color.white;
        DisplayFuncToggle();
        UnityEngine.Object[] _objectArray = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets);
        var _selectPath = (_objectArray == null || _objectArray.Length == 0) ? string.Empty : Application.dataPath.Substring(0, Application.dataPath.LastIndexOf('/')) + "/" + AssetDatabase.GetAssetPath(_objectArray[0]);
        if (!ToolsHelper.lockFolderPath)
        {
            ToolsHelper.folderPath = _selectPath;
        }
        if (!m_LockPrefabPath)
        {
            m_ReplacePrefabPath = _selectPath;
        }
        GUI.skin.button.normal.textColor = m_ButtonTxtColor;
        switch (m_SpriteManageType)
        {
            case SpriteManageType.RepeatSprite:
                DisplayRepeat();
                break;
            case SpriteManageType.UnUseResource:
                DisplayUnUse();
                break;
            case SpriteManageType.Reference:
                DisplayReference();
                break;
            case SpriteManageType.PrefabEnglishLabel:
                DisplayFindPrefabLabel();
                break;
            case SpriteManageType.FormatPrefab:
                FormatPrefabTool.OnGUI();
                break;
            case SpriteManageType.ButtonArea:
                ButtonAreaTool.OnGUI();
                break;
            case SpriteManageType.ExtractChsLabel:
                DisplayExtractChsLabel();
                break;
            case SpriteManageType.ImageMiss:
                ImageMissTool.OnGUI();
                break;
            case SpriteManageType.UIStyle:
                DisplayUIStyle();
                break;
        }
    }
    private void OnEnable()
    {
        ConfigInitiator.EditorLoad();
        m_IconCfgs = IconConfig.GetValues();
        m_DeleteTexture = EditorGUIUtility.FindTexture("TreeEditor.Trash");
        InitStyle();
        m_SpriteManageType = m_FindReference ? SpriteManageType.Reference : SpriteManageType.RepeatSprite;
        if (m_FindReference)
        {
            m_ReferenceSource = Selection.activeObject;
        }
    }
    private void DisplayFuncToggle()
    {
        GUILayout.BeginHorizontal();
        string[] labels = new string[9] { "重复图片资源", "未引用的资源(图片)", "查找引用", "界面英文", "格式化预制体", "按钮监听区域", "提取界面中文","缺失图片组件", "UI风格" };
        m_SpriteManageType = (SpriteManageType)GUILayout.Toolbar((int)m_SpriteManageType, labels, "LargeButton", GUILayout.Width(labels.Length * 130));
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    #region 重复图片资源
    private Dictionary<string, RepeatSprite> m_RepeatSprites = new Dictionary<string, RepeatSprite>();
    private Dictionary<string, string> m_PrefabDict = new Dictionary<string, string>();
    private string m_ReplacePrefabPath = string.Empty;
    private bool m_LockPrefabPath = false;
    private void DisplayRepeat()
    {
        ToolsHelper.DisplayFolderPath();
        DisplayPrefabPath();
        GUILayout.BeginHorizontal();
        if (GUILayout.Button("查找", GUILayout.Width(50), GUILayout.Height(25)))
        {
            StartFindRepeat();
            StartFindPrefabsGuid();
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        foreach (var _key in m_RepeatSprites.Keys)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label(StringUtility.Contact("MD5:", _key));
            if (GUILayout.Button("合并"))
            {
                MergeSprite(m_RepeatSprites[_key]);
            }
            if (GUILayout.Button("合并并删除"))
            {
                MergeSprite(m_RepeatSprites[_key]);
                m_RepeatSprites[_key].DeleteOther();
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            var _repeat = m_RepeatSprites[_key];
            for (int i = 0; i < _repeat.repeats.Count; i++)
            {
                GUILayout.BeginHorizontal();
                EditorGUILayout.ObjectField(_repeat.repeats[i], typeof(Sprite), false);
                if (GUILayout.Toggle(_repeat.select == i, ""))
                {
                    _repeat.select = i;
                }
                if (_repeat.exitInCfgs[i] != -1)
                {
                    var _index = _repeat.exitInCfgs[i];
                    GUILayout.Label(StringUtility.Contact("key:", m_IconCfgs[_index].id, "    folder:",
                        m_IconCfgs[_index].folder));
                }
                if (_repeat.select != i && GUILayout.Button(m_DeleteTexture))
                {
                    _repeat.Delete(i);
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
            }
            GUILayout.Space(10);
        }
        GUILayout.EndScrollView();
    }
    private void StartFindRepeat()
    {
        if (Regex.IsMatch(ToolsHelper.folderPath, @".*\..*"))
        {
            Debug.LogError("该路径不是文件夹路径");
            return;
        }
        var _files = Directory.GetFiles(ToolsHelper.folderPath, "*.png", SearchOption.AllDirectories);
        if (_files == null || _files.Length == 0)
        {
            Debug.LogError("没找到图片");
            return;
        }
        m_RepeatSprites.Clear();
        int _index = 0;
        EditorApplication.update = () =>
        {
            var _md5 = GetFileMD5(_files[_index]);
            if (m_RepeatSprites.ContainsKey(_md5))
            {
                var _sprite = GetSpriteByAssetPath(_files[_index]);
                if (_sprite != null)
                {
                    var _existIndex = m_IconCfgs.FindIndex((x) =>
                    {
                        return x.sprite == _sprite.name;
                    });
                    m_RepeatSprites[_md5].Add(_sprite, _existIndex);
                }
            }
            else
            {
                var _repeat = new RepeatSprite();
                m_RepeatSprites.Add(_md5, _repeat);
                var _sprite = GetSpriteByAssetPath(_files[_index]);
                if (_sprite != null)
                {
                    var _existIndex = m_IconCfgs.FindIndex((x) =>
                    {
                        return x.sprite == _sprite.name;
                    });
                    _repeat.Add(_sprite, _existIndex);
                }
            }
            bool isCancel = EditorUtility.DisplayCancelableProgressBar("查找重复资源", "", (float)_index / (float)_files.Length);
            _index++;
            if (isCancel || _index >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                _index = 0;
                var _keys = m_RepeatSprites.Keys.ToList();
                if (_keys != null)
                {
                    for (int i = 0; i < _keys.Count; i++)
                    {
                        if (m_RepeatSprites[_keys[i]].Count < 2)
                        {
                            m_RepeatSprites.Remove(_keys[i]);
                        }
                    }
                }
                _keys = null;
            }
        };
    }
    private void StartFindPrefabsGuid()
    {
        if (Regex.IsMatch(m_ReplacePrefabPath, @".*\..*"))
        {
            Debug.LogError("该路径不是文件夹路径");
            return;
        }
        m_PrefabDict.Clear();
        string[] _prefabFiles = Directory.GetFiles(m_ReplacePrefabPath, "*.prefab", SearchOption.AllDirectories);
        if (_prefabFiles == null || _prefabFiles.Length == 0)
        {
            return;
        }
        for (int i = 0; i < _prefabFiles.Length; i++)
        {
            m_PrefabDict.Add(_prefabFiles[i], File.ReadAllText(_prefabFiles[i]));
        }
    }
    private void MergeSprite(RepeatSprite _repeat)
    {
        if (m_PrefabDict.Count == 0)
        {
            Debug.LogError("没找到预制体");
            return;
        }
        var _nGuid = GetGUIDByAssets(_repeat.repeats[_repeat.select]);
        for (int i = 0; i < _repeat.repeats.Count; i++)
        {
            if (i == _repeat.select)
            {
                continue;
            }
            var _guid = GetGUIDByAssets(_repeat.repeats[i]);
            var _list = m_PrefabDict.Keys.ToList();
            for (int j = 0; j < _list.Count; j++)
            {
                var _key = _list[j];
                if (Regex.IsMatch(m_PrefabDict[_key], _guid))
                {
                    string _file = Regex.Replace(m_PrefabDict[_key], _guid, _nGuid);
                    File.WriteAllText(_key, _file);
                    m_PrefabDict[_key] = _file;
                    AssetDatabase.SaveAssets();
                }
            }
        }
        AssetDatabase.Refresh();
    }
    private string GetFileMD5(string _filePath)
    {
        var _fileMd5 = string.Empty;
        using (FileStream fs = new FileStream(_filePath, FileMode.Open))
        {
            System.Security.Cryptography.MD5 _md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] _bytes = _md5.ComputeHash(fs);
            for (int i = 0; i < _bytes.Length; i++)
            {
                _fileMd5 += _bytes[i].ToString("x2");
            }
        }
        return _fileMd5;
    }
    public class RepeatSprite
    {
        public List<Sprite> repeats = new List<Sprite>();
        public List<int> exitInCfgs = new List<int>();
        public int select = 0;
        public void Add(Sprite _sprite, int _index)
        {
            repeats.Add(_sprite);
            exitInCfgs.Add(_index);
        }
        public void Delete(int _index)
        {
            var _sprite = repeats[_index];
            if (select > _index)
            {
                select--;
            }
            repeats.RemoveAt(_index);
            exitInCfgs.RemoveAt(_index);
            AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(_sprite));
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        public void DeleteOther()
        {
            while (repeats.Count > 1)
            {
                Delete(select == 0 ? 1 : 0);
            }
        }
        public int Count
        {
            get
            {
                return repeats.Count;
            }
        }
    }
    #endregion
    #region 未引用资源
    private Dictionary<string, List<Sprite>> m_UnUseSpriteDict = new Dictionary<string, List<Sprite>>();
    private List<string> m_UnUseSpritePaths = new List<string>();
    [SerializeField] string m_RemoveSpritePath = string.Empty;
    private void DisplayUnUse()
    {
        ToolsHelper.DisplayFolderPath();
        DisplayPrefabPath();
        GUILayout.BeginHorizontal();
        if (GUILayout.Button("查找", GUILayout.Width(50), GUILayout.Height(25)))
        {
            StartFindPrefabsGuid();
            StartFindUnUse();
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        foreach (var _key in m_UnUseSpriteDict.Keys)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label(StringUtility.Contact("Folder:", _key));
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            var _sprites = m_UnUseSpriteDict[_key];
            for (int i = 0; i < _sprites.Count; i++)
            {
                GUILayout.BeginHorizontal();
                EditorGUILayout.ObjectField(_sprites[i], typeof(Sprite), false);
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
            }
            GUILayout.Space(10);
        }
        GUILayout.EndScrollView();
        GUILayout.BeginHorizontal();
        GUILayout.Label(StringUtility.Contact("移除路径:", m_RemoveSpritePath));
        if (GUILayout.Button("选择移出的文件根路径"))
        {
            var _path = EditorUtility.OpenFolderPanel("根路径", "", "");
            m_RemoveSpritePath = _path;
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        if (GUILayout.Button("开始移除"))
        {
            StartRemoveSprite();
        }
        GUILayout.Space(20);
    }
    private void StartFindUnUse()
    {
        m_UnUseSpriteDict.Clear();
        m_UnUseSpritePaths.Clear();
        if (Regex.IsMatch(ToolsHelper.folderPath, @".*\..*"))
        {
            Debug.LogError("该路径不是文件夹路径");
            return;
        }
        var _files = Directory.GetFiles(ToolsHelper.folderPath, "*.png", SearchOption.AllDirectories);
        if (_files == null || _files.Length == 0)
        {
            Debug.LogError("没找到图片");
            return;
        }
        var _list = m_PrefabDict.Values.ToList();
        int i = 0;
        EditorApplication.update = delegate ()
        {
            var _guid = AssetDatabase.AssetPathToGUID(GetRelativeAssetsPath(_files[i]));
            FileInfo _fileInfo = new FileInfo(_files[i]);
            bool isCancel = EditorUtility.DisplayCancelableProgressBar("查找未引用资源",
                StringUtility.Contact(i, "/", _files.Length), (float)i / _files.Length);
            var _spriteName = Regex.Replace(_fileInfo.Name, @"\.png", string.Empty, RegexOptions.IgnoreCase);
            var _index = m_IconCfgs.FindIndex((x) =>
            {
                return x.sprite.ToLower().Equals(_spriteName.ToLower())
                && x.folder == _fileInfo.Directory.Name;
            });
            if (_index == -1)
            {
                bool _unUse = true;
                for (int k = 0; k < _list.Count; k++)
                {
                    if (Regex.IsMatch(_list[k], _guid))
                    {
                        _unUse = false;
                        break;
                    }
                }
                if (_unUse)
                {
                    var _sprite = GetSpriteByAssetPath(_files[i]);
                    List<Sprite> _sprites = null;
                    if (!m_UnUseSpriteDict.TryGetValue(_fileInfo.Directory.Name, out _sprites))
                    {
                        _sprites = new List<Sprite>();
                        m_UnUseSpriteDict.Add(_fileInfo.Directory.Name, _sprites);
                    }
                    _sprites.Add(_sprite);
                    m_UnUseSpritePaths.Add(_files[i]);
                }
            }
            i++;
            if (isCancel || i >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                i = 0;
            }
        };
    }
    private void StartRemoveSprite()
    {
        if (m_UnUseSpriteDict.Count == 0)
        {
            return;
        }
        if (!Directory_Regex.IsMatch(m_RemoveSpritePath))
        {
            return;
        }
        var _directory = Directory_Regex.Match(m_RemoveSpritePath).Groups[1].Value;
        var _path = StringUtility.Contact(m_RemoveSpritePath, "/", _directory);
        if (!Directory.Exists(_path))
        {
            Directory.CreateDirectory(_path);
        }
        StartRecordRemoveSprite(_path);
        for (int i = 0; i < m_UnUseSpritePaths.Count; i++)
        {
            var _extention = Name_Regex.Match(m_UnUseSpritePaths[i]).Groups[1].Value;
            File.Move(m_UnUseSpritePaths[i], StringUtility.Contact(_path, @"\", _extention));
        }
        m_UnUseSpriteDict.Clear();
        m_UnUseSpritePaths.Clear();
        AssetDatabase.Refresh();
    }
    private void StartRecordRemoveSprite(string _path)
    {
        using (FileStream fs = new FileStream(StringUtility.Contact(_path, "/logger.txt"), FileMode.Create, FileAccess.Write))
        {
            using (StreamWriter sw = new StreamWriter(fs))
            {
                for (int i = 0; i < m_UnUseSpritePaths.Count; i++)
                {
                    sw.WriteLine(m_UnUseSpritePaths[i]);
                }
            }
        }
    }
    #endregion
    #region 引用资源
    private UnityEngine.Object m_ReferenceSource;
    private UnityEngine.Object m_ReferenceReplace;
    private static string[] m_ReferenceDisplays = new string[] { "Material", "Prefab", "Asset", "Scene" };
    private Dictionary<UnityEngine.Object, string> m_ReferenceObjectDict = new Dictionary<UnityEngine.Object, string>();
    private Dictionary<UnityEngine.Object, bool> m_ReferenceReplaceDict = new Dictionary<UnityEngine.Object, bool>();
    private Dictionary<UnityEngine.Object, List<RefDetail>> m_ReferenceDetailDict = new Dictionary<UnityEngine.Object, List<RefDetail>>();
    private List<RefDetail> m_PrefabDetails = new List<RefDetail>();
    private string m_ReferenceGUID = string.Empty;
    [SerializeField] bool m_GlobalSearch = false;
    [SerializeField] int m_ReferenceType = 1 << (int)ReferenceType.Prefab;
    public enum ReferenceType
    {
        Material,
        Prefab,
        Asset,
        Scene,
    }
    private void DisplayReference()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("被引用的资源");
        m_ReferenceSource = EditorGUILayout.ObjectField(m_ReferenceSource, typeof(UnityEngine.Object), false);
        m_GlobalSearch = GUILayout.Toggle(m_GlobalSearch, "全局搜索");
        if (m_ReferenceSource != null && GUILayout.Button("显示GUID"))
        {
            m_ReferenceGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferenceSource));
        }
        if (m_ReferenceSource != null && m_ReferenceSource is GameObject && GUILayout.Button("分析Prefab"))
        {
            m_PrefabDetails.Clear();
            GetReferenceDetail(File.ReadAllText(AssetDatabase.GetAssetPath(m_ReferenceSource)), string.Empty, m_PrefabDetails);
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        GUILayout.Label("GUID:");
        EditorGUILayout.TextField(m_ReferenceGUID);
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        if (m_ReferenceSource != null && m_ReferenceSource is GameObject)
        {
            DisplayPrefabDetail();
            return;
        }
        if (!m_GlobalSearch)
        {
            ToolsHelper.DisplayFolderPath();
        }
        GUILayout.BeginHorizontal();
        GUILayout.Label("引用资源的类型");
        m_ReferenceType = EditorGUILayout.MaskField((int)m_ReferenceType, m_ReferenceDisplays);
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        if (m_ReferenceSource != null && m_ReferenceSource is Texture2D)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("替换资源");
            m_ReferenceReplace = EditorGUILayout.ObjectField(m_ReferenceReplace, typeof(UnityEngine.Object), false);
            if (!(m_ReferenceReplace is Texture2D))
            {
                m_ReferenceReplace = null;
            }
            if (m_ReferenceObjectDict.Count > 0 && m_ReferenceReplace != null)
            {
                if (GUILayout.Button("一键替换"))
                {
                    var _replaceGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferenceReplace));
                    m_ReferenceGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferenceSource));
                    foreach (var _object in m_ReferenceReplaceDict.Keys)
                    {
                        if (m_ReferenceReplaceDict[_object] && m_ReferenceObjectDict.ContainsKey(_object))
                        {
                            var _allText = m_ReferenceObjectDict[_object];
                            var _path = AssetDatabase.GetAssetPath(_object);
                            if (Regex.IsMatch(_allText, m_ReferenceGUID))
                            {
                                string _file = Regex.Replace(_allText, m_ReferenceGUID, _replaceGuid);
                                File.WriteAllText(_path, _file);
                                AssetDatabase.SaveAssets();
                                AssetDatabase.Refresh();
                            }
                            m_ReferenceObjectDict.Remove(_object);
                        }
                    }
                }
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
        }
        if (GUILayout.Button("查找"))
        {
            if (m_ReferenceSource == null)
            {
                Debug.LogError("未指定所引用的资源");
                return;
            }
            if (!m_GlobalSearch && Regex.IsMatch(ToolsHelper.folderPath, @".*\..*"))
            {
                Debug.LogError("必须为文件夹路径");
                return;
            }
            string _path = AssetDatabase.GetAssetPath(m_ReferenceSource);
            if (!string.IsNullOrEmpty(_path))
            {
                string _guid = AssetDatabase.AssetPathToGUID(_path);
                StartFindReference(_guid);
            }
        }
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        foreach (var _object in m_ReferenceObjectDict.Keys)
        {
            GUILayout.BeginHorizontal();
            EditorGUILayout.ObjectField(_object, typeof(UnityEngine.Object), false);
            if (_object is GameObject &&
                GUILayout.Button("显示详细信息"))
            {
                if (!m_ReferenceDetailDict.ContainsKey(_object))
                {
                    List<RefDetail> _details = new List<RefDetail>();
                    GetReferenceDetail(m_ReferenceObjectDict[_object], AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferenceSource)), _details);
                    m_ReferenceDetailDict.Add(_object, _details);
                }
            }
            if (_object is GameObject)
            {
                m_ReferenceReplaceDict[_object] = EditorGUILayout.Toggle(m_ReferenceReplaceDict[_object]);
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            if (m_ReferenceDetailDict.ContainsKey(_object))
            {
                var _list = m_ReferenceDetailDict[_object];
                for (int i = 0; i < _list.Count; i++)
                {
                    var _detail = _list[i];
                    var _fatherDetail = _detail.fatherDetail;
                    GUILayout.BeginHorizontal();
                    GUILayout.Label(StringUtility.Contact(i + 1, ".", "Path: "));
                    var _path = StringUtility.Contact(_detail.fatherDetail, _fatherDetail == string.Empty ? string.Empty : "/", _detail.name);
                    GUILayout.TextField(_path);
                    if (_fatherDetail != string.Empty && GUILayout.Button("Goto"))
                    {
                        var _go = GameObject.Find(_path);
                        if (_go != null)
                        {
                            Selection.activeGameObject = _go;
                        }
                    }
                    if (_fatherDetail == string.Empty && GUILayout.Button("FindFather"))
                    {
                        _detail.fatherDetail = GetFatherDetail(_detail.fatherId);
                    }
                    GUILayout.FlexibleSpace();
                    GUILayout.EndHorizontal();
                }
            }
            GUILayout.Space(5);
        }
        GUILayout.EndScrollView();
    }
    private void DisplayPrefabDetail()
    {
        if (m_PrefabDetails.Count > 0 && GUILayout.Button("一键转换"))
        {
            for (int i = 0; i < m_PrefabDetails.Count; i++)
            {
                m_PrefabDetails[i].GuidToObjects();
            }
        }
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        for (int i = 0; i < m_PrefabDetails.Count; i++)
        {
            var _detail = m_PrefabDetails[i];
            if (_detail.guids.Count == 0)
            {
                continue;
            }
            GUILayout.BeginHorizontal();
            var _fatherDetail = _detail.fatherDetail;
            GUILayout.Label(StringUtility.Contact(i + 1, ".", "Path: "));
            var _path = StringUtility.Contact(_detail.fatherDetail, _fatherDetail == string.Empty ? string.Empty : "/", _detail.name);
            GUILayout.TextField(_path);
            if (_fatherDetail != string.Empty && GUILayout.Button("Goto"))
            {
                var _go = GameObject.Find(_path);
                if (_go != null)
                {
                    Selection.activeGameObject = _go;
                }
            }
            if (_fatherDetail == string.Empty && GUILayout.Button("FindFather"))
            {
                _detail.fatherDetail = GetFatherDetail(_detail.fatherId);
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            for (int k = 0; k < _detail.guids.Count; k++)
            {
                var _guid = _detail.guids[k];
                if (_detail.objectDict.ContainsKey(_guid))
                {
                    EditorGUILayout.ObjectField(_detail.objectDict[_guid], typeof(UnityEngine.Object), false);
                    continue;
                }
                GUILayout.BeginHorizontal();
                GUILayout.Label("Guid:");
                GUILayout.Label(_guid);
                if (GUILayout.Button("GUID To 资源"))
                {
                    if (!_detail.GuidToObject(k))
                    {
                        k--;
                    }
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
            }
            GUILayout.Space(10);
        }
        GUILayout.EndScrollView();
    }
    private void StartFindReference(string _guid)
    {
        m_ReferenceObjectDict.Clear();
        m_ReferenceReplaceDict.Clear();
        m_ReferenceDetailDict.Clear();
        m_RefDetailDict.Clear();
        var _referenceExtentions = GetReferenceExtention();
        if (_referenceExtentions.Count == 0)
        {
            Debug.LogError("未指定任意一种引用资源类型");
            return;
        }
        string[] _files = Directory.GetFiles(m_GlobalSearch ? Application.dataPath : ToolsHelper.folderPath, "*.*", SearchOption.AllDirectories)
            .Where(s => _referenceExtentions.Contains(Path.GetExtension(s).ToLower())).ToArray();
        int _index = 0;
        if (_files == null || _files.Length == 0)
        {
            EditorUtility.DisplayDialog("提示", "未找到任意文件", "确定");
            return;
        }
        EditorApplication.update = delegate ()
        {
            string _file = _files[_index];
            bool isCancel = EditorUtility.DisplayCancelableProgressBar("查找引用资源", _file, (float)_index / (float)_files.Length);
            var _allTxt = File.ReadAllText(_file);
            if (Regex.IsMatch(_allTxt, _guid))
            {
                UnityEngine.Object _object = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(GetRelativeAssetsPath(_file));
                m_ReferenceObjectDict.Add(_object, _allTxt);
                m_ReferenceReplaceDict.Add(_object, false);
            }
            _index++;
            if (isCancel || _index >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                _index = 0;
            }
        };
    }
    private List<string> GetReferenceExtention()
    {
        var _list = new List<string>();
        for (int i = 0; i < m_ReferenceDisplays.Length; i++)
        {
            if ((m_ReferenceType & (1 << i)) != 0)
            {
                switch ((ReferenceType)i)
                {
                    case ReferenceType.Material:
                        _list.Add(".mat");
                        break;
                    case ReferenceType.Prefab:
                        _list.Add(".prefab");
                        break;
                    case ReferenceType.Asset:
                        _list.Add(".asset");
                        break;
                    case ReferenceType.Scene:
                        _list.Add(".unity");
                        break;
                }
            }
        }
        return _list;
    }
    private readonly Regex s_PrefabRegex = new Regex(@"--- !u![0-9]+ \&([0-9]+)");
    private readonly Regex s_GameObjectRegex = new Regex(@"m_GameObject\: \{fileID\: ([0-9]+)\}");
    private readonly Regex s_GameObjectNameRegex = new Regex(@"m_Name\: ([a-zA-Z0-9_]+)");
    private readonly Regex s_GuidRegex = new Regex(@"guid\: ([a-z0-9]+)");
    private readonly Regex s_GameObjectFatherRegex = new Regex(@"m_Father\: \{fileID\: ([0-9]+)\}");
    private Dictionary<string, RefDetail> m_RefDetailDict = new Dictionary<string, RefDetail>();
    private void GetReferenceDetail(string _data, string _guid, List<RefDetail> _details)
    {
        var _strArray = s_PrefabRegex.Split(_data);
        MatchCollection _matchs = s_PrefabRegex.Matches(_data);
        List<string> _list = new List<string>(_strArray);
        m_RefDetailDict.Clear();
        if (_strArray != null)
        {
            _list.RemoveAll((x) =>
            {
                return Regex.IsMatch(x, "^[0-9]+$");
            });
            var _index = 1;
            EditorApplication.update = delegate ()
            {
                var _match = _matchs[_index - 1];
                GetRefComponent(_list[_index], _list[_index].Split('\n'), _match.Groups[1].Value);
                bool isCancel = EditorUtility.DisplayCancelableProgressBar("查找引用资源",
                    StringUtility.Contact(_index, "/", _list.Count), (float)_index / (float)_list.Count);
                _index++;
                if (isCancel || _index >= _list.Count)
                {
                    _index = 0;
                    if (_guid == string.Empty)
                    {
                        _details.AddRange(m_RefDetailDict.Values.ToList());
                        EditorUtility.ClearProgressBar();
                        EditorApplication.update = null;
                        System.GC.Collect();
                        return;
                    }
                    var _keys = m_RefDetailDict.Keys.ToList();
                    EditorApplication.update = delegate ()
                    {
                        var _detail = m_RefDetailDict[_keys[_index]];
                        if (_detail.guids.Contains(_guid))
                        {
                            _details.Add(_detail);
                        }
                        isCancel = EditorUtility.DisplayCancelableProgressBar("查找引用资源",
                            StringUtility.Contact(_index, "/", _keys.Count), (float)_index / (float)_keys.Count);
                        _index++;
                        if (isCancel || _index >= _keys.Count)
                        {
                            EditorUtility.ClearProgressBar();
                            _index = 0;
                            EditorApplication.update = null;
                            System.GC.Collect();
                        }
                    };
                }
            };
        }
    }
    private void GetRefComponent(string _source, string[] _msgs, string _fileId)
    {
        if (_msgs != null)
        {
            switch (_msgs[1])
            {
                case "GameObject:":
                    {
                        RefDetail _detail = new RefDetail();
                        m_RefDetailDict.Add(_fileId, _detail);
                        var _match = s_GameObjectNameRegex.Match(_source);
                        _detail.name = _match != null ? _match.Groups[1].Value : string.Empty;
                        _detail.fileId = _fileId;
                    }
                    break;
                case "MonoBehaviour:":
                    {
                        var _match = s_GameObjectRegex.Match(_source);
                        if (_match != null)
                        {
                            var _id = _match.Groups[1].Value;
                            var _refDetail = m_RefDetailDict.ContainsKey(_id) ? m_RefDetailDict[_id] : null;
                            if (_refDetail != null)
                            {
                                var _guidMatchs = s_GuidRegex.Matches(_source);
                                if (_guidMatchs != null)
                                {
                                    foreach (Match _guidMatch in _guidMatchs)
                                    {
                                        _refDetail.guids.Add(_guidMatch.Groups[1].Value);
                                    }
                                }
                            }
                        }
                    }
                    break;
                case "RectTransform:":
                    {
                        var _match = s_GameObjectRegex.Match(_source);
                        if (_match != null)
                        {
                            var _id = _match.Groups[1].Value;
                            var _refDetail = m_RefDetailDict.ContainsKey(_id) ? m_RefDetailDict[_id] : null;
                            if (_refDetail != null)
                            {
                                _refDetail.rectId = _fileId;
                                var _fatherMatch = s_GameObjectFatherRegex.Match(_source);
                                _refDetail.fatherId = _fatherMatch != null ? _fatherMatch.Groups[1].Value : string.Empty;
                            }
                        }
                    }
                    break;
            }
        }
    }
    public class RefDetail
    {
        public string fileId = string.Empty;
        public string name = string.Empty;
        public string fatherId = string.Empty;
        public string rectId = string.Empty;
        public string fatherDetail = string.Empty;
        public List<string> guids = new List<string>();
        public Dictionary<string, UnityEngine.Object> objectDict = new Dictionary<string, UnityEngine.Object>();
        public void GuidToObjects()
        {
            if (objectDict.Count >= guids.Count)
            {
                return;
            }
            for (int i = 0; i < guids.Count; i++)
            {
                if (objectDict.ContainsKey(guids[i]))
                {
                    continue;
                }
                if (!GuidToObject(i))
                {
                    i--;
                }
            }
        }
        public bool GuidToObject(int _index)
        {
            var _objectPath = AssetDatabase.GUIDToAssetPath(guids[_index]);
            var _object = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(_objectPath);
            if (_object == null || (_object != null && _object.name == "UnityEngine.UI"))
            {
                guids.RemoveAt(_index);
                return false;
            }
            else
            {
                objectDict.Add(guids[_index], _object);
                return true;
            }
        }
    }
    public string GetFatherDetail(string _fatherId)
    {
        if (_fatherId == string.Empty)
        {
            return string.Empty;
        }
        foreach (var _detail in m_RefDetailDict.Values)
        {
            if (_detail.rectId == _fatherId)
            {
                var _father = GetFatherDetail(_detail.fatherId);
                return StringUtility.Contact(GetFatherDetail(_detail.fatherId), _father == string.Empty ? string.Empty : "/", _detail.name);
            }
        }
        return string.Empty;
    }
    #endregion
    #region 查找界面上的指定文字
    [SerializeField] string m_RegexPattern = ".*[a-zA-Z]+.*";
    [SerializeField] bool m_IgnoreCaps = true;
    [SerializeField] string m_ReplaceLabelPath = string.Empty;
    private Dictionary<GameObject, List<string>> m_PrefabLabels = new Dictionary<GameObject, List<string>>();
    private List<Text> m_PrefabTexts = new List<Text>();
    private List<Text> m_PrefabCopyTexts = new List<Text>();
    private Dictionary<string, string> m_ReplaceLabelDict = new Dictionary<string, string>();
    protected string[] lineStep = new string[] { "\r\n" }; //行间隔体
    private void DisplayFindPrefabLabel()
    {
        DisplayPrefabPath();
        GUILayout.BeginHorizontal();
        GUILayout.Label("正则表达式:");
        m_RegexPattern = EditorGUILayout.TextField(m_RegexPattern);
        GUILayout.Label("忽略大小写");
        m_IgnoreCaps = EditorGUILayout.Toggle(m_IgnoreCaps);
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        GUILayout.Label("替换的文本文件:");
        GUILayout.Label(m_ReplaceLabelPath);
        if (GUILayout.Button("Broswer"))
        {
            m_ReplaceLabelPath = EditorUtility.OpenFilePanel("替换文本文件", "", "txt");
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        if (GUILayout.Button("查找"))
        {
            m_PrefabLabels.Clear();
            m_ReplaceLabelDict.Clear();
            if (ToolsHelper.folderPath == string.Empty)
            {
                return;
            }
            StartFindPrefabLabel();
        }
        m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
        foreach (var _object in m_PrefabLabels.Keys)
        {
            var _list = m_PrefabLabels[_object];
            EditorGUILayout.ObjectField(_object, typeof(GameObject), false);
            for (int i = 0; i < _list.Count; i++)
            {
                EditorGUILayout.TextField(_list[i]);
            }
            GUILayout.Space(10);
        }
        GUILayout.EndScrollView();
    }
    private void StartFindPrefabLabel()
    {
        if (File.Exists(m_ReplaceLabelPath))
        {
            var _fileInfo = new FileInfo(m_ReplaceLabelPath);
            var _fs = _fileInfo.OpenRead();
            var _sr = new StreamReader(_fs, Encoding.UTF8);
            var lines = _sr.ReadToEnd().Split(lineStep, StringSplitOptions.None);
            m_ReplaceLabelDict.Clear();
            for (int i = 0; i < lines.Length; i++)
            {
                var _line = lines[i].Split('\t');
                if (_line.Length > 1 && _line[1] != string.Empty)
                {
                    var _key = _line[0].ToLower();
                    if (!m_ReplaceLabelDict.ContainsKey(_key))
                    {
                        m_ReplaceLabelDict.Add(_key, _line[1]);
                    }
                }
            }
            _fs.Dispose();
            _fs.Close();
        }
        string[] _files = Directory.GetFiles(ToolsHelper.folderPath, "*.prefab", SearchOption.AllDirectories);
        if (_files == null || _files.Length == 0)
        {
            return;
        }
        var _index = 0;
        EditorApplication.update = delegate ()
        {
            var _file = _files[_index];
            var _prefab = AssetDatabase.LoadAssetAtPath<GameObject>(GetRelativeAssetsPath(_file));
            if (_prefab != null)
            {
                FindAllText(_prefab, null);
                bool _change = false;
                if (m_PrefabTexts != null && m_PrefabTexts.Count > 0)
                {
                    for (int i = 0; i < m_PrefabTexts.Count; i++)
                    {
                        var _text = m_PrefabTexts[i];
                        TextEx _textEx = _text as TextEx;
                        if (_textEx != null && _textEx.isKey)
                        {
                            continue;
                        }
                        if (Regex.IsMatch(_text.text, m_RegexPattern, m_IgnoreCaps ? RegexOptions.IgnoreCase : RegexOptions.None))
                        {
                            List<string> _list = null;
                            if (!m_PrefabLabels.TryGetValue(_prefab, out _list))
                            {
                                _list = new List<string>();
                                m_PrefabLabels.Add(_prefab, _list);
                            }
                            _list.Add(GetParentName(_text.transform));
                            if (m_ReplaceLabelDict.Count > 0)
                            {
                                var _collections = Regex.Matches(_text.text, m_RegexPattern);
                                for (int k = 0; k < _collections.Count; k++)
                                {
                                    var _match = _collections[k] as Match;
                                    var _key = _match.Groups[1].Value;
                                    if (m_ReplaceLabelDict.ContainsKey(_key.ToLower()))
                                    {
                                        _text.text = Regex.Replace(_text.text, _key, m_ReplaceLabelDict[_key.ToLower()]);
                                        _change = true;
                                    }
                                }
                            }
                        }
                    }
                }
                if (_change)
                {
                    EditorUtility.SetDirty(_prefab);
                }
            }
            bool _isCancel = EditorUtility.DisplayCancelableProgressBar("查找界面文字",
               StringUtility.Contact(_index, "/", _files.Length), (float)_index / _files.Length);
            _index++;
            if (_isCancel || _index >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
                _index = 0;
            }
        };
    }
    void FindAllText(GameObject _prefab,GameObject _copy)
    {
        m_PrefabTexts.Clear();
        m_PrefabCopyTexts.Clear();
        FindChildText(_prefab.transform, ref m_PrefabTexts);
        if (_copy != null)
        {
            FindChildText(_copy.transform, ref m_PrefabCopyTexts);
        }
    }
    void FindChildText(Transform _transform, ref List<Text> _allTexts)
    {
        if (_transform != null)
        {
            var text = _transform.GetComponent<Text>();
            if (text != null)
            {
                _allTexts.Add(text);
            }
            for (int i = 0; i < _transform.childCount; i++)
            {
                FindChildText(_transform.GetChild(i), ref _allTexts);
            }
        }
    }
    string GetParentName(Transform _parent)
    {
        if (_parent.parent != null && _parent.GetComponent<WindowInfo>() == null)
        {
            return StringUtility.Contact(GetParentName(_parent.parent), "/", _parent.name);
        }
        return _parent.name;
    }
    #endregion
    #region 提取界面中文
    private Dictionary<string, string> m_ExtractChsDict = new Dictionary<string, string>();
    private Dictionary<string, bool> m_ExtractSerializedDict = new Dictionary<string, bool>();
    private void DisplayExtractChsLabel()
    {
        ToolsHelper.DisplayFolderPath();
        ToolsHelper.DisplayExternalPath();
        if (GUILayout.Button("开始查找", GUILayout.Width(200)))
        {
            m_ExtractChsDict.Clear();
            m_ExtractSerializedDict.Clear();
            if (ToolsHelper.folderPath.Equals(string.Empty))
            {
                return;
            }
            if (ToolsHelper.m_ExternalFilePath.Equals(string.Empty))
            {
                return;
            }
            StartExtractLabel();
        }
    }
    private void StartExtractLabel()
    {
        string[] _files = Directory.GetFiles(ToolsHelper.folderPath, "*.prefab", SearchOption.AllDirectories);
        if (_files == null || _files.Length == 0)
        {
            return;
        }
        var _index = 0;
        var inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance);
        EditorApplication.update = delegate ()
        {
            var _file = _files[_index];
            var _prefab = AssetDatabase.LoadAssetAtPath<GameObject>(GetRelativeAssetsPath(_file));
            if (_prefab != null)
            {
                var all_text = File.ReadAllText(_file);
                var _copy = PrefabUtility.InstantiatePrefab(_prefab) as GameObject;
                if (_copy != null)
                {
                    FindAllText(_prefab, _copy);
                    bool _change = false;
                    if (m_PrefabCopyTexts != null && m_PrefabCopyTexts.Count > 0)
                    {
                        for (int i = 0; i < m_PrefabCopyTexts.Count; i++)
                        {
                            var _text = m_PrefabCopyTexts[i];
                            var serializedObject = new SerializedObject(m_PrefabTexts[i]);
                            inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);
                            var localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile");
                            var fieldId = localIdProp.longValue;
                            bool isSerialized = ContainGuid(all_text, fieldId.ToString());
                            TextEx _textEx = _text as TextEx;
                            if (_textEx != null && _textEx.isKey)
                            {
                                continue;
                            }
                            RichText _richText = _text as RichText;
                            if (_richText != null && _richText.language)
                            {
                                continue;
                            }
                            if (Regex.IsMatch(_text.text, ".*[\u4e00-\u9fa5]+.*"))
                            {
                                _change = true;
                                var _name = GetParentName(_text.transform);
                                var _key = _name.Replace('/', '_');
                                _key = GetUnRepetitionKey(_key);
                                var _value = _text.text;
                                if (_textEx != null && !isSerialized)
                                {
                                    _textEx.text = _key;
                                    _textEx.isKey = true;
                                }
                                else if (_richText != null && !isSerialized)
                                {
                                    _richText.language = true;
                                    _richText.enableDisplay = _key;
                                }
                                else if (!isSerialized)
                                {
                                    var nTextEx = ToolsHelper.PasteText(_text);
                                    nTextEx.isKey = true;
                                    nTextEx.text = _key;
                                }
                                m_ExtractChsDict.Add(_key, _value);
                                m_ExtractSerializedDict.Add(_key, isSerialized);
                            }
                        }
                    }
                    if (_change)
                    {
                        PrefabUtility.ReplacePrefab(_copy, _prefab, ReplacePrefabOptions.ConnectToPrefab);
                    }
                    GameObject.DestroyImmediate(_copy);
                }
            }
            bool _isCancel = EditorUtility.DisplayCancelableProgressBar("提取界面中文",
               StringUtility.Contact(_index, "/", _files.Length), (float)_index / _files.Length);
            _index++;
            if (_isCancel || _index >= _files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
                StartRecordExtract(ToolsHelper.m_ExternalFilePath);
                _index = 0;
            }
        };
    }
    static bool ContainGuid(string _serializedFile, string _guid)
    {
        if (string.IsNullOrEmpty(_serializedFile))
        {
            return false;
        }
        else
        {
            var matches = Regex.Matches(_serializedFile, _guid);
            return matches.Count > 2;
        }
    }
    private void StartRecordExtract(string _path)
    {
        using (FileStream fs = new FileStream(StringUtility.Contact(_path, "/logger.txt"), FileMode.Create, FileAccess.Write))
        {
            using (StreamWriter sw = new StreamWriter(fs))
            {
                foreach (var _key in m_ExtractChsDict.Keys)
                {
                    sw.WriteLine(StringUtility.Contact(_key, '\t', m_ExtractChsDict[_key], "\t", m_ExtractSerializedDict[_key]));
                }
            }
        }
    }
    static Regex m_TrimNumberRegex = new Regex(@"\d+$", RegexOptions.Singleline);
    private string GetUnRepetitionKey(string _key)
    {
        if (m_ExtractChsDict.ContainsKey(_key))
        {
            var _index = 0;
            if (m_TrimNumberRegex.IsMatch(_key))
            {
                var _match = m_TrimNumberRegex.Match(_key);
                int.TryParse(_match.Value, out _index);
                _index++;
                _key = m_TrimNumberRegex.Replace(_key, string.Empty);
            }
            _key = StringUtility.Contact(_key, _index);
            _key = GetUnRepetitionKey(_key);
        }
        return _key;
    }
    #endregion
    #region UI风格
    [SerializeField] Color m_ButtonTxtColor = Color.gray;
    private void DisplayUIStyle()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("按钮字色");
        m_ButtonTxtColor = EditorGUILayout.ColorField(m_ButtonTxtColor);
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    #endregion
    private void DisplayPrefabPath()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("预制体路径");
        m_ReplacePrefabPath = GUILayout.TextField(m_ReplacePrefabPath);
        m_LockPrefabPath = GUILayout.Toggle(m_LockPrefabPath, "Lock");
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    private Sprite GetSpriteByAssetPath(string _path)
    {
        return AssetDatabase.LoadAssetAtPath<Sprite>(GetRelativeAssetsPath(_path));
    }
    private string GetRelativeAssetsPath(string _path)
    {
        return "Assets" + Path.GetFullPath(_path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');
    }
    private string GetGUIDByAssets(UnityEngine.Object _object)
    {
        if (_object == null)
        {
            return string.Empty;
        }
        return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(_object));
    }
}
public static class ToolsHelper
{
    [SerializeField] public static string folderPath = string.Empty;
    [SerializeField] public static bool lockFolderPath = false;
    [SerializeField] public static string m_ExternalFilePath = string.Empty;
    public static void DisplayFolderPath()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("文件路径");
        folderPath = GUILayout.TextField(folderPath);
        lockFolderPath = GUILayout.Toggle(lockFolderPath, "Lock");
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    public static string GetRelativeAssetsPath(string _path)
    {
        return "Assets" + Path.GetFullPath(_path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');
    }
    public static string GetGUIDByAssets(UnityEngine.Object _object)
    {
        if (_object == null)
        {
            return string.Empty;
        }
        return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(_object));
    }
    public static void DisplayExternalPath()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label(StringUtility.Contact("文件夹路径:", m_ExternalFilePath));
        if (GUILayout.Button("选择文件根路径"))
        {
            var _path = EditorUtility.OpenFolderPanel("根路径", "", "");
            m_ExternalFilePath = _path;
        }
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
    }
    static string content = string.Empty;
    static Font fontData = null;
    static FontStyle fontStyle;
    static int fontSize = 14;
    static float lineSpacing = 0f;
    static bool richText = true;
    static TextAnchor alignment;
    static HorizontalWrapMode hwmode;
    static VerticalWrapMode vwmode;
    static Color m_Color;
    static Material m_Material;
    static bool raycastTarget;
    public static TextEx PasteText(Text text)
    {
        content = text.text;
        fontData = text.font;
        fontStyle = text.fontStyle;
        fontSize = text.fontSize;
        lineSpacing = text.lineSpacing;
        richText = text.supportRichText;
        alignment = text.alignment;
        hwmode = text.horizontalOverflow;
        vwmode = text.verticalOverflow;
        m_Color = text.color;
        m_Material = text.material;
        raycastTarget = text.raycastTarget;
        var gameObject = text.gameObject;
        Component.DestroyImmediate(text);
        TextEx textex = gameObject.AddMissingComponent<TextEx>();
        textex.text = content;
        textex.font = fontData;
        textex.fontStyle = fontStyle;
        textex.fontSize = fontSize;
        textex.lineSpacing = lineSpacing;
        textex.supportRichText = richText;
        textex.alignment = alignment;
        textex.horizontalOverflow = hwmode;
        textex.verticalOverflow = vwmode;
        textex.color = m_Color;
        textex.material = m_Material;
        textex.raycastTarget = raycastTarget;
        return textex;
    }
}