Unity3D查找丢失材质和脚本工具
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。
CSDN视频网址:http://edu.csdn.net/lecturer/144
在游戏开发中,UI是经常需要变动的,一款游戏从开发到结束,UI至少更换好多版,这就给替换UI的人增加了很多负担,认为的因素很难将旧的UI彻底删除掉,这样就会出现很多冗余的资源,在项目后期要将这些冗余的资源清除掉,如果单靠人工操作难免会出现各种错误,其实我们完全可以通过工具将它们删除掉。下面把删除冗余的工具代码给读者展示如下:
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"); } }
将该脚本放置到Editor文件夹下面,然后在Tool菜单下点击UI冗余图片扫描就会弹出窗口将冗余的UI图片列出来,非常方便。
另外,在游戏中经常出现脚本丢失情况,自己查找非常麻烦,这个也可以通过工具去查找,代码如下所示:
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(); } }
同样需要将该脚本放置到Editor文件夹下面,点击菜单栏中的Tool/Missing Reference 即可实现丢失脚本的查找,它可以分成多个部分查找,自己可以去测试一下。
Unity3D查找丢失材质和脚本工具的更多相关文章
- 4.3.6 对象的界定通过编写接口来访问带这类命名结构的表会出问题。如前所述,SQL Server的灵活性不应用作编写错误代码或创建问题对象的借口。 注意在使用Management Studio的脚本工具时,SQL Server会界定所有的对象。这不是因为这么做是必须的,也不是编写代码的最佳方式,而是因为在界定符中封装所有的对象,比编写脚本引擎来查找需要界定的对象更容易。
如前所述,在创建对象时,最好避免使用内嵌的空格或保留字作为对象名,但设计人员可能并没有遵守这个最佳实践原则.例如,我当前使用的数据库中有一个审核表名为Transaction,但是Transaction ...
- [Unity3D] 5.0 图集合并扩展工具,用于解决UGUI与AssetBundle打包造成资源包过大的问题
[Unity3D] 5.0 图集合并扩展工具,用于解决UGUI与AssetBundle打包造成资源包过大的问题 2017年07月05日 15:57:44 阅读数:1494 http://www.cpp ...
- java性能问题排查提效脚本工具
在性能测试过程中,往往会出现各种各样的性能瓶颈.其中java常见瓶颈故障模型有cpu资源瓶颈:文件IO瓶颈:网络IO瓶颈:内存资源瓶颈:资源消耗不高程序本身执行慢等场景模型. 如何快速定位分析这些类型 ...
- unity3d 特殊文件夹和脚本编译顺序
unity3d 特殊文件夹和脚本编译顺序 转自http://blog.csdn.net/u010019717/article/details/40474631 大多数情况下,您可以选择任何你喜欢的文件 ...
- ArcGIS使用Python脚本工具
在Pyhton写的一些代码,用户交互不方便,用户体验比较差,不方便重用.在ArcGIS中可以将用写的Python代码导入到ToolBox中,这样用起来就比较方便了.这里用按要素裁剪栅格的Python来 ...
- ArcMap自定义脚本工具制作
原文 ArcMap自定义脚本工具制作 在制图的前期,一般需要做一些数据的整理,如图层合并.裁剪等工作.虽然在ArcMap中也有提供对应的工具,但使用起来需要点技巧.如批量裁剪,虽然可以实现,但出来的结 ...
- 自动脚本工具新版 v2.0
自动脚本工具 下载 下载工具后,解压,直接双击 "execute.bat" 文件后(前提已配置好 jdk 1.7 的环境),会生成文件夹 "output",该文 ...
- axf、elf文件转换成bin、hex脚本工具
在嵌入式开发过程中常常遇到将axf或elf文件转换成bin的情况,大家都知道通过gnu toolchain中的objcopy和keil中的fromelf能做到.可是为了这么一个小事而记住复杂的选项以及 ...
- REDGATE又一好用的脚本工具ScriptsManager1.3
原文:REDGATE又一好用的脚本工具ScriptsManager1.3 REDGATE又一好用的脚本工具ScriptsManager1.3 先说明一下:这个工具是免费的 下载地址:http://ww ...
随机推荐
- 20145335《java程序设计》第10周学习总结
20145335郝昊 <Java程序设计>第10周学习总结 教材学习内容总结 网络编程 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.程序员所作的事情就是把数据发送到指定的 ...
- CentOS安装wkhtmltopdf及解决中文支持问题
安装wkhtmltopdf,先下载 wkhtmltox-0.12.2.1_linux-centos6-amd64.rpm yum install -y wkhtmltox-0.12.2.1_linu ...
- excel表中同一列相同内容进行合并
如下图所示一张表格,如果想要把表格中相同考号的信息合并来查看的话,首先我们先通过表格的排序功能,把相同的内容先排列在一起.在数据选项卡下找到排序点就可以. 第二步,选中整个数据区域,在数据选项卡下 ...
- 爬虫框架Scrapy之Item Pipeline
Item Pipeline 当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item. 每个Item Pipeline ...
- .net知识点汇总
死锁的必要条件?怎么克服? 答:系统的资源不足,进程的推进的顺序不合适,资源分配不当,一个资源每次只能被一个进程使用,一个资源请求资源时,而此时这个资源已阻塞,对已获得资源不放,进程获得资源时,未使用 ...
- jenkins+gradle打包android遇到的坑
1.gradle与gradlew的选择 配置project,我们选择gradle进行打包.会看到如下图配置项.然而很多网上教程中给出的选择是第一项.只能这么说,如果你是新建一个androidDemo, ...
- javaScript实现点击按钮直接打印
很多网站都有此功能,当浏览到底部时都会有一个打印按钮,点击打印按钮就可以完成打印功能,功能非常不错,人性化,代码非常的简单. 一.只要调用window.print()函数就可以实现打印当前页面 < ...
- Java 最常见的 200+ 面试题:面试必备
这份面试题,包含的内容了十九了模块:Java 基础.容器.多线程.反射.对象拷贝.Java Web 模块.异常.网络.设计模式.Spring/Spring MVC.Spring Boot/Spring ...
- mysql外键理解
一个班级的学生个人信息表: 什么是外键 在设计的时候,就给表1加入一个外键,这个外键就是表2中的学号字段,那么这样表1就是主表,表2就是子表. 外键用来干什么 为了一张表记录的数据不要太过冗余. 这和 ...
- HTML DOM(二):节点的增删改查
上一篇讲述了DOM的基本知识,从其得知,在DOM眼中,HTML的每个成分都可以看作是节点(文档节点.元素节点.文本节点.属性节点.注释节点,其中,属性节点是属于元素节点),本篇的内容就是通过DOM对这 ...