概述
在项目的开发中,使用的是Tolua的热更新框架,考虑到项目有买量发小包推广的需求,需要支持边玩边下载、增量更新资源的需求,所以在实现资源管理器时,需要额外考虑到这些问题。这里对使用方案的实现细节做下记录。
实现
首先,在项目中,我们将资源分为必要资源与非必要资源。必要资源在游戏启动时进行更新;而非必要时则是在用到时,进行资源加载时再进行检查更新。为保证非必要资源的正确加载,主要实现的机制有:
- 加载优先级
- ab引用计数管理
- ab缓存
- ab更新加载
- 边玩边下
加载优先级
在边玩边下的过程中,需要考虑到资源加载的优先级问题,一些重要资源要做能能够优先加载。就比如,加载一个角色模型时,身体、头部必须优先加载,武器、翅膀等挂件则优先级靠后。
ab引用计数管理
对加载的ab进行管理,每LoadAsset一次则引用计数+1;当实例化对象销毁时,则对应ab引用-1。持续检查是否存在引用计数为0的ab,有则Unload此ab;与此同时,此ab所依赖的的资源ab引用计数也都-1;
ab缓存
当更新ab时,需要根据当前游戏状态进行处理,确保不对游戏性能有大的影响。项目中分为切场景中与非切场景中两种情况进行处理。切场景时,当发生更新ab的情况,则直接将最新的ab存储到本地,且进行版本文件信息的更新;而非切场景时,更新ab后,将ab的序列化数据缓存使用,不立即进行存文件操作,而是每隔2s检查是否存在缓存的ab数据,并判断当前时刻存文件不会对玩家造成影响,则进行存本地操作,更新版本文件信息;在下次切场景时,如果还有缓存未存到本地,则一口气将所有ab缓存存到本地。
加载资源流程
- 检查是否为版本文件
- 检查是否已经预加载过资源了,是的话直接返回资源。
- 保存加载请求信息,以ab名为索引保存在map中。并根据指定的优先级加入到更新加载任务队列中。
- 从更新加载任务队列中按优先级取出一个Task
- 启动协程进行Task。
- 检查是否为最新版本,不是则启动下载,等待下载结束返回
- 进行依赖ab资源加载。从第1步开始,进行加载资源流程。
- 更新ab完毕,加载bundle。
- 资源、依赖资源加载完成后,最后进行LoadAsset,执行回调
边玩边下
提供一种主动下载非必须资源更新方式,在具备特定条件下触发(是否为Wifi,手机内存达标)。使用多线程,以WebClient方式直接将需要更新的资源下载到本地,并且记录改资源的版本信息。
总结
项目中使用的检查更新方式,总是需要读取本地bundle进行Md5值比对,虽然这种方式比较可靠,杜绝了资源被中途串改的可能,但同时也带来了不小的io压力,且会造成大量的GC Alloc;还有一个问题,就是缓存ab的机制,虽然可以避免资源更新完后保存的性能消耗,但是这是以内存去换性能。综合这几种问题,可能这是造成现在项目Mono内存较大的原因之一吧。