Unity构建详解(8)——SBP的Bundle生成

【WriteSerializedFiles】

这里将实际的写操作执行单独拎了出来共用,放在了IRunCachedCallbacks,但数据的传入和处理还是在Task中执行。

这一步会生成实际的SerializedFile文件,文件名就是之前的InternalName,但这还不是最终的Bundle文件,所以在之前的处理中会有一个InternalnameToBundleName的映射。

这一步可以改造成多线程的。

Unity中将用到的文件分为4类

public enum FileType
{//// 摘要://     Object is contained in file not currently tracked by the AssetDatabase.NonAssetType,//主要是内置资产,这些资产guid都是0,得通过路径(path)直接找到//// 摘要://     Object is contained in a very old format. Currently unused.DeprecatedCachedAssetType,//// 摘要://     Object is contained in a standard asset file type located in the Assets folder.SerializedAssetType,//Asset文件夹下Unity自定义的文件,例如scene,prefab,material,animationclip//// 摘要://     Object is contained in the imported asset meta data located in the Library folder.MetaAssetType //一些行业标准文件,例如fbx,texture,这些在导入Unity中会转成Unity的格式,被保存在Artifacts中
}

 先看没有缓存时

  • ProcessUncached
    • 获取文件保存路径:就是TempOutputFolder
    • 调用WriteOperations中的Write方法
      • ContentBuildInterface.WriteSerializedFile将序列化的数据写入到文件中得到WriteResult具体如下
        • ObjectSerializedInfo[] m_SerializedObjects要序列化的Object
          • ObjectIdentifier m_SerializedObject Object的标识
            • GUID m_GUID
            • long m_LocalIdentifierInFile 就是Bundle内的PathID
            • FileType m_FileType
            • string m_FilePath
          • SerializedLocation m_Header ObjectHeader的数据的位置
          • SerializedLocation m_RawData Object包含的数据的位置
            • string m_FileName
            • ulong m_Offset
            • ulong m_Size
        • ResourceFile[] m_ResourceFiles 生成的CAB-xxxxx文件,一般的AssetBundle只有一个,Scene还会有CAB-xxxx.sharedAsset文件
          • string m_FileName
          • string m_FileAlias
          • bool m_SerializedFile
        • Type[] m_IncludedTypes
        • string[] m_IncludedSerializeReferenceFQN
        • ExternalFileReference[] m_ExternalFileReferences
          • string m_filePath;
          • int m_type
          • GUID m_guid
    • 计算文件的Hash数据CalculateFileMetadata
      • RawFileHash:该Bundle内包含的所有ResourceFiles的名字的Hash
        • data.RawFileHash = HashingMethods.Calculate(fullHashObjects).ToHash128();
      • ContentHash:根据第一个Object的内容计算Hash
        • data.ContentHash = HashingMethods.Calculate(contentHashObjects).ToHash128();
        • 注意计算Hash只会从流中取4kb的数据,很可能导致文件Object数据变了,但Hash值没变
    • 简化SerializedObject数据SlimifySerializedObjects
    • PostProcess将写入的数据放入WriteResult中
      • m_Results.WriteResultsMetaData.Add(op.Command.internalName, item.Context.MetaData);
      • m_Results.WriteResults.Add(op.Command.internalName, item.Context.Result);

缓存数据的获取和保存 

  • 创建缓存CreateCacheEntry
    • entry.Type = CacheEntry.EntryType.Data;这里的EntryType是Data
  • 获取缓存数据GetCachedInfo
    • 这里缓存的定义数据就是WriteResult和SerializedFileMetaData
      • info.Data = new object[] { result, metaData };
  • 保存缓存数据
    • 和之前保存Asset和Scene的缓存数据逻辑一致cache.SaveCachedData(uncachedInfo);

缓存数据的读取和使用

  • 读取缓存数据cache.LoadCachedData(cacheEntries, out cachedInfo);
  • 直接读取缓存数据
    • item.Context.Result = (WriteResult)info.Data[0];
      item.Context.MetaData = (SerializedFileMetaData)info.Data[1];

【ArchiveAndCompressBundles】

这里生成最终的Bundle文件

没有缓存时

  • 创建ArchiveWorkItem
    • BundleName:还是之前算出来的bundleName
    • Compression:配置的压缩格式
    • OutputFilePath:Bundle文件输入路径,这个也是要配置的,是真正的文件路径,之前的只是临时路径
    • ResourceFiles:WriteData时算出来的
    • SeriliazedFileMetaDatas:WriteData时算出来的
  • 执行ArchiveWorkItem,不考虑多线程,实际写文件在ArchiveSingleItem
    • 文件先写到tempOutputFolder文件夹
      • SerializedFile文件也是先写入到这个文件夹
    • 调用ContentBuildInterface.ArchiveAndCompress得到bundle文件,返回该文件的Crc
    • 得到BundleDetails,这就是BuildIn模式的Manifest:
      • item.ResultDetails.FileName = item.OutputFilePath;
      • CRC
    • 将文件从tempOutputFolder复制到OutputFilePath
  • 后处理PostArchiveProcessing,主要是计算BundleDetails的Dependencies和Hash
    • Dependencies 算出来这个Bundle依赖的其他Bundle
    • Hash 根据依赖算Hash

缓存数据获取和保存

  • GetCacheEntry
  • GetCachedInfo
    • 定义的Data是BundleDetails
  • SaveCachedData(保存在"Library/BuildCache"文件夹中)

缓存数据读取和使用

  • GetCacheEntry
  • LoadCachedData
    • 通过计算的CacheEntry从缓存的CacheInfo中找到
  • 筛选出 cachedItems和nonCachedItems
  • 计算缓存文件路径并拷贝CopyingCachedFiles

【GenerateLocationListsTask】

这个Task目的是为Addressable创建寻址信息,在Addressable中每个Bundle、Asset都会有一个用于寻址的Location,上层加载传入路径,根据路径找到Location,根据Location找到Bundle、Asset。在Catalog中,Bundle和Asset的相关信息保存在ContentCatalogDataEntry

该Task可以改为多线程的

public class ContentCatalogDataEntry
{/// <summary>/// Internl id./// </summary>public string InternalId { get; set; }/// <summary>/// IResourceProvider identifier./// </summary>public string Provider { get; private set; }/// <summary>/// Keys for this location./// </summary>public List<object> Keys { get; private set; }/// <summary>/// Dependency keys./// </summary>public List<object> Dependencies { get; private set; }/// <summary>/// Serializable data for the provider./// </summary>public object Data { get; set; }/// <summary>/// The type of the resource for th location./// </summary>public Type ResourceType { get; private set; }
}
  • 创建 BundleEntry,每个Bundle对应一个BundleEntry
    • 计算包含的List<GUID> Assets :从WriteData.AssetToFiles和WriteData.FileToBundle可以得到每个bundle包含的Asset
    • 计算依赖的bundle HashSet<BundleEntry> Dependencies :WriteData.AssetToFiles其他File对应的bundle就是依赖的bundle
    • 计算其他依赖HashSet<BundleEntry> ExpandedDependencies :上面计算的是直接依赖,这里一直找到所有依赖
    • 指定AddressableAssetGroup Group:从aaContext.bundleToAssetGroup中找到该bundle对应的Group
  • 创建Bundle的ContentCatalogDataEntry
    • string InternalId 运行时加载的路径,对于bundle可能是本地路径或者是网络路径
    • string Provider 加载方法位于哪个类中
    • Type ResourceType:这个加载路径对应的资源类型
    • key只有BundleName
    • 没有Dependencies
  • 创建每个资源的ContentCatalogDataEntry:Calculate Locations
    • 创建该Asset的KeyList:CreateKeyList
      • 从Group的配置中,看KeyList是否要包含该Asset的address、guid、labels
    • Type ResourceType获取该资源运行时的类型
      • 对于Scene: Type runtimeProvider = GetRuntimeProviderType(providerType, mainType);
      • 对于Asset
        • 根据从该AddressableAssetEntry的guid从DependencyData.AssetInfo中找到includedObjects
        • 找到每个Object的Type:ContentBuildInterface.GetTypeForObjects
        • 再转为运行时的Type:rtType = AddressableAssetUtility.MapEditorTypeToRuntimeType(objType, false)
    • string InternalId 计算运行时从bundle中加载的路径
      • string assetPath = GetAssetLoadPath(isBundled, assetsInBundle);
    • HashSet<BundleEntry> ExpandedDependencies:
      • 其所在bundle的所有其他依赖
    •  string Provider
      • 从Group中得到 string assetProvider = GetAssetProviderName(bEntry.Group);
    • object Data 为空
  • 得到输出
    • 每个Bundle和bundle中每个资源的ContentCatalogDataEntry放入aaContext.locations
    • 每个AddressableAssetGroup对应的所有bunlde放入aaContext.assetGroupToBundles
    • bundle和asset对应的Provider放入aaContext.providerTypes
    • 每个Bundle的直接依赖放入aaContext.bundleToExpandedBundleDependencies
    • 每个Bundle的间接依赖放入aaContext.bundleToExpandedBundleDependencies

【Post Processing AssetBundles】

这里可以作为一个Task,但被Unity拿了出来,完全可以放到GenerateLocationListsTask中。这个Task的目的是为了继续补全ContentCatalogDataEntry

  • ContentCatalogDataEntry的KeyList中,第一个Key是primaryKey
  • 从aaContext.locations可以建立primaryKeyToCatalogEntryDic
  • Bundle的ContentCatalogDataEntry的Data是AssetBundleRequestOptions(这里的Data可以自定义,Unity提供的有很多冗余信息)
    • Crc:看Group的配置是否用,如果用,则从之前计算的BundleDetails中获取
    • UseCrcForCachedBundle:If false, the CRC will not be used when loading bundles from the cache.
    • UseUnityWebRequestForLocalBundles:If true, UnityWebRequest will be used even if the bundle is stored locally
    • Hash:看Group的配置是否用,如果用,则从之前计算的BundleDetails中获取
    • ChunkedTransfer
    • RedirectLimit
    • RetryCount
    • Timeout
    • BundleName
    • AssetLoadMode
    • BundleSize
    • ClearOtherCachedVersionsWhenLoaded
  • 重建输出的bundle的名字
    • ConstructAssetBundleName
  • 修改加载依赖
    • 修改bundle的InternalId和primaryKey
    • 修改Asset的依赖
      • 利用从aaContext.locations.Dependencies可以建立每个依赖在locations的索引和Dependencies的索引Dictionary<string, List<int[]>>来加速

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/813241.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DNF手游攻略:2024新手攻略大全

在《DNF手游》的世界中&#xff0c;前期阶段对于新手玩家来说至关重要。以下是一份综合整理的新手攻略&#xff0c;帮助玩家快速适应游戏并取得进展。 1. 角色建立策略&#xff1a; 在前期&#xff0c;建议玩家建立3个角色&#xff0c;包括1个大号和2个小号。大号可以根据个人喜…

Vue3常见核心面试题(之二)

Q1&#xff1a;Vue3如何实现全局状态管理&#xff1f; A1: Vue3中使用provide&#xff08;&#xff09;和 inject()函数来实现全局状态管理 Q2&#xff1a;Vue3中的ref指令有哪些用途&#xff1f; A2&#xff1a;Vue3中的ref指令可以用来在组件内获取子组件的实例&#xff0c…

谷歌google浏览器无法更新Chrome至最新版本怎么办?浏览器Chrome无法更新至最新版本

打开谷歌google浏览器提示&#xff1a;无法更新Chrome&#xff0c;Chrome无法更新至最新版本&#xff0c;因此您未能获得最新的功能和安全修复程序。点击「重新安装Chrome」后无法访问此网站&#xff0c;造成谷歌浏览器每天提示却无法更新Chrome至最新版本。 谷歌google浏览器无…

SaaS知识库哪些比较好用?中小企业也能适用

在快节奏的商业世界中&#xff0c;拥有一个高效、易于使用的知识管理工具是提升工作效率的关键。对于中小企业来说&#xff0c;选择合适的SaaS&#xff08;软件即服务&#xff09;知识库平台尤为重要&#xff0c;因为它不仅能帮助员工快速找到信息&#xff0c;而且还能优化客户…

C语言运行时隐藏控制台

#include <windows.h> int main() {// 获取控制台窗口句柄HWND hwnd GetConsoleWindow();// 隐藏控制台窗口ShowWindow(hwnd, SW_HIDE);while (1){/* code */}return 0; }编译后运行&#xff0c;什么都没看到&#xff0c;打开任务管理器&#xff0c;在进程里能找到它。

数据结构进阶之堆

今天我们学习的是数据结构里面的堆&#xff0c;大家先看看我们今天要学习的内容 一、堆概念及认识 在学习堆之前我们得先明白完全二叉树是什么样子&#xff0c;因为堆是依据完全二叉树的结构来实现的&#xff0c;所以在这里我先告诉大家完全二叉树的是什么&#xff0c;如下图…

Excel中输入数字会改变怎么办?

一、数字显示不全&#xff0c;以“#”号代替 随着列宽的缩小&#xff0c;数字逐渐被“#”号代替&#xff08;首先数字的格式是“数值型&#xff0c;且只有整数”&#xff09; 原因分析&#xff1a;单元格中的数字无法完全显示&#xff0c;Excel会自动用“#”号填充剩余的空间 解…

00_如何使用国内镜像源下载QT

如何使用国内镜像源下载QT 如何使用国内镜像源下载QT 如何使用国内镜像源下载QT 第一步&#xff1a;下载下载qt online installer 网站&#xff1a;https://download.qt.io/official_releases/online_installers/ 添加链接描述 下载windows版本 第二步&#xff1a; 剪切放…

【LeetCode热题100】【链表】两数相加

题目链接&#xff1a;2. 两数相加 - 力扣&#xff08;LeetCode&#xff09; 基本思路同&#xff1a;【leetcode】大数相加-CSDN博客 数值的位置已经倒过来了&#xff0c;用一个进位记录进位&#xff0c;用一个数记录和&#xff0c;链表到空了就当成0 class Solution { publi…

搭建个人智能家居 4 -WS2812B-RGB灯

搭建个人智能家居 4 - WS2812B-RGB灯 前言说明ESPHomeHomeAssistant 前言 上一篇文章我们已经完成了第一个外设的添加&#xff08;一个LED灯&#xff09;&#xff0c;今天接着来“壮大”这个系统&#xff0c;添加第二个外设“RGB灯”。 环境搭建可以回顾前面的文章。前文回顾&…

Vue 的父组件和子组件生命周期钩子函数执行顺序

Vue 的父组件和子组件生命周期钩子函数执行顺序 1. 加载渲染过程 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted 2. 子组件更新过程 父 beforeUpdate -> 子 bef…

AutoCAD 2024 安装注册教程

前言 大家好&#xff0c;我是梁国庆。 本篇分享的安装包是 AutoCAD 的全新版本——AutoCAD 2024&#xff0c;下文安装教程中简称 AutoCAD。 时间&#xff1a;2024年4月8日。 获取 AutoCAD 安装包 我已将本篇所使用的安装包打包上传至百度云&#xff0c;扫描下方二维码关注…

【通过虚拟现实:让我们对危险更敏感】

在科技日新月异的今天&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐从科幻走向现实&#xff0c;成为推动各行业发展的重要动力。除了应用在游戏、影视以及终端交互等娱乐文化行业中&#xff0c;VR技术在高危行业中更是开辟了一片新天地。从虚拟现实数据中得出的…

Linux 内核学习(1) --- 时钟子系统

标题 时钟系统说明时钟树Clock Provider时钟通用数据结构clock_device 的注册clock_provider DTS配置和注册clock consumer时钟系统总结 时钟系统说明 时钟就是 SoC 中的脉搏&#xff0c;由它来控制各个部件按各自的节奏跳动。比如&#xff0c;CPU主频设置&#xff0c;串口的波…

windows本地运行dreamtalk踩坑总结

dreamtalk是一个语音图片转视频的一个工具&#xff0c;就是给一段语音加一个头像图片&#xff0c;然后生成一段头像跟语音对口型的视频&#xff0c;其实还是很有意思的&#xff0c;最近阿里发布了一个类似的模型&#xff0c;但是还没开源&#xff0c;从展示视频看&#xff0c;阿…

itext7 pdf转图片

https://github.com/thombrink/itext7.pdfimage 新建asp.net core8项目&#xff0c;安装itext7和system.drawing.common 引入itext.pdfimage核心代码 imageListener下有一段不安全的代码 unsafe{for (int y 0; y < image.Height; y){byte* ptrMask (byte*)bitsMask.Scan…

Centos 7.9.2009 下 Gitlab 完全卸载

一、linux版本&#xff1a;lsb_release -a 二、GtiLab 版本 # 查看gitlab的版本号 cat /opt/gitlab/embedded/service/gitlab-rails/VERSION 三、开始卸载 3.1&#xff0c;停止Gitlab 相关服务 # 停止所有GitLab相关服务&#xff1a; sudo gitlab-ctl stop# 移除GitLab包…

【2024年MathorCup数模竞赛】C题完整解析(代码与技术文档)

C题第一问 1 数据预处理2 问题一2.1基于混合ARIMA-LSTM预测模型的未来30天货量预测2.1.1 自适应混合ARIMA-LSTM混合预测模型的建立2.1.2 自适应混合ARIMA-LSTM混合预测模型的求解 2.2 基于混合ARIMA-LSTM预测模型与模糊修正的未来30天每小时货量预测 代码分享 目前已经完成C题数…

如何利用python机器学习解决空间模拟与时间预测问题

徐老师&#xff1a;副教授&#xff1a;长期从事定量遥感、遥感数据同化、地表水热通量转化等相关领域的研究&#xff0c;发表多篇相关领域核心期刊论文&#xff0c;具有丰富的实践技术经验。 专题一、机器学习原理与概述 了解机器学习的发展历史、计算原理、基本定义&#xf…

vue快速入门(二十一)计算属性

注释很详细&#xff0c;直接上代码 上一篇 新增内容 计算属性的基本应用 源码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.…