| | |
| | | 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;
|
| | | }
|
| | | }
|