少年修仙传客户端基础资源
client_Wu Xijin
2019-04-16 afd53f6b3c0583e74c783c7c0653aa7d0588b1b9
6519 【工具】【2.0】删除无用KYE的工具
1个文件已修改
2个文件已添加
688 ■■■■■ 已修改文件
Assets/Editor/Tool/EffectAssetCheck.cs 659 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/EffectAssetCheck.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/UIAssetCheck.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/EffectAssetCheck.cs
New file
@@ -0,0 +1,659 @@
//------------------------------------------------------------------
//本文件中的工具提供在编辑器环境下,快速整理特效相关的资源
//-------------------------------------------------------------------
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);
        }
    }
}
Assets/Editor/Tool/EffectAssetCheck.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6084c3e1e032eb547bb56eb8a745d4bd
timeCreated: 1555386504
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/Tool/UIAssetCheck.cs
@@ -496,6 +496,7 @@
    static void ProcessUnUsedIconKeys()
    {
        var lines = new List<string>(File.ReadAllLines(Application.dataPath + "/ResourcesOut/Refdata/Config/Icon.txt"));
        var deleteLines = new List<string>();
        var unUsedIconKeys = new List<string>();
        foreach (var task in tasks)
        {
@@ -515,11 +516,13 @@
            {
                if (unUsedIconKeys.Contains(contents[0]))
                {
                    deleteLines.Add(lines[i]);
                    lines.RemoveAt(i);
                }
            }
        }
        File.WriteAllLines(Application.dataPath + "/删除的Icon表配置.txt", deleteLines.ToArray());
        File.WriteAllLines(Application.dataPath + "/ResourcesOut/Refdata/Config/Icon.txt", lines.ToArray());
    }
@@ -562,9 +565,13 @@
    {
        var files = FileExtersion.GetFileInfos(Application.dataPath + "/ResourcesOut/Refdata/Config", new string[] { "*.txt", "*.TXT" });
        var count = 0;
        var columns = new List<Column>();
        foreach (var file in files)
        {
            count++;
            EditorUtility.DisplayProgressBar("解析配置文件", "正在解析配置文件", (float)count / files.Count);
            var nameWithoutExtension = Path.GetFileNameWithoutExtension(file.FullName);
            if (!iconKeyMap.ContainsKey(nameWithoutExtension))
            {
@@ -614,6 +621,7 @@
        }
        EditorUtility.ClearProgressBar();
        return columns;
    }
@@ -622,10 +630,15 @@
        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;
    }
@@ -643,12 +656,16 @@
            assetPaths.Add(AssetDatabase.GUIDToAssetPath(item));
        }
        var count = 0;
        prefabTexts = new List<string>();
        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();
        return prefabTexts;
    }