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 ...
随机推荐
- 20144303 《Java程序设计》第六周学习总结
20144303 <Java程序设计>第六周学习总结 教材学习内容总结 第十章输入和输出 Java是以串流(Stream)的方式来处理输入与输出. 串流是一种抽象观念,从键盘输入资料,将处 ...
- mongodb入门很简单(2)
mongodb的安装 1.下载mongodb: www.mongodb.org 下载最新的stable版:我下载的版本是3.2.5 2.解压文件 3.不用编译:本身就是编译后的二进制可执行文件 打开 ...
- IT最新最火的网络词汇*2*(文章来源电商)
P2P.P2C .O2O .B2C.B2B.C2C等等最新最火的网络用词直接将我们都弄晕了,特此今天将这些划时代意义的词汇总结起来,若有什么不足之处,希望各位评论指正. 大致意思为: 1. ...
- 【纯代码】Swift-自定义PickerView单选(可修改分割线颜色、修改字体大小、修改字体颜色。)(可根据需要自己扩展)
typealias PopPickerViewCallBackClosure = (_ resultStr:NSString?) -> () class PopPickerView : UIVi ...
- maven打包pom.xml备忘
打包生成可执行jar 包 POM.XML <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=" ...
- 使用WebUploader实现文件批量上传,进度条显示功能
知识点:利用WebUploader,实现文件批量上传,并且实时显示文件的上传进度 参考官方文档:http://fex.baidu.com/webuploader/ (1)引入三个资源 JS,CSS,S ...
- mybatis中的懒加载
知识点:mybatis中的懒加载的使用 参考:https://www.cnblogs.com/ysocean/p/7336945.html?utm_source=debugrun&utm_me ...
- UIAutomation学习入门
一.界面的自动化操作 .Ui自动化测试 .软件外挂 二.Win32基础知识 a.Win32中一切元素皆窗口,窗口之间有父子关系.整个桌面是一个“根窗口”. b.进程: 根据进程id拿到进程对象Proc ...
- PHP处理MySQL事务代码
php使用mysqli进行事务处理 <?php$db = new mysqli("localhost","root",""," ...
- pahlcon:循环调度(Dispatch Loop)或跳转
循环调度将会在分发器执行,直到没有action需要执行为止.在上面的例子中,只有一个action 被执行到.现在让我们来看下“forward”(转发)怎样才能在循环调度里提供一个更加复杂的操作流,从而 ...