1)Unity 2022 LTS版本的稳定性
2)多个小资源包合并为大资源包的疑问
3)启动Unity导入变动的资源时,Singleton ScriptableObject 加载不到


这是第362篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更全面地掌握和学习。

Platform

Q:想从Unity 2021 LTS升级到Unity 2022 LTS,想问下2022的稳定性怎么样?

主要想要的Feature是DOTS的Production Version和Material Variant。

A:稳定性肯定是可以的,但需要考虑以下几点:

  1. DOTS我用的比较多,22的肯定会更好、更成熟,基本上版本越新越好具体看更新日志。
  2. 你要升级22,目前只是22.3.13,未来肯定还有很多小版本,根据规律每个大版本的小版本至少都是.3.30+了,那么就需要考虑成本了,24年开始发布的版本就需要各种用户支付安装费用,目前21最新是21.3.32,还是要综合起来考虑。

感谢沈杰@UWA问答社区提供了回答


AssetBundle

Q:看有文章说可以利用接口LoadFromFile(string path, uint crc, ulong offset);来实现资源包合并为一个打包,且能减少IO操作,不知流程是否是如下理解:

合并前:
资源包A:assets_res_a.bundle
资源包B:assets_res_b.bundle
合并前对资源包的加载方式:
AssetBundle a = AssetBundle.LoadFromFile("assets_res_a.bundle");
AssetBundle b = AssetBundle.LoadFromFile("assets_res_b.bundle");

合并后:
资源包AB:assets_res_ab.bundle
并且记录了a、b在大包(ab)中的offset(A包的offset=0,B包offset=12)
合并后对资源包的加载方式:
AssetBundle a = AssetBundle.LoadFromFile("assets_res_ab.bundle", 0, 0);
AssetBundle b = AssetBundle.LoadFromFile("assets_res_ab.bundle", 0, 12);

从接口上看,合并后并没有减少IO操作,仍是两次对assets_res_ab.bundle的读取,除非引擎内部有做优化,当第一次读assets_res_ab.bundle有IO,在没释放情况下第二次读就不是IO了,求指点迷津。

A1:首先引擎内部是有文件打开句柄的Cache的,合并以后可以减少Open Close的开销(其实这个开销不小),不过Cache也不是很大,如果频繁读取不同VFS的文件其实也差不太多了。

各个OS最大开启文件句柄数是有上限的,这个也能有效降低因为同时开启句柄太多,造成后面文件打不开问题。

个别手机有打开文件权限问题,明明文件存在,但是低概率偶发会因为权限问题短时间内无法再Open,那么合并后也能改善遇到这种问题的几率。

单独小文件在各个操作系统下其实还有一个簇的概念,比如Windows下一般最小空间占用单位是4KB。那么合并成大文件还能减少空间浪费。

在Windows下,开启WindowsDefender的情况下,Open还会触发杀毒软件Scan,文件很多很碎的情况下还是多少有点影响的。

感谢黄程@UWA问答社区提供了回答

A2:我记得官方说过这种方式还是不推荐,本身AssetBundle已经是一个VFS的,多了这个操作反而显得累赘。

感谢司马老师@UWA问答社区提供了回答

A3:以下几点建议供参考:

  1. File的Open、Exists等消耗都挺高,之前某低端机Exists大概0.3ms;一种优化策略就是基于离线分析一次生成文件列表或整合大文件认为大文件内的散文件都存在,减少Exists调用,大文件Open一次可以缓存下来不Close,减少Open调用。
  2. 句柄数限制,大多安卓可能1024,当然,也有几万的。
  3. 文件读取一般File.ReadALl或者手动开Stream,File.ReadAll底层依然是个Stream,然后Stream读取一般是每次读满一个默认的1KB或4KB长度的Buffer(或者匹配到结尾);那么对于小文件合并后的大文件,可能达到预取的效果,减少Read次数。
  4. 物理空间占用。
  5. 安全性方面的不太了解,参考楼上@黄程回答


Asset

Q:当有资源变动时,启动Unity,在导入资源时,Singleton ScriptableObject 加载不到,有解决办法么?

问题出现:
把ScriptableObject封装成单例,当配置文件,在别的资源导入的时候需要读单例配置。

已知现象:
加载不到的原因是当有新资源变化时,Asset Database要等新资源初始化完才能初始化完成,这个阶段,很多东西都加载不上来;Resource接口也是不能用的。

我最早是通过自定义导入顺序,还专门给配置文件改了后缀,但也是被资产解析挡住了。

A:你们用单例的话,可以继承Unity的ScriptableSingleton,它可以通过Attribute配置加载路径,应该能直接解决问题。我们是不用单例,所以把它内部用的接口翻出来了。