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 { Reference, } private Vector2 m_ScrollPosition; private Texture2D m_DeleteTexture; private List 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("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; } GUI.skin.button.normal.textColor = Color.gray; switch (m_SpriteManageType) { case SpriteManageType.Reference: DisplayReference(); break; } } private void OnEnable() { InitStyle(); m_SpriteManageType = SpriteManageType.Reference; if (m_FindReference) { m_ReferenceSource = Selection.activeObject; } } private void DisplayFuncToggle() { GUILayout.BeginHorizontal(); string[] labels = new string[1] { "查找引用" }; m_SpriteManageType = (SpriteManageType)GUILayout.Toolbar((int)m_SpriteManageType, labels, "LargeButton", GUILayout.Width(labels.Length * 130)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } #region 引用资源 private UnityEngine.Object m_ReferenceSource; private UnityEngine.Object m_ReferenceReplace; private static string[] m_ReferenceDisplays = new string[] { "Material", "Prefab", "Asset", "Scene" }; private Dictionary m_ReferenceObjectDict = new Dictionary(); private Dictionary m_ReferenceReplaceDict = new Dictionary(); private Dictionary> m_ReferenceDetailDict = new Dictionary>(); private List m_PrefabDetails = new List(); 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 _details = new List(); 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(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 GetReferenceExtention() { var _list = new List(); 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 m_RefDetailDict = new Dictionary(); private void GetReferenceDetail(string _data, string _guid, List _details) { var _strArray = s_PrefabRegex.Split(_data); MatchCollection _matchs = s_PrefabRegex.Matches(_data); List _list = new List(_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 guids = new List(); public Dictionary objectDict = new Dictionary(); 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(_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 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.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; } }