Unity3D查找丢失材质和脚本工具
发表于2017-09-21
在游戏开发中,UI是经常需要变动的,一款游戏从开发到结束,UI至少更换好多版,这就给替换UI的人增加了很多负担,认为的因素很难将旧的UI彻底删除掉,这样就会出现很多冗余的资源,在项目后期要将这些冗余的资源清除掉,如果单靠人工操作难免会出现各种错误,其实我们完全可以通过工具将它们删除掉。下面把删除冗余的工具代码给大家展示如下:copy
- using UnityEngine;
- using UnityEditor;
- using System.IO;
- using System.Linq;
- using System.Text.RegularExpressions;
- using System.Collections.Generic;
- using System.Text;
- using System;
- public static class LinqHelper {
- public static TSource Fold<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func, TSource id)
- {
- TSource r = id;
- foreach (var s in source)
- {
- r = func(r, s);
- }
- return r;
- }
- public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
- {
- foreach (T element in source)
- action(element);
- }
- public static IEnumerable<U> SelectI<U, T>(this IEnumerable<T> source, Func<T, int, U> action)
- {
- int i = 0;
- foreach (var s in source)
- {
- yield return action(s, i);
- i = 1;
- }
- }
- public static TSource Reduce<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func) where TSource : new()
- {
- return Fold<TSource>(source, func, new TSource());
- }
- public static void ForEachI<T>(this IEnumerable<T> source, Action<T, int> action)
- {
- int i = 0;
- foreach (T element in source)
- {
- action(element, i);
- i = 1;
- }
- }
- }
- public static class FindUnUnUsedUITexture
- {
- static List<string> getUUIDsInFile(string path)
- {
- StreamReader file = new StreamReader(path);
- List<string> uuids = new List<string>();
- string line;
- while ((line = file.ReadLine()) != null)
- {
- var reg = new Regex(@"([a-f0-9]{32})");
- var m = reg.Match(line);
- if (m.Success)
- {
- uuids.Add(m.Groups[0].Value);
- }
- }
- file.Close();
- return uuids;
- }
- // Use this for initialization
- [MenuItem("Tools/UI冗余图片扫描")]
- public static void Scan()
- {
- var uiPrefabRootDir = EditorUtility.OpenFolderPanel("选择UIPrefab目录", "Assets","");
- if (string.IsNullOrEmpty(uiPrefabRootDir))
- {
- return;
- }
- var uiPicRootDir = EditorUtility.OpenFolderPanel("选择UIPrefab目录", "Assets", "");
- if (string.IsNullOrEmpty(uiPicRootDir))
- {
- return;
- }
- //find all meta and pic path
- var uuidReg = new Regex(@"guid: ([a-f0-9]{32})");
- var pngs = Directory.GetFiles(uiPicRootDir, "*.meta", SearchOption.AllDirectories)
- .Select(p => "Assets/" p.Replace('\\','/').Substring(Application.dataPath.Length 1))
- .Where(p =>
- {
- return p.EndsWith(".png.meta") || p.EndsWith(".jpg.meta") || p.EndsWith(".tag.meta");
- }).ToList();
- var uuid2path = new Dictionary<string, string>();
- pngs.ForEachI((png, i) =>
- {
- var matcher = uuidReg.Match(File.ReadAllText(png));
- var uuid = matcher.Groups[1].Value;
- if (uuid2path.ContainsKey(uuid))
- {
- Debug.LogError("uuid dup" uuid " \n" png "\n" uuid2path[uuid]);
- }
- else
- {
- uuid2path.Add(uuid, png.Substring(0,png.Length-5));
- }
- EditorUtility.DisplayProgressBar("扫描图片中", png, (float)i / pngs.Count);
- });
- //find all prefab and search pic uuid
- var prefabs = Directory.GetFiles(uiPrefabRootDir, "*.prefab", SearchOption.AllDirectories);
- var anims = Directory.GetFiles("Assets/", "*.anim", SearchOption.AllDirectories).Where(p => !p.Replace('\\', '/').Contains("Characters/"));
- var allFiles = prefabs.Concat(anims).ToList();
- var alluuids = allFiles
- .SelectI((f, i) => {
- EditorUtility.DisplayProgressBar("获取引用关系", f, (float)i / allFiles.Count);
- return getUUIDsInFile(f);
- }).ToList().Aggregate((a, b) => a.Concat(b).ToList()).ToList();
- EditorUtility.ClearProgressBar();
- //rm used pic uuid
- var uuidshashset = new HashSet<string>(alluuids);
- var em = uuidshashset.GetEnumerator();
- while(em.MoveNext())
- {
- var uuid = em.Current;
- uuid2path.Remove(uuid);
- }
- StringBuilder sb = new StringBuilder();
- sb.Append("UnUsedFiles: ");
- sb.Append(uuid2path.Count);
- sb.Append("\n");
- uuid2path.ForEach(kv => sb.Append(kv.Value "\n"));
- File.WriteAllText("Assets/unusedpic.txt", sb.ToString());
- EditorUtility.DisplayDialog("扫描成功", string.Format("共找到{0}个冗余图片\n请在Assets/unsedpic.txt查看结果",uuid2path.Count), "ok");
- }
- }
另外,在游戏中经常出现脚本丢失情况,自己查找非常麻烦,这个也可以通过工具去查找,代码如下所示:
- using System.Linq;
- using UnityEditor;
- using UnityEngine;
- using System.Collections.Generic;
- using System.Text.RegularExpressions;
- using System.IO;
- using System;
- public static class MissingScriptFinder
- {
- private const string MENU_ROOT = "Tool/Missing References/";
- public static string GetHierarchyName(Transform t)
- {
- if (t == null)
- return "";
- var pname = GetHierarchyName(t.parent);
- if (pname != "")
- {
- return pname "/" t.gameObject.name;
- }
- return t.gameObject.name;
- }
- public static TSource Fold<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func,TSource id)
- {
- TSource r = id;
- foreach(var s in source)
- {
- r = func(r,s);
- }
- return r;
- }
- public static void ForEachI<T>(this IEnumerable<T> source, Action<T,int> action)
- {
- int i = 0;
- foreach (T element in source)
- {
- action(element,i);
- i = 1;
- }
- }
- public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
- {
- foreach (T element in source)
- {
- action(element);
- }
- }
- static HashSet<string> findAllScriptUUIDsInAssets()
- {
- var uuids = Directory.GetFiles("Assets/", "*.cs.meta", SearchOption.AllDirectories)
- .Select(p =>
- {
- return File.ReadAllLines(p)[1].Substring(6);
- }).ToList();
- //find dll uuids
- var dlluuids = Directory.GetFiles(EditorApplication.applicationContentsPath, "*.dll", SearchOption.AllDirectories)
- .Select(p =>
- {
- return AssetDatabase.AssetPathToGUID(p.Replace('\\', '/'));
- }).Where(s => s!= "").ToList();
- return new HashSet<string>(uuids.Concat(dlluuids));
- }
- static Regex s_scriptUUIDReg = new Regex(@"m_Script: \{fileID: [0-9] , guid: ([0-9a-f]{32}), type: 3\}");
- static string getScriptUUID(string line)
- {
- var m = s_scriptUUIDReg.Match(line);
- if (m.Success)
- {
- return m.Groups[1].Value;
- }
- if(line.Contains("m_Script: {fileID: 0}")) //missing script
- {
- return "0";
- }
- return null;
- }
- static Dictionary<string,HashSet<string>> findAllPrefabScriptRefInDir(string dir,Action<int> onBeginFinding,Action<int,string,int> onFinding, Action onEndFinding )
- {
- var allPrefabs = Directory.GetFiles(dir, "*.prefab", SearchOption.AllDirectories);
- onBeginFinding(allPrefabs.Length);
- Dictionary<string, HashSet<string>> r = new Dictionary<string, HashSet<string>>();
- for (int i =0;i<allPrefabs.Length; i)
- {
- onFinding(i, allPrefabs[i],allPrefabs.Length);
- File.ReadAllLines(allPrefabs[i]).ForEach(line =>
- {
- string s = getScriptUUID(line);
- if (s != null)
- {
- HashSet<string> files = null;
- r.TryGetValue(s, out files);
- if (files == null)
- {
- files = new HashSet<string>();
- r.Add(s, files);
- }
- files.Add(allPrefabs[i]);
- }
- });
- }
- onEndFinding();
- return r;
- }
- private static void FindMissionRefInGo(GameObject go)
- {
- var components = go.GetComponents<MonoBehaviour>();
- foreach (var c in components)
- {
- // Missing components will be null, we can't find their type, etc.
- if (!c)
- {
- var assetPath = AssetDatabase.GetAssetPath(go);
- if(assetPath != "" && assetPath != null)
- {
- Debug.LogError("missing script: " GetHierarchyName(go.transform) "-->" assetPath);
- }
- else
- {
- Debug.LogError("missing script: " GetHierarchyName(go.transform));
- }
- continue;
- }
- }
- foreach(Transform t in go.transform)
- {
- FindMissionRefInGo(t.gameObject);
- }
- }
- public static IEnumerable<GameObject> SceneRoots()
- {
- var prop = new HierarchyProperty(HierarchyType.GameObjects);
- var expanded = new int[0];
- while (prop.Next(expanded))
- {
- yield return prop.pptrValue as GameObject;
- }
- }
- [MenuItem(MENU_ROOT "search in scene")]
- public static void FindMissingReferencesInCurrentScene()
- {
- var objs = SceneRoots();
- int count = objs.Count();
- objs.ForEachI((prefab, i) =>
- {
- EditorUtility.DisplayProgressBar("check missing prefabs", prefab.ToString(), (float)i / count);
- FindMissionRefInGo(prefab);
- });
- EditorUtility.ClearProgressBar();
- }
- [MenuItem(MENU_ROOT "search in all assets")]
- public static void MissingSpritesInAssets()
- {
- var allScriptsIds = findAllScriptUUIDsInAssets();
- var refScriptIds = findAllPrefabScriptRefInDir("Assets/",
- (count) =>
- {
- EditorUtility.DisplayProgressBar("scanning","",0);
- },
- (idx,file,count) =>
- {
- EditorUtility.DisplayProgressBar("scanning", file, (float) idx/count);
- },
- () =>
- {
- EditorUtility.ClearProgressBar();
- });
- var missingScriptsFiles = refScriptIds
- .Where(kv => !allScriptsIds.Contains(kv.Key))
- .Select(kv => kv.Value)
- .ToList()
- .Fold((a,b)=>new HashSet<string>(a.Concat(b)),new HashSet<string>());
- Debug.LogError("----------------------------------------->\nMissingFiles: " missingScriptsFiles.Count);
- missingScriptsFiles.ForEachI((f, i) =>
- {
- EditorUtility.DisplayProgressBar("check missing prefabs", f, (float)i / missingScriptsFiles.Count);
- var prefab = AssetDatabase.LoadAssetAtPath(f, typeof(GameObject)) as GameObject;
- FindMissionRefInGo(prefab);
- });
- EditorUtility.ClearProgressBar();
- }
- }