| using vnxbqy.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;  | 
|     }  | 
| }  |