深入剖析U3D的Miss Mono Behaviour问题

我相信u3d稍微大一点的项目,大家都是用unitypackage来传递资源和工作共享的吧?

问题是这样的,美术给我们的unitypackage在程序这边导入之后,总是会出现Miss Mono Behaviour的问题,也就是脚本丢失了,不知道大家有没遇到过。出现很多次了,终于在两天前怒了,想要彻底解决这个破事。

本文就是解决这个问题时的一些经验,最后发现,在良好的工作规范之下,这个问题几乎不应该出现,我们项目出现了多是历史遗留问题,metaFile应该在项目最早期就开启,并受SVN版本管理。



Meta File

U3D是自带文件版本管理的,在project setting - editor - Version Control 可以选择,一般都是选择生成Meta Files 的方式来管理。

meta file 从内容上讲,记录了

1、u3d当前的的文件格式版本号

2、每个文件的唯一标示:guid。

3、一些具体文件类型相关的信息,比如是脚本文件,会记录executionOrder之类的额外信息,png文件,会记录贴图尺寸,mipmap之类的信息

这中间,最重要的就是GUID了,稍后会讲到。



由于Miss Mono Behaviour主要是处理脚本,所以我以脚本对象举例,其实本文的技巧可以推广到任意类型的文件,只是繁简程度。

脚本文件: .cs文件

容器文件: .unity 和 .prefab文件

这样区分是因为脚本文件只能作为组件对象挂在到GameObject上,而GameObject只会在scene(.unity)和prefab(.prefab)中出现,容器文件的处理方式是一致的,我仅以.unity文件为例。



容器文件和其他相关文件

二进制打开.unity文件,工具我推荐fairdellhexcmp.exe,可以搜索到引用的脚本组件,比如"abc.cs" ,我们可以看到,unity文件记录了

1、以Assets目录开始的 PathName , 比如 "Assets/artcode/abc.cs"

2、GUID的串行化形式

3、脚本的cache文件所在地 , library/cache/c9/c9123456789012eec9123456789012ee

相关文件包括Library目录下的

1、guidmapper文件

2、metadata目录

3、cache目录

4、assetdatabase3文件

文件guidmapper记录的是 短文件名 和 GUID 的对应关系。

assetDatabase3 记录的是 文件全路径 和 cache文件的对应关系。

metadata , cache 则是记录的当前的脚本文件格式信息和内容信息,也就是U3D的版本管理核心数据。

当脚本文件内容发生变化的时候,实际上GUID是不会发生变化的。而且U3D其实并不基于文件内容增量变化的版本管理,而是覆盖式的。这也从一个方面说明为什么它大部分文件都是二进制的。





GUID的产生和它的使用者

GUID是文件唯一标示,容器文件里的关联关系都是基于GUID而不是基于文件名和文件路径的。当一个新文件创建之后,U3D会自动给它生成一个GUID。

现在假设这样一个情况,我们新建了脚本abc.cs , U3D给他分配了GUID : c9123456789012eec9123456789012ee, 记录在 abc.cs.meta 文件里

然后我们把这个脚本挂到 scene 中的某个对象上,并且把这个场景保存为 sss.unity.

现在可以知道 sss.unity 里记录了GUID, abc.cs.meta文件里也记录了GUID ,之前列出来的4个相关文件里也发生了变化,这六个变化是GUID产生之时U3D自动做的事情。





Miss Mono Behaviour问题的产生

我机器上sss.unity里记录的abc.cs的GUID是 AAA,但是如果我只给你abc.cs,而不同时给你abc.cs.meta文件,那么你的机器会自己生成一个GUID,而这个GUID和我的是不一样的BBB,于是问题就产生了,在这之后,如果你导入我给你的sss.unitypackage的话,你就会发生Miss Mono Behaviour问题。

这是因为你机器上的 sss.unity引用的abc.cs 的 GUID还是AAA,但实际上相关4文件里都没有这个GUID的文件记录。

这个问题本质上是不理解U3D版本管理导致的使用错误,在项目初期非常普遍,大家也不清楚到底肿么了,导致这个错误被扩散到相当多的scene中。这个就十分要命了,不得不总是小心翼翼的,看哪个脚本有没丢。



如何解决

基本上来说就是保持各处GUID都一致,分别是

【人工改】脚本的meta文件

【人工改】容器文件里的引用

【U3D自动改】library/cache里以GUID命名的文件

【U3D自动改】library/metadata里以GUID命名的文件

【U3D自动改】library/guidmapper里的对应关系

【U3D自动改】library/assetDatabase3里的对应关系

如果只是sss.unity里的是AAA, 自己机器上的是BBB,只需要将AAA那台机器的meta file拷贝过来就可以了



复杂情况

(总有但是,不是么)

在解决的过程中,实际上发现错误情况不止一种,而是

1、GUID在两台机器不一致

2、容器文件内的GUID引用在两台机器的不一致

3、脚本路径不一致

4、脚本文件没了

上述4种错误会任意混合出现,都是因为多人协作流程不规范导致的问题,而要做到规范是不可能的,总有人会犯点错不是?



我基于上述的分析,做了针对项目实际情况的自动化工具,在美术、策划、和程序之间维护文件GUID的同步,C#处理二进制文件写起来真够恶心的。这个工具的源码在公司内网,带不出来了,不过相信知道这个问题的成因之后,理解决它也没多远了,加油吧少年们。

你可能感兴趣的:(IO)