# 前言

在我们项目中,资源打包主要通过 AssetLable 的功能对需要打包的对象进行搜集:

按照指定规则设置资源的 AssetLable ,然后通过 AssetLable 再分类搜集资源,采用自定义容器管理资源引用,设置 AssetBundleName,最终出包。

在对代码走了一个流程后,将流程大概流程记一下,做做记录。

# 标签功能

  1. 在 Unity 搜索栏输入『l:Name』可以直接查找到所有指定标记的资源
    例如:
  2. 代码中通过 AssetDatabase.FindAssets 获取所有指定标签资源
    例如通过该功能获取所有标签为 “Name” 的资源:
AssetDatabase.FindAssets("l:Name", new string[1] { "Assets/Resources" });
  1. 对指定资源的标签操作:
    • AssetDatabase.GetLabels:获取
    • AssetDatabase.SetLabels: 设置
    • AssetDatabase.ClearLabels: 清除

# 流程

目前我们项目实际使用流程如下:

  • 按照指定规则设置对应的 AssetLabel (可称为初始化资源环境,如果有设置过,该步骤其实可跳过)

  • 获取所有打上标签资源

  • 然后获取文件列表 (包括列表中每个资源对应的引用 [AssetDatabase.GetDependencies]),转化为自定义引用管理容器 (EditorAssetData) 存放,各种依赖信息

  • 上述步骤每个资源都已通过 AssetDatabase.GetDependencies 获取到了自己的引用资源,这些生成的 EditorAssetData 目前统一存放于一个字典中,此时设置每个资源引用实际对应的 EditorAssetData 上下级依赖

    注:这里 GetDependencies 获取后会剔除自身,因此相当于在这打断了下级资源造成的循环引用。

    如下代码所示:循环所有搜集资源,首先将每个资源的所有下级 (即包括下级的下级) 引用加入自身,然后循环直接下级,将自身设置为下一级的父引用

    EditorAssetData[] _array = dic.Values.ToArray();
    for (int i = 0; i < _count; ++i)
    {
    	EditorAssetData _info = _array[i];
    	int _listCount = _info.DownDependentPathList.Count;
    	for (int j = 0; j < _listCount; ++j)
    	{
    		string _downPath = _info.DownDependentPathList[j];
    		if (dic.ContainsKey(_downPath))
    		{
    			_info.AddDownDependence(dic[_downPath]);
    		}
    	}
    	_listCount = _info.NoRecursiveDownDependentPathList.Count;
    	for (int j = 0; j < _listCount; ++j)
    	{
    		string _downPath = _info.NoRecursiveDownDependentPathList[j];
    		if (dic.ContainsKey(_downPath))
    		{
    			dic[_downPath].AddUpDependence(_info);
    		}
    	}
    }

    所以,实际上我们项目加载一个资源,是会同时帮忙加载下一级,以及下级资源的引用的 (平级加载所有依赖)。

  • 按照一定规则整理资源,如一个资源最顶级对其的引用 (递归上级资源)、上级依赖大于 1 的当做公共资源单独打包

  • 重复名提示

  • 在引用管理容器中命名逻辑上 AssetBundleName,并剔除无效资源 (如父级没有被引用)

    • 指定了 IsBuildSingle 标签的,直接用自己的 AssetBundleName 单打
    • 只有一个上级资源的,资源的 AssetBundleName 直接设置为上级资源同名 (与上级打一块)
  • 使用所有需打包的文件列表生成 ManiFestText:这是所有资源的描述

  • 使用所有需打包的文件列表生成 AssetBundleText:这是所有资源的数据

  • 将 ManiFestText 与 AssetBundleText 合并为一个自定义的 ScriptableObject 描述对象,并创建对应 Prefab,设置 AssetBundleName

  • 调用 Unity AssetImporter 接口将所有逻辑 AssetBundleName 进行实际资源设置

  • 调用 BuildPipeline.BuildAssetBundles 接口,打包最终 AssetBundle 资源

后续实际加载流程同理,在 FResourcesManager 首先加载 ManiFestText、AssetBundleText 资源引用、描述数据,再次形成 打包时处理生成的 『引用管理结构』,然后再依次加载公共资源 (Shader、初始配置等),进入正式流程。

# 总结

整个流程理下来,可以看出,我们项目的资源管理,完全是自己实现的一套:包括打包、加载、引用管理等。

除了打包时调用 UnityEditor 接口获取某资源的引用外,都采用了一套自定义资源管理流程封装,没有使用 Unity 内置接口如 AssetBundleManifest 等。

所以对于我们项目,打包资源时与 assetbundle 同步生成的 『.manifest』其实可以直接删掉,包括热更也是没用的,数据都是统一存在我们自定义结构中了。