前言

  奇怪的技术栈招来了奇怪的暑期实习岗,概括而言目前作为技术美术在主导某个小游戏项目: 写策划案立项,做程序功能架构及负责美术表现。等美术资源时实在无聊,顺手把项目UI画了些,再试着研究下给项目上个热更,也以此确立下后续代码,美术资源规范。

准备

前期研究

  热更可以分为资源热更和代码热更两块:目前资源热更方案底层都是AssetBundles,AB包管理繁琐故有Addressable以及YooAsset以此延伸,各家公司貌似也都在此基础上自己魔改作为资源热更方案。据说Addressable坑有亿点多所以选择了后者;而代码热更则有Xlua,ILRuntime,InjectFix,HybridCLR。Xlua之前项目用过注入式对Update不友好,ILRuntime看着还行但也要插桩,InjectFix的话疑似Xlua Plus但HybridCLR的代码一致和原生性能直接杀死了比赛。

资源热更方案 Asset Bundle Addressable YooAsset
简介 Unity的传统资源打包与管理方案。 Unity推荐的资源管理方案,通过标记资源为Addressable进行管理。 第三方插件,增加了更灵活的热更新和资源管理功能。
优势 Unity原生支持,稳定性高。 自动管理资源依赖。 简化了资源热更新流程, 支持资源分包、依赖管理等。
缺点 资源管理相对复杂,依赖路径需要手动管理,且打包和更新流程繁琐。 配置较为复杂,尤其是在多平台或大项目中。 需要第三方支持,可能存在兼容性问题。
代码热更方案 xLua ILRuntime InjectFix HybridCLR
热更新粒度 脚本文件级 类方法级 函数级修补 程序集级
性能损耗 高(Lua虚拟机) 中(解析执行) 低(局部替换) 极低(AOT为主)
开发成本 需维护Wrap文件 需绑定定代码生成 需插桩配置 无需接入
适用阶段 运维期内容更新 开发期功能迭代 运维期紧急修复 全生命周期

资源准备

  YooAsset和HybridCLR都可在官网找到快速开始文档构入项目,这里不过多赘述(YooAsset中演示项目逻辑还挺清晰的,但本人用不惯状态机直接放弃)。比较值得一提的是YooAsset不能打包StreamingAssets中的资源,HybridCLR是把程序集打成dll再封成bytes传入包中。这样的话大概项目层级规划就如下图所示(项目为弱联网模式,无网可游玩有网可更新)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Assets
├─ Arts
│ ├─ Textures
│ ├─ Materials
│ ├─ Prefabs
│ └─ ...
├─ Scenes
│ └─ ...
├─ Scripts
│ ├─ HotUpdate
│ │ ├─ HotUpdate.asmdef(热更程序集)
│ │ └─ ...(可热更代码)
│ └─ HotUpdateManager.cs(热更处理程序入口)
│ └─ HotUpdate.dll.bytes(热更字节码)
└─ StreamingAssets(打入AB包的资源)
├─ yoo
│ └─ ...(YooAsset热更资源)
└─ hybridclr
└─ ...(HybridCLR AOT字节码)

实操

  热更的大致流程为HybridCLR先热更代码(替换热更字节码),YooAsset再热更资源(放入yoo文件夹中)。个人把Yooasset和HybridCLR的初始化及获取资源流程合并到HotUpdateManager中。需注意此时热更代码需要从YooAsset中获取,即代码中注释掉重写的部分;如果要对场景中挂载的预制体热更的话也建议在代码热更后预热下预制体。

1
2
3
4
5
6
7
8
9
10
11
12
void InitGame()
{
LoadMetadataForAOTAssemblies();
#if !UNITY_EDITOR
//_hotUpdateAss = Assembly.Load(File.ReadAllBytes($"{Application.streamingAssetsPath}/hybridclr/HotUpdate.dll.bytes"));
AssetHandle handle = package.LoadAssetAsync<TextAsset>("Assets/Scripts/HotUpdate.dll.bytes");
TextAsset textAsset = handle.AssetObject as TextAsset; _hotUpdateAss = Assembly.Load(textAsset.bytes);
#else
_hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "HotUpdate");
#endif
StartCoroutine(EnterGame());
}

YooAsset的收集设置如下

分别收集美术资源,场景,热更程序集

而代码的执行逻辑则为

1
2
3
4
5
1. InitHotUpdate() //初始化YooAssets,根据不同模式(单机,联网,Web)走不同初始化流程
2. DownloadAssets() //联网时从服务器获取热更资源,比对版本走AB下载。单机时直接跳过该步
3. InitLibrarys() //加载官方给的三个最基础的AOT运行库
4. InitScripts() //加载自己的热更程序集并预热预制体
5. EnterGame() //原神启动

  之后使用本地服务器验证热更,个人使用的是nginx,下好后解压即可使用(可能需要自己配置下端口)。首先点击HybridCLR/ComplieDll/ActiveBuildTarget生成dll文件(初次需HybridCLR/Generate/All),再给热更代码集加个.bytes尾缀扔指定位置,之后点击YooAsset/AssetBundles Builder/Click Build,将生成出的那堆文件扔html文件夹中,在注入文件中配好端口索引即可。

本地服务器及热更管理器配置别收集美术资源,场景,热更程序集

  为了验证同时热更资源和代码,个人找了张耄耋的图再让AI写了个屏幕移动的脚本。打包时仅有空场景而不添加其他资源,热更时加入全部,经过数天调试最终还是跑通了这一流程(道爷,我成了!)

小结

  协调YooAsset和HybridCLR看似简单,但整起来还是有不少坑,后续的流程设置,资源规范也需要多加费心。在研究过程中官方的手册、演示项目都会是好的助力,毕竟这些项目还在迭代,之前的各类教程恐不适用,也希望这文章和工程能对需要的人有所帮助。