YooAsset 有自己的网站了,文西大佬更新的很快,这篇记录已经跟不上节奏咯


YooAsset官方网站




请大家使用官网学习吧!





YooAsset 学习记录

跟着b站视频+文档学习的

地址:https://github.com/tuyoogame/YooAsset

  • b站视频:https://space.bilibili.com/328590743
  • 文档看它项目里的就行

YooAsset 基于的原理也是来源于Unity的 AssetBundle 和 AddressableAssetBundle的原理及最佳实践

YooAsset简介

具体的简介项目里都有,就简单截一些了

unity 微信小游戏get_unity 微信小游戏get

1.Editor

1.1导入YooAsset

直接看文档。

总共三种,用的是这种

unity 微信小游戏get_运行模式_02

unity 微信小游戏get_初始化_03

1.2 全局配置

unity 微信小游戏get_unity 微信小游戏get_04

在Resources下新建 YooAsset 配置文件

unity 微信小游戏get_加载_05

1.3 资源配置

配置直接看文档

unity 微信小游戏get_unity 微信小游戏get_06

1.3.1 AutoCollectShaders

新版已经没有这个选项了。

unity 微信小游戏get_unity_07

ShaderVariant Collector 仍在

unity 微信小游戏get_初始化_08

旧版:

搜集所有Group内的材质球,把它们的shader打入一个包内

unity 微信小游戏get_unity 微信小游戏get_09

这里设置好后打开

unity 微信小游戏get_unity_10

为了防止Shader资源荣誉,点击搜集变种生成

unity 微信小游戏get_初始化_11

点击完毕后,会跳到它给我们的一个所有Shader的材质球展示界面。以及生成了 ShaderVariants 的搜集结果文件

unity 微信小游戏get_unity_12

然后在热更资源目录新建一个文件夹,放入这个配置文件

unity 微信小游戏get_unity_13

然后在YooAsset打包配置里新建一个它的收集器

unity 微信小游戏get_运行模式_14

专门为它自定义一个打包规则

unity 微信小游戏get_unity 微信小游戏get_15

这里返回的名称和Shader Bundle Name一致

unity 微信小游戏get_运行模式_16

最后给搜集器换成自定义的打包规则类即可

unity 微信小游戏get_加载_17

1.4 资源打包

unity 微信小游戏get_unity_18

记录一些配(详细配置请看文档,只记录了部分)

  • Build Pipeline 构建管线
  1. BuiltinBuildPipeline: 传统的内置构建管线。
  2. ScriptableBuildPipeline: 可编程构建管线。
  • Build Mode 构建模式
  1. 强制构建模式:会删除指定构建平台下的所有构建记录,重新构建所有资源包。
  2. 增量构建模式:以上一次构建结果为基础,对于发生变化的资源进行增量构建。
  3. 演练构建模式:在不生成AssetBundle文件的前提下,进行演练构建并快速生成构建报告和补丁清单。
  4. 模拟构建模式:在编辑器下配合EditorSimulateMode运行模式,来模拟真实运行的环境。
  • Output Name Style 输出的资源包文件名称样式
  1. HashName:哈希值
  2. HashName_Extension:哈希值+后缀名
  3. HashName_BundleName_Extension:资源包名+哈希值+后缀名
  • Copy Buildin File Option 首包资源文件的拷贝方式
  1. None:不拷贝任何文件
  2. ClearAndCopyAll:先清空已有文件,然后拷贝所有文件
  3. ClearAndCopyByTags:先清空已有文件,然后按照资源标签拷贝文件
  4. OnlyCopyAll:不清空已有文件,直接拷贝所有文件
  5. OnlyCopyByTags:不清空已有文件,直接按照资源标签拷贝文件

重要概念

  • 增量构建 增量构建是在Unity的帮助下实现的一种快速打包机制。主要是利用资源构建相关的缓存文件来避免二次构建,以此来提高打包效率。
  • 强制构建 强制构建是每次构建之前,都会清空之前构建的所有缓存文件,以此来重新构建资源包。
  • 首包资源 在构建应用程序的时候,我们希望将某些资源打进首包里,**首包资源拷贝至StreamingAssets/BuildinFiles/目录下。**首包资源如果发生变化,也可以通过热更新来更新资源。
  • 补丁包 无论是通过增量构建还是强制构建,在构建完成后都会生成一个以包裹版本(PackageVersion)命名的文件夹,我们把这个文件夹统称为补丁包。补丁包里包含了游戏运行需要的所有资源,我们可以无脑的将补丁包内容覆盖到CDN目录下,也可以通过编写差异分析工具,来筛选出和线上最新版本之间的差异文件,然后将差异文件上传到CDN目录里。 不勾就是增量,勾选就是重出包了。

1.4.1 自定义加密

unity 微信小游戏get_加载_19

unity 微信小游戏get_unity_20

  • Check 检查哪些文件要加密,比如配置表。路径是相对应于Assets下的(“Assets/xxx/xxx”)
  • Encrypt 就是具体的加密算法了。demo里提供了一个简单的数据偏移算法。

1.4.2 Buildin Tags

unity 微信小游戏get_运行模式_21

Buildin Tags 里填的是Group 的 Grouper Asset Tags。就是表示你这次想把哪些 Group 打包。

多个 Tag 用 ; 隔开。 
buildin;level;other

1.4.3 补丁清单

unity 微信小游戏get_加载_22

  1. AssetList 所有通过Grouper搜集器搜到的通过代码加载的资源。
  • AssetPath Asset下的相对路径
  • BundleID 主BundleID
  • DependIDs 以来的BundleID们
  1. BundleList 根据YooAsset配置生成的所有Bundle了上面的BundleID指的就是这个列表下的Bundle
  • Hash 它的hash值
  • CRC 验证完整性
  • SizeBytes 大小
  • Tags 包含了Grouper Asset Tags 和 搜集器上填的 tag
  • Flag 一些附加数据全部存在这里(= =没搞懂)
  1. YooAsset的不同之处
  1. 记录AssetPath对应的资源对象依赖了哪些Bundle。
  2. 记录 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 资源部署

unity 微信小游戏get_unity 微信小游戏get_23

增量更新直接替换就可以了。记得用类似Beyonce Compare比对一线,不用上传没改变的文件。

1.6 构建报告

unity 微信小游戏get_初始化_24

unity 微信小游戏get_unity 微信小游戏get_25

unity 微信小游戏get_unity_26

这个构建报告,在生成的文件下面都有。导入的就是这个东西。

AssetView

unity 微信小游戏get_加载_27

Grouper里搜集的,所有通过代码加载的资源对象。

  • Size 大小
  • Main Bundle 位于哪个Bundle里

unity 微信小游戏get_unity 微信小游戏get_28

原生数据其实不是AB包的格式。并且每份都有一个资源包。

BundleView

unity 微信小游戏get_初始化_29

以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}");
	    }
	}

老版本和新版本差异有点大啊

unity 微信小游戏get_运行模式_30

源代码解析
编辑器模拟模式

每次启动调用EditorSimulateModeHelper.SimulateBuild()方法,都会在底层执行一次模拟构建(Simulate Build)。

如果参与构建的资源对象数量级很大的话则会有卡顿现象,可以通过直接指定已有的清单路径来避免每次都重复执行模拟构建。

单机运行模式

在初始化的时候,会直接读取内置清单文件(StreamingAssets文件夹里的文件),最后根据加载的清单去验证沙盒里缓存的文件。

联机运行模式

在初始化的时候,会优先从沙盒里加载清单,如果沙盒里不存在,则会尝试加载内置清单并将其拷贝到沙盒里。最后根据加载的清单去验证沙盒里缓存的文件。

注意:如果沙盒清单和内置清单都不存在,初始化也会被判定为成功!

2.2 资源更新

unity 微信小游戏get_unity 微信小游戏get_31

demo里实现了一个状态机,咱们可以直接拿来用。

文档和视频内容有差异,这里只好直接用视频的文档截图了

unity 微信小游戏get_运行模式_32

也可以自己写HTTP逻辑来访问。

unity 微信小游戏get_运行模式_33

unity 微信小游戏get_unity_34

unity 微信小游戏get_初始化_35

unity 微信小游戏get_初始化_36

这里的 tags 就是对于的 Grouper Asset Tags ,表示你想下载那个 Grouper。

不太理解这么做的原因= =。

2.2.1 路径

内置文件

unity 微信小游戏get_unity 微信小游戏get_37

重新强制出包的时候,把生成的内容放到如图目录下。

沙盒

unity 微信小游戏get_unity 微信小游戏get_38

unity 微信小游戏get_初始化_39

在PC上的地址和Asset同级,应该就是可写目录了。也就是热更新文件的存放位置。

2.2.2 下载器

unity 微信小游戏get_初始化_40

补丁下载目前只有两种,传入单/多 个Grouper Asset Tag 。

这样可以实现按需下载,比如我可以在进入关卡的时候再下载这个关卡的资源(进入关卡Loading的时候下载)。

3.补充部分

3.1 Sample 改造

我直接拿Sample里的Sapce Shooter的热更流程来改了

unity 微信小游戏get_加载_41

unity 微信小游戏get_运行模式_42

unity 微信小游戏get_加载_43

大致保留这些就行了。还有提供的UniFramework系类的挺好用的,要是不想自己写事件系统之类的,可以直接拿来用。

unity 微信小游戏get_unity 微信小游戏get_44

3.2 UniTask接入

4.AssetBundle 学习笔记(简略)

Unity学习—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 决定是否同时卸载该包下所有已加载对象。

  1. 由此诞生一个问题,当卸载了 AssetBundle 未卸载已加载对象时,此时这些对象与 AssetBundle 便失去关联了,重新加载 AssetBundle 并重新加载同一对象时,只会产生一个新的关联对象,而旧对象则无法使用AssetBundle.Unload卸载了,这就导致了内存中同时存在两个一样的对象。
  2. unity 微信小游戏get_加载_45

  3. 另外还可能出现的问题是,在 AssetBundle 卸载之后加载 AssetBundle 中的对象时,会出现对象缺失的问题。出现该问题大部分原因为 Unity 丢失又重新获得对图形上下文的控制,如移动设备 App 挂起,PC 锁定等场景

4.7 AssetBundle 发布

unity 微信小游戏get_unity_46

也就是说,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.其他

unity 微信小游戏get_运行模式_47

5.问题&解答

Q:自己使用的时候,收集器里只有原生类型的文件,然后报错“No AssetBundle has been set for this build.”

A: 意思就是你的AssetBundle根本没东西啊,没东西用什么AssetBundle。 然后添加了一个Scene到收集器里,就不报错了 。。。服了,原生类型不配算资源呗?