YooAsset 有自己的网站了,文西大佬更新的很快,这篇记录已经跟不上节奏咯
YooAsset官方网站
请大家使用官网学习吧!
YooAsset 学习记录
跟着b站视频+文档学习的
地址:https://github.com/tuyoogame/YooAsset
- b站视频:https://space.bilibili.com/328590743
- 文档看它项目里的就行
YooAsset 基于的原理也是来源于Unity的 AssetBundle 和 Addressable
AssetBundle的原理及最佳实践
YooAsset简介
具体的简介项目里都有,就简单截一些了
1.Editor
1.1导入YooAsset
直接看文档。
总共三种,用的是这种
1.2 全局配置
在Resources下新建 YooAsset 配置文件
1.3 资源配置
1.3.1 AutoCollectShaders
新版已经没有这个选项了。
ShaderVariant Collector 仍在
旧版:
搜集所有Group内的材质球,把它们的shader打入一个包内
这里设置好后打开
为了防止Shader资源荣誉,点击搜集变种生成
点击完毕后,会跳到它给我们的一个所有Shader的材质球展示界面。以及生成了 ShaderVariants 的搜集结果文件
然后在热更资源目录新建一个文件夹,放入这个配置文件
然后在YooAsset打包配置里新建一个它的收集器
专门为它自定义一个打包规则
这里返回的名称和Shader Bundle Name一致
最后给搜集器换成自定义的打包规则类即可
1.4 资源打包
记录一些配(详细配置请看文档,只记录了部分)
-
Build Pipeline 构建管线
- BuiltinBuildPipeline: 传统的内置构建管线。
- ScriptableBuildPipeline: 可编程构建管线。
-
Build Mode 构建模式
- 强制构建模式:会删除指定构建平台下的所有构建记录,重新构建所有资源包。
- 增量构建模式:以上一次构建结果为基础,对于发生变化的资源进行增量构建。
- 演练构建模式:在不生成AssetBundle文件的前提下,进行演练构建并快速生成构建报告和补丁清单。
- 模拟构建模式:在编辑器下配合EditorSimulateMode运行模式,来模拟真实运行的环境。
-
Output Name Style 输出的资源包文件名称样式
- HashName:哈希值
- HashName_Extension:哈希值+后缀名
- HashName_BundleName_Extension:资源包名+哈希值+后缀名
-
Copy Buildin File Option 首包资源文件的拷贝方式
- None:不拷贝任何文件
- ClearAndCopyAll:先清空已有文件,然后拷贝所有文件
- ClearAndCopyByTags:先清空已有文件,然后按照资源标签拷贝文件
- OnlyCopyAll:不清空已有文件,直接拷贝所有文件
- OnlyCopyByTags:不清空已有文件,直接按照资源标签拷贝文件
重要概念
- 增量构建
增量构建是在Unity的帮助下实现的一种快速打包机制。主要是利用资源构建相关的缓存文件来避免二次构建,以此来提高打包效率。 - 强制构建
强制构建是每次构建之前,都会清空之前构建的所有缓存文件,以此来重新构建资源包。 - 首包资源
在构建应用程序的时候,我们希望将某些资源打进首包里,**首包资源拷贝至StreamingAssets/BuildinFiles/目录下。**首包资源如果发生变化,也可以通过热更新来更新资源。 - 补丁包
无论是通过增量构建还是强制构建,在构建完成后都会生成一个以包裹版本(PackageVersion)命名的文件夹,我们把这个文件夹统称为补丁包。补丁包里包含了游戏运行需要的所有资源,我们可以无脑的将补丁包内容覆盖到CDN目录下,也可以通过编写差异分析工具,来筛选出和线上最新版本之间的差异文件,然后将差异文件上传到CDN目录里。
不勾就是增量,勾选就是重出包了。
1.4.1 自定义加密
- Check 检查哪些文件要加密,比如配置表。路径是相对应于Assets下的(“Assets/xxx/xxx”)
- Encrypt 就是具体的加密算法了。demo里提供了一个简单的数据偏移算法。
1.4.2 Buildin Tags
Buildin Tags 里填的是Group 的 Grouper Asset Tags。就是表示你这次想把哪些 Group 打包。
多个 Tag 用 ; 隔开。
buildin;level;other
1.4.3 补丁清单
-
AssetList
所有通过Grouper搜集器搜到的通过代码加载的资源。
- AssetPath Asset下的相对路径
- BundleID 主BundleID
- DependIDs 以来的BundleID们
-
BundleList
根据YooAsset配置生成的所有Bundle了上面的BundleID指的就是这个列表下的Bundle
- Hash 它的hash值
- CRC 验证完整性
- SizeBytes 大小
- Tags 包含了Grouper Asset Tags 和 搜集器上填的 tag
- Flag 一些附加数据全部存在这里(= =没搞懂)
-
YooAsset的不同之处
- 记录AssetPath对应的资源对象依赖了哪些Bundle。
- 记录 AssetPath对应的资源对象的Bundle 依赖了哪些 Bundle
而大部分其他的框架是用 2. 的方式。
而 2. 的方式有个问题。比如有 A、B、C、D 三个 Bundle,对象 X 在 A 、C Bundle 里
X in A Depend A、C
A depend B
B depend C、D
方法 2.
会导入 ABCD
X -> A -> B -> C、D result ABCD
方法 1.
直接导入A、C即可。
因为经过计算,这里的依赖是展开的,不是树形,不需要再查每个Bundle下层的依赖了
X in A Depend A、C
X -> A ,X -> C result A、C
1.5 资源部署
增量更新直接替换就可以了。记得用类似Beyonce Compare比对一线,不用上传没改变的文件。
1.6 构建报告
这个构建报告,在生成的文件下面都有。导入的就是这个东西。
AssetView
Grouper里搜集的,所有通过代码加载的资源对象。
- Size 大小
- Main Bundle 位于哪个Bundle里
原生数据其实不是AB包的格式。并且每份都有一个资源包。
BundleView
以Bundle视角的视图。下面可以看到这个Bundle里可以用代码加载的资源列表。
2.代码部分
这部分代码具体请看文档。仅会贴出部分
2.1 初始化
2.1.1初始化资源系统
// 初始化资源系统
YooAssets.Initialize();
// 创建默认的资源包
var package = YooAssets.CreateAssetsPackage("DefaultPackage");
// 设置该资源包为默认的资源包,可以使用YooAssets相关加载接口加载该资源包内容。
YooAssets.SetDefaultAssetsPackage(package);
资源系统的运行模式支持三种:编辑器模拟模式,单机运行模式,联机运行模式。
编辑器模拟模式
在编辑器下,不需要构建资源包,来模拟运行游戏。
注意:该模式只在编辑器下起效
private IEnumerator InitializeYooAsset()
{
var initParameters = new EditorSimulateModeParameters();
initParameters.SimulatePatchManifestPath = EditorSimulateModeHelper.SimulateBuild("DefaultPackage");
yield return defaultPackage.InitializeAsync(initParameters);
}
联机运行模式
对于需要热更新资源的游戏,可以使用联机运行模式,该模式下初始化参数会很多。
注意:该模式需要构建资源包
- DecryptionServices : 如果资源包在构建的时候有加密,需要提供实现IDecryptionServices接口的实例类。
- QueryServices:内置资源查询服务接口。
- DefaultHostServer : 默认的资源服务器IP地址。
- FallbackHostServer : 备用的资源服务器IP地址。
如果只有一个CDN地址那就都填一样的
private IEnumerator InitializeYooAsset()
{
var initParameters = new HostPlayModeParameters();
initParameters.QueryServices = new QueryStreamingAssetsFileServices();
initParameters.DefaultHostServer = "http://127.0.0.1/CDN1/Android/v1.0";
initParameters.FallbackHostServer = "http://127.0.0.1/CDN2/Android/v1.0";
yield return defaultPackage.InitializeAsync(initParameters);
}
// 内置文件查询服务类
private class QueryStreamingAssetsFileServices : IQueryServices
{
public bool QueryStreamingAssets(string fileName)
{
// 注意:使用了BetterStreamingAssets插件,使用前需要初始化该插件!
string buildinFolderName = YooAssets.GetStreamingAssetBuildinFolderName();
return BetterStreamingAssets.FileExists($"{buildinFolderName}/{fileName}");
}
}
老版本和新版本差异有点大啊
源代码解析
编辑器模拟模式
每次启动调用EditorSimulateModeHelper.SimulateBuild()方法,都会在底层执行一次模拟构建(Simulate Build)。
如果参与构建的资源对象数量级很大的话则会有卡顿现象,可以通过直接指定已有的清单路径来避免每次都重复执行模拟构建。
单机运行模式
在初始化的时候,会直接读取内置清单文件(StreamingAssets文件夹里的文件),最后根据加载的清单去验证沙盒里缓存的文件。
联机运行模式
在初始化的时候,会优先从沙盒里加载清单,如果沙盒里不存在,则会尝试加载内置清单并将其拷贝到沙盒里。最后根据加载的清单去验证沙盒里缓存的文件。
注意:如果沙盒清单和内置清单都不存在,初始化也会被判定为成功!
2.2 资源更新
demo里实现了一个状态机,咱们可以直接拿来用。
文档和视频内容有差异,这里只好直接用视频的文档截图了
也可以自己写HTTP逻辑来访问。
这里的 tags 就是对于的 Grouper Asset Tags ,表示你想下载那个 Grouper。
不太理解这么做的原因= =。
2.2.1 路径
内置文件
重新强制出包的时候,把生成的内容放到如图目录下。
沙盒
在PC上的地址和Asset同级,应该就是可写目录了。也就是热更新文件的存放位置。
2.2.2 下载器
补丁下载目前只有两种,传入单/多 个Grouper Asset Tag 。
这样可以实现按需下载,比如我可以在进入关卡的时候再下载这个关卡的资源(进入关卡Loading的时候下载)。
3.补充部分
3.1 Sample 改造
我直接拿Sample里的Sapce Shooter的热更流程来改了
大致保留这些就行了。
还有提供的UniFramework系类的挺好用的,要是不想自己写事件系统之类的,可以直接拿来用。
3.2 UniTask接入
4.AssetBundle 学习笔记(简略)
以下内容为此博客的笔记。
详细介绍请看博客,这里只记简略。
4.1 AssetBundle 作用
- AssetBundle 是外部资产的集合,可独立于 Unity 构建过程外,是 Unity 更新非代码内容的主要工具;
- AssetBundle 使开发者可以提交更小的应用包,最小化运行时内存压力,使终端可以选择性加载优化内容
4.2AssetBundle 组成
AssetBundle 主要由两部分组成:文件头和数据段
文件头包含了id、压缩类型、索引清单,该索引清单是与 Resources 相同的记录了序列化文件中的字节偏移量的查找表。对于大部分平台该表为平衡搜索树,对 Windows 和 OSX 系列(包括 iOS)则为红黑树,随着 AssetBundle 中对象的增加,构造清单所需时间的增长速度将超过线形增长速度。
数据段包含了 Asset 经过序列化的原始数据,数据还可选择是否压缩,
- 若使用 LZMA 压缩,则将所有 Asset 的字节数组整体压缩;
- 若使用 LZ4 压缩,则将每个 Asset 单独压缩;
- 若不压缩,则数据保持原始字节流
4.3AssetBundle 加载
有四种不同的 API 用于加载 AssetBundle,但每个 API 的行为随压缩算法和平台而不同
- AssetBundle.LoadFromMemoryAsync
- AssetBundle.LoadFromFile
该方法可高效地从硬盘加载未压缩或 LZ4 压缩的 Assetbundle,加载 LZMA 压缩包时会先解压再加载到内存 - WWW.LoadfromCacheOrDownload(5.6 及以前版本)旧方法,已抛弃
- UnityWebRequestAssetBundle (5.3 及以后版本)
官方推荐尽量使用 AssetBundle.LoadFromFile,该 API 在速度、磁盘使用和运行时内存使用方面都最高效;需要下载则使用 UnityWebRequest
注:Web平台都用 UnityWebRequest 来加载,web平台没有本地存储数据
4.4 AssetBundle Asset 加载
同步异步加载 Asset 一共有六种 API 可使用
-
LoadAssets (LoadAssetsAsync)
-
LoadAssetWithSubAssets (LoadAssetWithSubAssetsAsync)
适合需要加载的对象内嵌了其他对象的情况,若加载对象均来自于一个 Asset 且包中有许多其他无关对象,则使用该 API -
LoadAllAsset (LoadAllAssetAsync)
其他情况均用LoadAsset (LoadAssetAsync)
4.5 AssetBundle 依赖
当一个对象所在的 AssetBundle 被加载时,该对象就被分配了一个唯一的有效实例 ID。Unity 不会自动加载子 AssetBundle。就是不会加载你的依赖,咱们必须自己处理加载依赖的AssetBundle。
在构建 AssetBundle 时,Unity 创建一个包含每一个 AssetBundle 依赖信息的类型为 AssetBundleManifest 的序列化对象,该文件存在一个与其他 AssetBundle 在同一打包路径下的单独的 AssetBundle 中,且与父层文件夹名相同。
有两种 API 查询依赖
- AssetBundleManifest.GetAllDependencies 获取 AssetBundle 的所有依赖层级
- AssetBundleManifest.GetDirectDependencies 获取 AssetBundle 直接依赖
因该 API 会生成字符串数组,所以应尽量少用,且避免性能高峰时使用
官方建议:
大部分场合下,在进入性能需求高的场景前,尽可能多地加载对象,尤其对于移动平台这种,访问本地存储慢,加载卸载对象引起内存流失会触发垃圾回收的平台
4.6 AssetBundle 使用
这个问题和资源卸载有关。
不适当地卸载 AssetBundle 会导致对象缺失或者在内存中重复。
调用AssetBundle.Unload可卸载 AssetBundle 的头信息,传入参数 true 或 false 决定是否同时卸载该包下所有已加载对象。
-
由此诞生一个问题,当卸载了 AssetBundle 未卸载已加载对象时,此时这些对象与 AssetBundle 便失去关联了,重新加载 AssetBundle 并重新加载同一对象时,只会产生一个新的关联对象,而旧对象则无法使用AssetBundle.Unload卸载了,这就导致了内存中同时存在两个一样的对象。
-
另外还可能出现的问题是,在 AssetBundle 卸载之后加载 AssetBundle 中的对象时,会出现对象缺失的问题。出现该问题大部分原因为 Unity 丢失又重新获得对图形上下文的控制,如移动设备 App 挂起,PC 锁定等场景
4.7 AssetBundle 发布
也就是说,AssetBundle.LoadFromFile只能在无压缩的apk获取AssetBundle???
4.8 自定义下载器
这部分看博客
4.9 Asset 分包策略
- 逻辑实体分包
- 对象类型分包
- 并发内容分包
AssetBundle变体是什么意思?
4.10 常见问题
只贴出原因,解决方案请看博客。或者这部分直接到博客里看
4.10.1 资产重复
若有一个未分配资产被多个不同 AssetBundle 中的已分配资产引用,则在构建 AssetBundle 时,该引用对象会被拷贝到每个 AssetBundle 中,造成空间和内存浪费
4.10.2 精灵图集重复
任何自动生成的图集会被分配到其包含精灵所在的 AssetBundle,若精灵对象被分配到多个包,则图集会被复制,因此需确保同一图集的精灵对象被分配到同一 AssetBundle 中
4.10.3 Android 纹理
由于 Android 生态的碎片化,经常需要使用不同格式压缩纹理。
为了适配支持不同纹理格式的android机器。使用AssetBundle变体
5.AssetBundle 变体
AssetBundle Variants 的主要作用在于使 AssetBundle 随运行时环境调整其内容配置。
AssetBundle Variants 使不同 AssetBundle 中的不同对对象在加载时公用一个实例 ID,使其看起来为同一个对象。
个人觉得多渠道多语言也可以用这个。
6.其他
5.问题&解答
Q:自己使用的时候,收集器里只有原生类型的文件,然后报错“No AssetBundle has been set for this build.”
A:
意思就是你的AssetBundle根本没东西啊,没东西用什么AssetBundle。
然后添加了一个Scene到收集器里,就不报错了
。。。服了,原生类型不配算资源呗?