using UnityEngine; using UnityEditor; using System.IO; using System.Collections.Generic; using System.Text; using Thousandto.Editor.Excel; public class CheckInvalidAtlasSpriteEditor : EditorWindow { [MenuItem("Ares/检查Atlas上无用的Sprite")] static void DoIt() { var win = (CheckInvalidAtlasSpriteEditor)EditorWindow.GetWindow(typeof(CheckInvalidAtlasSpriteEditor)); win.Show(); } private string _prefabPath = string.Empty; private Dictionary> allAtlsInfo = new Dictionary>(); private Vector2 _scrollPos = Vector2.zero; void OnGUI() { EditorGUILayout.BeginVertical(); EditorGUILayout.LabelField("选择路径"); EditorGUILayout.Space(); EditorGUILayout.LabelField("需要检测的UIForm路径"); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("浏览", GUILayout.Width(100))) { _prefabPath = EditorUtility.OpenFolderPanel("Check UIForm Prefab Path", _prefabPath, ""); } if (string.IsNullOrEmpty(_prefabPath)) { EditorGUILayout.LabelField("null..."); } else { EditorGUILayout.LabelField(_prefabPath); } EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); if (GUILayout.Button("检测并导出", GUILayout.Width(100))) { if (string.IsNullOrEmpty(_prefabPath)) return; if (Directory.Exists(_prefabPath)) { string excelPath = EditorUtility.SaveFilePanel("Export Excel", "", "InvalidAtlasSprite", "xlsx"); if (string.IsNullOrEmpty(excelPath)) return; allAtlsInfo.Clear(); DirectoryInfo direction = new DirectoryInfo(_prefabPath); FileInfo[] files = direction.GetFiles("*.prefab", SearchOption.AllDirectories); for (int i = 0; i < files.Length; ++i) { var path = files[i].FullName.Replace('\\', '/'); var starIndex = path.IndexOf("/Assets/", 0); path = path.Remove(0, starIndex + 1); var go = AssetDatabase.LoadAssetAtPath(path); if (go != null) { var sprites = go.GetComponentsInChildren(true); for (int j = 0; j < sprites.Length; ++j) { if (sprites[j].atlas != null) { var atlasName = sprites[j].atlas.name; var cIndex = atlasName.LastIndexOf("/"); if (cIndex >= 0) { atlasName = atlasName.Remove(0, cIndex + 1); } if(!atlasName.StartsWith("UIIconAtlas") && !atlasName.StartsWith("UIExpressionAtlas")) { List sprNameList = null; if (!allAtlsInfo.TryGetValue(atlasName, out sprNameList)) { //读取所有sprite信息 var sprList = sprites[j].atlas.spriteList; sprNameList = new List(sprList.Count); for (int k = 0; k < sprList.Count; ++k) { sprNameList.Add(sprList[k].name); } allAtlsInfo.Add(atlasName, sprNameList); } sprNameList.Remove(sprites[j].spriteName); } } } } } //查找cs代码和lua代码 var starIndex2 = _prefabPath.IndexOf("/Assets/", 0); var csCodePath = _prefabPath.Remove(starIndex2); csCodePath = csCodePath + "/Assets/GameAssets/Resources/GameUI/Form"; var luaCodePath = _prefabPath.Remove(starIndex2); luaCodePath = luaCodePath + "/Assets/GameAssets/Resources/Lua/UI/Forms"; var strDefPath = _prefabPath.Remove(starIndex2); strDefPath = strDefPath + "/Assets/GameAssets/Resources/Lua/Config/Data/StringDefines.lua"; List codeTexts = new List(64); codeTexts.Add(File.ReadAllText(strDefPath)); if (Directory.Exists(csCodePath)) { DirectoryInfo csdirection = new DirectoryInfo(csCodePath); FileInfo[] csFiles = csdirection.GetFiles("*.cs", SearchOption.AllDirectories); for (int j = 0; j < csFiles.Length; ++j) { codeTexts.Add(File.ReadAllText(csFiles[j].FullName)); } } if (Directory.Exists(luaCodePath)) { DirectoryInfo luadirection = new DirectoryInfo(luaCodePath); FileInfo[] luaFiles = luadirection.GetFiles("*.lua", SearchOption.AllDirectories); for (int j = 0; j < luaFiles.Length; ++j) { codeTexts.Add(File.ReadAllText(luaFiles[j].FullName)); } } int rowCount = 0; { var iter = allAtlsInfo.GetEnumerator(); try { while (iter.MoveNext()) { ++rowCount; for (int i = iter.Current.Value.Count - 1; i >= 0; --i) { if (IsUsedSprite(iter.Current.Value[i], codeTexts)) { iter.Current.Value.RemoveAt(i); } } rowCount += iter.Current.Value.Count; } } finally { iter.Dispose(); } } { NormalExcelInfo excelInfo = new NormalExcelInfo(); excelInfo.Name = "InvalidAtlasSprite"; excelInfo.Values = new string[rowCount, 2]; var iter = allAtlsInfo.GetEnumerator(); int curRow = 0; while (iter.MoveNext()) { excelInfo.Values[curRow++, 0] = iter.Current.Key; for (int i = 0; i < iter.Current.Value.Count; ++i) { excelInfo.Values[curRow++, 1] = iter.Current.Value[i]; } } ExcelWriter.Write(excelPath, excelInfo); } } } //_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); //{ // var iter = allAtlsInfo.GetEnumerator(); // try // { // while (iter.MoveNext()) // { // GUI.color = Color.red; // EditorGUILayout.LabelField(iter.Current.Key); // GUI.color = Color.white; // for (int i = 0; i < iter.Current.Value.Count; ++i) // { // EditorGUILayout.BeginHorizontal(); // GUILayout.Space(30); // EditorGUILayout.TextField(iter.Current.Value[i]); // EditorGUILayout.EndHorizontal(); // } // } // } // finally // { // iter.Dispose(); // } //} //EditorGUILayout.EndScrollView(); } private bool IsUsedSprite(string name, List codeText) { if (name.StartsWith("bag_back_")) return true; string number = string.Empty; bool findNumber = false; for (int i = 0; i < name.Length; ++i) { if (name[i] >= '0' && name[i] <= '9') { number += name[i]; findNumber = true; } else if (findNumber) { break; } } var findText1 = "\"" + name + "\""; var findText2 = string.Empty; var findText3 = string.Empty; if (!string.IsNullOrEmpty(number)) { findText2 = "\"" + name.Replace(number, "{0}") + "\""; findText3 = "\"" + name.Replace(number, "%d") + "\""; } //需要检测是否代码有调用 bool isFind = false; for (int k = 0; k < codeText.Count; ++k) { if (codeText[k].IndexOf(findText1) >= 0) { isFind = true; break; } if (!string.IsNullOrEmpty(findText2) && codeText[k].IndexOf(findText2) >= 0) { isFind = true; break; } if (!string.IsNullOrEmpty(findText3) && codeText[k].IndexOf(findText3) >= 0) { isFind = true; break; } } return isFind; } }