New file |
| | |
| | | //------------------------------------------------------------------ |
| | | //本文件中的工具提供在编辑器环境下,快速整理特效相关的资源 |
| | | //------------------------------------------------------------------- |
| | | |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | using UnityEngine; |
| | | using UnityEditor; |
| | | using UnityEngine.UI; |
| | | using System.IO; |
| | | using System; |
| | | using System.Threading; |
| | | using System.Text.RegularExpressions; |
| | | |
| | | public class RemoveUnUsedEffect |
| | | { |
| | | static string uiroot1 = "Assets/ResourcesOut/UI/Window"; |
| | | static string uiroot2 = "Assets/ResourcesOut/UI/PriorityWindow"; |
| | | static string uiroot3 = "Assets/ResourcesOut/UI/Prefab"; |
| | | static string mobroot = "Assets/ResourcesOut/UI/Prefab"; |
| | | static string builtinroot = "Assets/ResourcesOut/BuiltIn/Prefabs"; |
| | | |
| | | static string effectroot = "Assets/ResourcesOut/Effect"; |
| | | |
| | | static List<string> prefabTexts = new List<string>(); |
| | | |
| | | static Dictionary<string, GameObject> processObjects = new Dictionary<string, GameObject>(); |
| | | static List<AnalyzeTask> tasks = new List<AnalyzeTask>(); |
| | | |
| | | static int taskCount = 1; |
| | | static int completedTaskCount = 0; |
| | | static List<EffectConfig> configs; |
| | | |
| | | [MenuItem("程序/Effect Assets/移除无用的特效")] |
| | | public static void RemoveUnUsedEffects() |
| | | { |
| | | try |
| | | { |
| | | EditorApplication.update += OnUpdate; |
| | | EffectConfig.Init(true); |
| | | configs = EffectConfig.GetValues(); |
| | | |
| | | LoadPrefabTexts(); |
| | | FindEffects(); |
| | | |
| | | taskCount = 0; |
| | | completedTaskCount = 0; |
| | | foreach (var task in tasks) |
| | | { |
| | | task.total = task.effects.Count; |
| | | taskCount += task.total; |
| | | } |
| | | |
| | | Analyze(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | EditorApplication.update -= OnUpdate; |
| | | EditorUtility.ClearProgressBar(); |
| | | } |
| | | } |
| | | |
| | | static void LoadPrefabTexts() |
| | | { |
| | | var guids = new List<string>(); |
| | | guids.AddRange(AssetDatabase.FindAssets("t:prefab", new string[] { uiroot1 })); |
| | | guids.AddRange(AssetDatabase.FindAssets("t:prefab", new string[] { uiroot2 })); |
| | | guids.AddRange(AssetDatabase.FindAssets("t:prefab", new string[] { uiroot3 })); |
| | | guids.AddRange(AssetDatabase.FindAssets("t:prefab", new string[] { mobroot })); |
| | | guids.AddRange(AssetDatabase.FindAssets("t:prefab", new string[] { builtinroot })); |
| | | |
| | | var assetPaths = new List<string>(); |
| | | foreach (var item in guids) |
| | | { |
| | | assetPaths.Add(AssetDatabase.GUIDToAssetPath(item)); |
| | | } |
| | | |
| | | var count = 0; |
| | | prefabTexts.Clear(); |
| | | foreach (var path in assetPaths) |
| | | { |
| | | count++; |
| | | EditorUtility.DisplayProgressBar("读取预置体", "正在读取预置体文本", (float)count / assetPaths.Count); |
| | | prefabTexts.Add(File.ReadAllText(Application.dataPath + path.Substring(6, path.Length - 6))); |
| | | } |
| | | |
| | | EditorUtility.ClearProgressBar(); |
| | | } |
| | | |
| | | static void FindEffects() |
| | | { |
| | | processObjects.Clear(); |
| | | tasks.Clear(); |
| | | |
| | | var effects = new List<GameObject>(); |
| | | var guids = new List<string>(); |
| | | var subFolders = AssetDatabase.GetSubFolders(effectroot); |
| | | foreach (var folder in subFolders) |
| | | { |
| | | guids.AddRange(AssetDatabase.FindAssets("t:prefab", new string[] { folder })); |
| | | } |
| | | |
| | | foreach (var guid in guids) |
| | | { |
| | | effects.Add(AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(guid))); |
| | | } |
| | | |
| | | var count = 0; |
| | | var task = new AnalyzeTask(); |
| | | tasks.Add(task); |
| | | foreach (var asset in effects) |
| | | { |
| | | var path = AssetDatabase.GetAssetPath(asset); |
| | | var guid = AssetDatabase.AssetPathToGUID(path); |
| | | processObjects[guid] = asset; |
| | | |
| | | var folderName = Path.GetDirectoryName(path).Split('/').GetLast(); |
| | | task.Add(new EffectInfo() |
| | | { |
| | | name = asset.name, |
| | | guid = guid, |
| | | folder = folderName |
| | | }); |
| | | |
| | | count++; |
| | | EditorUtility.DisplayProgressBar("获取特效", "正在获取特效预置体", (float)count / effects.Count); |
| | | if (count >= 20) |
| | | { |
| | | count = 0; |
| | | task = new AnalyzeTask(); |
| | | tasks.Add(task); |
| | | } |
| | | } |
| | | |
| | | EditorUtility.ClearProgressBar(); |
| | | |
| | | } |
| | | |
| | | static void Analyze() |
| | | { |
| | | foreach (var task in tasks) |
| | | { |
| | | ThreadPool.QueueUserWorkItem(x => |
| | | { |
| | | for (int i = 0; i < task.effects.Count; i++) |
| | | { |
| | | task.completed++; |
| | | var info = task.effects[i]; |
| | | if (ContainByIconTable(info)) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (RefrenceByPrefab(info)) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | info.unUsed = true; |
| | | task.effects[i] = info; |
| | | } |
| | | |
| | | task.done = true; |
| | | }); |
| | | } |
| | | } |
| | | |
| | | static void ProcessUnUsedEffects() |
| | | { |
| | | var total = 0; |
| | | foreach (var task in tasks) |
| | | { |
| | | foreach (var effect in task.effects) |
| | | { |
| | | if (effect.unUsed) |
| | | { |
| | | Debug.LogFormat("找到一个无用的Effect:文件夹->{0};特效名称->{1}", effect.folder, effect.name); |
| | | total++; |
| | | } |
| | | } |
| | | } |
| | | |
| | | var count = 0; |
| | | foreach (var task in tasks) |
| | | { |
| | | foreach (var sprite in task.effects) |
| | | { |
| | | if (sprite.unUsed) |
| | | { |
| | | EditorUtility.DisplayProgressBar("删除Effect", string.Format("正在删除第{0}个特效,共{1}个", count + 1, total), (float)count / total); |
| | | count++; |
| | | AssetDatabase.DeleteAsset(AssetDatabase.GUIDToAssetPath(sprite.guid)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | EditorUtility.ClearProgressBar(); |
| | | } |
| | | |
| | | static bool ContainByIconTable(EffectInfo info) |
| | | { |
| | | return configs.FindIndex(x => { return x.packageName.ToLower() == info.folder.ToLower() && x.fxName == info.name; }) != -1; |
| | | } |
| | | |
| | | static bool RefrenceByPrefab(EffectInfo info) |
| | | { |
| | | foreach (var content in prefabTexts) |
| | | { |
| | | if (Regex.IsMatch(content, info.guid)) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | static void OnUpdate() |
| | | { |
| | | var done = true; |
| | | completedTaskCount = 0; |
| | | foreach (var task in tasks) |
| | | { |
| | | completedTaskCount += task.completed; |
| | | if (!task.done) |
| | | { |
| | | done = false; |
| | | } |
| | | } |
| | | |
| | | EditorUtility.DisplayProgressBar("分析无用Effect", |
| | | string.Format("正在分析第{0}个Effect,共计{1}个", completedTaskCount + 1, taskCount), |
| | | (float)completedTaskCount / taskCount); |
| | | |
| | | if (done) |
| | | { |
| | | EditorUtility.ClearProgressBar(); |
| | | ProcessUnUsedEffects(); |
| | | EditorApplication.update -= OnUpdate; |
| | | } |
| | | } |
| | | |
| | | struct EffectInfo |
| | | { |
| | | public string guid; |
| | | public string name; |
| | | public string folder; |
| | | public bool unUsed; |
| | | } |
| | | |
| | | class AnalyzeTask |
| | | { |
| | | public int total; |
| | | public int completed; |
| | | public bool done; |
| | | public List<EffectInfo> effects; |
| | | |
| | | public AnalyzeTask() |
| | | { |
| | | effects = new List<EffectInfo>(); |
| | | } |
| | | |
| | | public void Add(EffectInfo info) |
| | | { |
| | | effects.Add(info); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | public class RemoveUnUsedEffectKey |
| | | { |
| | | static string uiroot1 = "Assets/ResourcesOut/UI/Window"; |
| | | static string uiroot2 = "Assets/ResourcesOut/UI/PriorityWindow"; |
| | | static string uiroot3 = "Assets/ResourcesOut/UI/Prefab"; |
| | | |
| | | static int taskCount = 1; |
| | | static int completedTaskCount = 0; |
| | | static Dictionary<string, List<string>> iconKeyMap = new Dictionary<string, List<string>>(); |
| | | |
| | | static List<UIEffect> uieffects = new List<UIEffect>(); |
| | | static List<Column> iconKeyRefrences = new List<Column>(); |
| | | static List<string> csharpFileContents = new List<string>(); |
| | | static List<AnalyzeTask> tasks = new List<AnalyzeTask>(); |
| | | |
| | | [MenuItem("程序/Effect Assets/移除无用的EffectKey")] |
| | | public static void Remove() |
| | | { |
| | | tasks.Clear(); |
| | | var effectKeys = GetOriginalEffectKeys(); |
| | | |
| | | taskCount = effectKeys.Count; |
| | | completedTaskCount = 0; |
| | | |
| | | var count = 0; |
| | | var task = new AnalyzeTask(); |
| | | tasks.Add(task); |
| | | foreach (var keyInfo in effectKeys) |
| | | { |
| | | task.Add(keyInfo); |
| | | if (count >= 100) |
| | | { |
| | | count = 0; |
| | | task = new AnalyzeTask(); |
| | | tasks.Add(task); |
| | | } |
| | | count++; |
| | | } |
| | | |
| | | iconKeyMap = GetEffectKeyMap(); |
| | | iconKeyRefrences = GetAllEffectKeyRefrences(); |
| | | csharpFileContents = GetAllCSharpFileContents(); |
| | | uieffects = GetEffectComponents(); |
| | | |
| | | try |
| | | { |
| | | EditorApplication.update += OnUpdate; |
| | | Analyze(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | EditorUtility.ClearProgressBar(); |
| | | EditorApplication.update -= OnUpdate; |
| | | Debug.Log(e); |
| | | } |
| | | |
| | | } |
| | | |
| | | static void Analyze() |
| | | { |
| | | foreach (var task in tasks) |
| | | { |
| | | ThreadPool.QueueUserWorkItem(x => |
| | | { |
| | | for (int i = 0; i < task.effectKeys.Count; i++) |
| | | { |
| | | task.completed++; |
| | | var info = task.effectKeys[i]; |
| | | if (info.folder.ToLower() == "cj") |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (ContainByTables(info.key, ref iconKeyRefrences)) |
| | | { |
| | | Debug.LogFormat("找到一个被其他配置配件引用的 effect key:{0}", info.key); |
| | | continue; |
| | | } |
| | | |
| | | if (ContainByCSharpFile(info.key, ref csharpFileContents)) |
| | | { |
| | | Debug.LogFormat("找到一个写在C#文件中的 effect key:{0}", info.key); |
| | | continue; |
| | | } |
| | | |
| | | if (ContainByPrefab(info.key, ref uieffects)) |
| | | { |
| | | Debug.LogFormat("找到一个被prefab依赖的 effect key:{0}", info.key); |
| | | continue; |
| | | } |
| | | |
| | | info.unused = true; |
| | | task.effectKeys[i] = info; |
| | | } |
| | | |
| | | task.done = true; |
| | | }); |
| | | } |
| | | } |
| | | |
| | | static void ProcessUnUsedEffectKeys() |
| | | { |
| | | var lines = new List<string>(File.ReadAllLines(Application.dataPath + "/ResourcesOut/Refdata/Config/Effect.txt")); |
| | | var deleteLines = new List<string>(); |
| | | var unUsedEffectKeys = new List<string>(); |
| | | foreach (var task in tasks) |
| | | { |
| | | foreach (var iconkey in task.effectKeys) |
| | | { |
| | | if (iconkey.unused) |
| | | { |
| | | unUsedEffectKeys.Add(iconkey.key); |
| | | } |
| | | } |
| | | } |
| | | |
| | | for (int i = lines.Count - 1; i >= 3; i--) |
| | | { |
| | | var contents = lines[i].Split('\t'); |
| | | if (!contents.IsNullOrEmpty()) |
| | | { |
| | | if (unUsedEffectKeys.Contains(contents[0])) |
| | | { |
| | | deleteLines.Add(lines[i]); |
| | | lines.RemoveAt(i); |
| | | } |
| | | } |
| | | } |
| | | |
| | | File.WriteAllLines(Application.dataPath + "/删除的Effect表配置.txt", deleteLines.ToArray()); |
| | | File.WriteAllLines(Application.dataPath + "/ResourcesOut/Refdata/Config/Effect.txt", lines.ToArray()); |
| | | } |
| | | |
| | | static Dictionary<string, List<string>> GetEffectKeyMap() |
| | | { |
| | | var lines = File.ReadAllLines(Application.dataPath + "/Editor/Config/TxtEffectKey.txt"); |
| | | var map = new Dictionary<string, List<string>>(); |
| | | |
| | | for (int i = 1; i < lines.Length; i++) |
| | | { |
| | | var line = lines[i]; |
| | | var contents = new List<string>(line.Split('\t')); |
| | | if (!contents.IsNullOrEmpty() && contents.Count >= 2) |
| | | { |
| | | var fields = map[contents[0]] = new List<string>(); |
| | | fields.AddRange(contents.GetRange(1, contents.Count - 1)); |
| | | } |
| | | } |
| | | |
| | | return map; |
| | | } |
| | | |
| | | static List<EffectKeyInfo> GetOriginalEffectKeys() |
| | | { |
| | | var lines = File.ReadAllLines(Application.dataPath + "/ResourcesOut/Refdata/Config/Effect.txt"); |
| | | var effectKeys = new List<EffectKeyInfo>(); |
| | | for (int i = 3; i < lines.Length; i++) |
| | | { |
| | | var contents = lines[i].Split('\t'); |
| | | if (!contents.IsNullOrEmpty()) |
| | | { |
| | | effectKeys.Add(new EffectKeyInfo() { key = contents[0], folder = contents[1] }); |
| | | } |
| | | } |
| | | |
| | | return effectKeys; |
| | | } |
| | | |
| | | static List<Column> GetAllEffectKeyRefrences() |
| | | { |
| | | var files = FileExtersion.GetFileInfos(Application.dataPath + "/ResourcesOut/Refdata/Config", new string[] { "*.txt", "*.TXT" }); |
| | | |
| | | var columns = new List<Column>(); |
| | | foreach (var file in files) |
| | | { |
| | | var nameWithoutExtension = Path.GetFileNameWithoutExtension(file.FullName); |
| | | if (!iconKeyMap.ContainsKey(nameWithoutExtension)) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | var lines = File.ReadAllLines(file.FullName); |
| | | var fields0 = new List<string>(lines[0].Split('\t')); |
| | | var fields1 = new List<string>(lines[1].Split('\t')); |
| | | var refrences = iconKeyMap[nameWithoutExtension]; |
| | | foreach (var refrence in refrences) |
| | | { |
| | | var name = string.Empty; |
| | | var index = fields0.IndexOf(refrence); |
| | | if (index != -1) |
| | | { |
| | | name = fields0[index]; |
| | | } |
| | | else |
| | | { |
| | | index = fields1.IndexOf(refrence); |
| | | if (index != -1) |
| | | { |
| | | name = fields1[index]; |
| | | } |
| | | } |
| | | |
| | | if (index == -1) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | var column = new Column() |
| | | { |
| | | name = name, |
| | | values = new List<string>() |
| | | }; |
| | | |
| | | columns.Add(column); |
| | | for (int i = 1; i < lines.Length; i++) |
| | | { |
| | | var line = lines[i]; |
| | | var contents = line.Split('\t'); |
| | | column.values.Add(contents[index]); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | return columns; |
| | | } |
| | | |
| | | static List<string> GetAllCSharpFileContents() |
| | | { |
| | | var files = FileExtersion.GetFileInfos(Application.dataPath + "/Scripts", new string[] { "*.cs" }); |
| | | var contents = new List<string>(); |
| | | |
| | | var count = 0; |
| | | foreach (var file in files) |
| | | { |
| | | count++; |
| | | EditorUtility.DisplayProgressBar("读取代码文件", "正在读取代码文件", (float)count / files.Count); |
| | | contents.Add(File.ReadAllText(file.FullName)); |
| | | } |
| | | |
| | | EditorUtility.ClearProgressBar(); |
| | | return contents; |
| | | } |
| | | |
| | | static List<UIEffect> GetEffectComponents() |
| | | { |
| | | var guids = new List<string>(); |
| | | guids.AddRange(AssetDatabase.FindAssets("t:prefab", new string[] { uiroot1 })); |
| | | guids.AddRange(AssetDatabase.FindAssets("t:prefab", new string[] { uiroot2 })); |
| | | guids.AddRange(AssetDatabase.FindAssets("t:prefab", new string[] { uiroot3 })); |
| | | |
| | | var assetPaths = new List<string>(); |
| | | foreach (var item in guids) |
| | | { |
| | | assetPaths.Add(AssetDatabase.GUIDToAssetPath(item)); |
| | | } |
| | | |
| | | var count = 0; |
| | | var uieffects = new List<UIEffect>(); |
| | | foreach (var path in assetPaths) |
| | | { |
| | | count++; |
| | | EditorUtility.DisplayProgressBar("收集UIEffect", "正在搜索Prefab上的UIEffect", (float)count / assetPaths.Count); |
| | | var gameObject = AssetDatabase.LoadAssetAtPath<GameObject>(path); |
| | | if (gameObject == null) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | var components = gameObject.GetComponentsInChildren<UIEffect>(true); |
| | | if (!components.IsNullOrEmpty()) |
| | | { |
| | | uieffects.AddRange(components); |
| | | } |
| | | } |
| | | |
| | | EditorUtility.ClearProgressBar(); |
| | | return uieffects; |
| | | } |
| | | |
| | | static bool ContainByTables(string key, ref List<Column> columns) |
| | | { |
| | | foreach (var column in columns) |
| | | { |
| | | foreach (var value in column.values) |
| | | { |
| | | if (Regex.IsMatch(value, key)) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | static bool ContainByCSharpFile(string key, ref List<string> csharpContents) |
| | | { |
| | | var pattern1 = string.Format(@"SFXPlayUtility.Instance.PlayBattleEffect.*{0}.*\);", key); |
| | | var pattern2 = string.Format(@"SFXPlayUtility.Instance.PlayEffectAsync.*{0}.*\);", key); |
| | | |
| | | foreach (var content in csharpContents) |
| | | { |
| | | if (Regex.IsMatch(content, pattern1)) |
| | | { |
| | | return true; |
| | | } |
| | | |
| | | if (Regex.IsMatch(content, pattern2)) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | static bool ContainByPrefab(string key, ref List<UIEffect> uieffects) |
| | | { |
| | | foreach (var uieffect in uieffects) |
| | | { |
| | | if (uieffect.effect.ToString() == key) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | static void OnUpdate() |
| | | { |
| | | var done = true; |
| | | completedTaskCount = 0; |
| | | foreach (var task in tasks) |
| | | { |
| | | completedTaskCount += task.completed; |
| | | if (!task.done) |
| | | { |
| | | done = false; |
| | | } |
| | | } |
| | | |
| | | EditorUtility.DisplayProgressBar("分析无用EffectKey", |
| | | string.Format("正在分析第{0}个EffectKey,共计{1}个", completedTaskCount + 1, taskCount), |
| | | (float)completedTaskCount / taskCount); |
| | | |
| | | if (done) |
| | | { |
| | | EditorUtility.ClearProgressBar(); |
| | | ProcessUnUsedEffectKeys(); |
| | | EditorApplication.update -= OnUpdate; |
| | | } |
| | | } |
| | | |
| | | struct Column |
| | | { |
| | | public string name; |
| | | public List<string> values; |
| | | } |
| | | |
| | | struct EffectKeyInfo |
| | | { |
| | | public string key; |
| | | public string folder; |
| | | public bool unused; |
| | | } |
| | | |
| | | class AnalyzeTask |
| | | { |
| | | public int total; |
| | | public int completed; |
| | | public bool done; |
| | | public List<EffectKeyInfo> effectKeys; |
| | | |
| | | public AnalyzeTask() |
| | | { |
| | | effectKeys = new List<EffectKeyInfo>(); |
| | | } |
| | | |
| | | public void Add(EffectKeyInfo key) |
| | | { |
| | | effectKeys.Add(key); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |