unity3d:YooAsset零冗余构建Assetbundle代码分析

news2024/11/24 11:37:25

BuildAssetInfo构建asset信息

1.每个收集器下asset会构建出BuildAssetInfo,这种asset是没有冗余,只有依赖列表
2.每个依赖asset会构建出BuildAssetInfo,会记录将要打入的bundle列表

依赖的Asset列表

这个asset依赖的其他asset列表,只对收集器资源有效

		/// <summary>
		/// 依赖的所有资源
		/// 注意:包括零依赖资源和冗余资源(资源包名无效)
		/// </summary>
		public List<BuildAssetInfo> AllDependAssetInfos { private set; get; }

列表信息从何来?
在创建收集器资源调用依赖

YooAsset.Editor.AssetBundleCollector.GetAllDependencies

private List<string> GetAllDependencies(string mainAssetPath)
{
	string[] depends = AssetDatabase.GetDependencies(mainAssetPath, true);
	List<string> result = new List<string>(depends.Length);
	foreach (string assetPath in depends)
	{
		if (IsValidateAsset(assetPath, false))
		{
			// 注意:排除主资源对象
			if (assetPath != mainAssetPath)
				result.Add(assetPath);
		}
	}
	return result;
}

预计会被打入的Bundle列表

HashSet< string> _referenceBundleNames
在处理数据时,如果一个依赖asset会被打入多个bundle,在这里记录,则视为冗余asset
这个bundle列表如何得到?
在遍历收集器资源依赖资源时,依赖资源add主资源的Bundle名
在最后处理冗余时,如果列表数量>2,则依赖asset生成独立bundle

BuildBundleInfo构建bundle信息

一个bundle会包含多个asset

主asset列表

/// <summary>
		/// 参与构建的资源列表
		/// 注意:不包含零依赖资源和冗余资源
		/// </summary>
		public readonly List<BuildAssetInfo> AllMainAssets = new List<BuildAssetInfo>();

1.普通bundle包,里面只有收集器asset,不会包含依赖asset。在构建时unity自动收集依赖进入bundle
2.共享bundle包,里面只有依赖asset

依赖asset列表

每个BuildAssetInfo又会包含List< BuildAssetInfo> AllDependAssetInfos,依赖资源列表

CollectAssetInfo收集器的asset

CollectAssetInfo是记录asset需要打入的bundle,和这个asset依赖的asset列表

asset的依赖列表

/// <summary>
		/// 依赖的资源列表
		/// </summary>
		public List<string> DependAssets = new List<string>();

如何得到
在创建CreateCollectAssetInfo时
YooAsset.Editor.AssetBundleCollector.CreateCollectAssetInfo
YooAsset.Editor.AssetBundleCollector.GetAllDependencies
调用AssetDatabase.GetDependencies,得到依赖列表

收集器Package,Group关系

package 的收集器资源
YooAsset.Editor.AssetBundleCollectorPackage.GetAllCollectAssets
收集器组
YooAsset.Editor.AssetBundleCollectorGroup.GetAllCollectAssets
一个收集器
YooAsset.Editor.AssetBundleCollector.GetAllCollectAssets
一个收集器按照规则又会包N个Asset

获取打包收集的资源文件

YooAsset.Editor.AssetBundleCollector.GetAllCollectAssets
1.如果收集器是文件夹路径,遍历下面所有资源类型,每个单独生成CollectAssetInfo加入字典
2.如果收集器是资源路径,只把该路径生成CollectAssetInfo加入字典
3.可寻址冲突,分两种情况,同个收集器与不同收集器;是对于同一个收集器而言,asset名字冲突,例如同个收集器下多个文件夹存在同名asset。例如
在这里插入图片描述

同个收集器下,两个文件夹下都存在cube1.prefab,报错

System.Exception: The address is existed : Cube1 in collector : Assets/YooAsset/Samples/Space Shooter/GameRes/Effect 
AssetPath:
     Assets/YooAsset/Samples/Space Shooter/GameRes/Effect/Engines/Cube1.prefab
     Assets/YooAsset/Samples/Space Shooter/GameRes/Effect/Explosions/Cube1.prefab

不同收集器在最后打包也会判断可寻址是否重复

System.Exception: The address is existed : Cube1 in group : battle 
AssetPath:
     Assets/YooAsset/Samples/Space Shooter/GameRes/Effect/Engines/Cube1.prefab
     Assets/YooAsset/Samples/Space Shooter/GameRes/Entity/Cube1.prefab

两个收集器里都有Cube1
在这里插入图片描述

资源构建上下文BuildMapContext

决定哪些是asset对应的bundle
YooAsset.Editor.TaskGetBuildMap.CreateBuildMap

BuildBundleInfo字典

key为bundle的名字,路径/换成_,从assets开始
Dictionary<string, BuildBundleInfo> _bundleInfoDic
在这里插入图片描述

所有asset构建BuildAssetInfo字典

Dictionary<string, BuildAssetInfo> allBuildAssetInfoDic
key为资源路径,BuildAssetInfo为打包路径

包含收集器的资源,收集器资源的依赖列表

录入所有收集器收集的资源

遍历allCollectAssetInfos

// 4. 录入所有收集器收集的资源
			foreach (var collectAssetInfo in allCollectAssetInfos)
			{					allBuildAssetInfoDic.Add(collectAssetInfo.AssetPath, buildAssetInfo);
				}

收集器下的asset 是不会存在打入多个bundle情况

录入所有收集资源的依赖资源

只对依赖资源有效
1.遍历每一个allCollectAssetInfos.DependAssets
2.如果依赖asset未进入allBuildAssetInfoDic,则创建一个新BuildAssetInfo,它的_referenceBundleNames增加一个为收集器资源信息CollectAssetInfo的bundle,即添加关联的资源包名称
3.如果依赖asset已经存在于allBuildAssetInfoDic,说明已经被一个bundleA依赖,再添加bundleB的信息,标记为冗余资源。HashSet< string> _referenceBundleNames,这是个哈希表,如果bundleA = bundleB,不会加入

// 5. 录入所有收集资源的依赖资源
foreach (var collectAssetInfo in allCollectAssetInfos)
{
	string collectAssetBundleName = collectAssetInfo.BundleName;
	foreach (var dependAssetPath in collectAssetInfo.DependAssets)
	{
		if (allBuildAssetInfoDic.ContainsKey(dependAssetPath))
		{
			allBuildAssetInfoDic[dependAssetPath].AddBundleTags(collectAssetInfo.AssetTags);
			allBuildAssetInfoDic[dependAssetPath].AddReferenceBundleName(collectAssetBundleName);
		}
		else
		{
			var buildAssetInfo = new BuildAssetInfo(dependAssetPath);
			buildAssetInfo.AddBundleTags(collectAssetInfo.AssetTags);
			buildAssetInfo.AddReferenceBundleName(collectAssetBundleName);
			allBuildAssetInfoDic.Add(dependAssetPath, buildAssetInfo);
		}
	}
}

填充所有收集资源的依赖列表

收集资源的依赖List< BuildAssetInfo>信息,只对收集资源有效,即这个收集资源的BuildAssetInfo的依赖List< BuildAssetInfo>

计算共享冗余的bundle

计算共享包名

YooAsset.Editor.BuildAssetInfo.CalculateShareBundleName
1.如果这个资源没有收集器类型CollectorType = ECollectorType.None,说明是被依赖的,非主动收集打包的
2.如果引用次数>1,说明至少被两个bundle引用,需要设置独立bundle,为了解决独立bundle过多的问题,按照资源的目录名字作为bundle名。如果同目录下还有零散资源被重复引用,都会打入这个包中。因为是按照零冗余ZeroRedundancySharedPackRule规则构建,生成的bundle名此asset的直接文件夹路径
3.如果引用 <= 1,只被一个bundle引用,不需要打独立bundle,把他bundle置为空

public void CalculateShareBundleName(ISharedPackRule sharedPackRule, bool uniqueBundleName, string packageName, string shadersBundleName)
		{
				if (_referenceBundleNames.Count > 1)
				{
					PackRuleResult packRuleResult = sharedPackRule.GetPackRuleResult(AssetPath);
					BundleName = packRuleResult.GetShareBundleName(packageName, uniqueBundleName);
				}
				else
				{
					// 注意:被引用次数小于1的资源不需要设置资源包名称
					BundleName = string.Empty;

AB依赖C,AB在同个Bundle

例如:Cube1,Cube2在同一bundleA里,它们都依赖MatCube.mat,那么MatCube.mat会被打入bundleA
在这里插入图片描述
在这里插入图片描述

AB依赖C,AB在不同Bundle

在这里插入图片描述

这种情况下C会打入共享包
在这里插入图片描述

bundle内容为空,因为被依赖asset不会通过代码加载

记录冗余资源

计算共享报名,已经去掉了冗余资源:把冗余asset的bundle变为文件夹路径名
如果asset有bundle名,一定不是冗余
对于没有bundle名的看,是否被2个引用

移除不参与构建的资源

如果一个asset的BuildAssetInfo.bundleName为空,说明它是被收集资源依赖的,且只被一个依赖,不需要生成一个独立bundle。这个asset会被打入依赖的bundle

构建资源列表

最后相当于遍历BuildAssetInfo字典,生成BuildBundleInfo字典
BuildAssetInfo字典 是N个重复的asset 对应bundle
BuildBundleInfo,是一个bundle里会有多少asset
最后按照bundle名生成BuildBundleInfo字典

构建

YooAsset.Editor.AssetBundleBuilder.Run
构建顺序,按照order来
在这里插入图片描述

两个比较重要的,TaskGetBuildMap 构建出零冗余的bundle关系:YooAsset.Editor.TaskGetBuildMap.CreateBuildMap

TaskBuilding:BuiltinBuildPipeline下出包

YooAsset.Editor.BuildMapContext.GetPipelineBuilds
根据BuildBundleInfo字典生成Ab信息
bundle里只插入主资源,依赖asset会 被收集插入bundle

		/// <summary>
		/// 获取构建管线里需要的数据
		/// </summary>
		public UnityEditor.AssetBundleBuild[] GetPipelineBuilds()
		{
			List<UnityEditor.AssetBundleBuild> builds = new List<UnityEditor.AssetBundleBuild>(_bundleInfoDic.Count);
			foreach (var bundleInfo in _bundleInfoDic.Values)
			{
				if (bundleInfo.IsRawFile == false)
					builds.Add(bundleInfo.CreatePipelineBuild());
			}
			return builds.ToArray();
		}

AssetBundleManifest buildResults = BuildPipeline.BuildAssetBundles(pipelineOutputDirectory, buildMapContext.GetPipelineBuilds(), buildOptions, buildParametersContext.Parameters.BuildTarget);

冗余MatCube.mat如何打包示例

asset:Assets/YooAsset/Samples/Space Shooter/GameRes/Material/MatCube.mat分配bundle:assets_yooasset_samples_space shooter_gameres_effect.bundle

asset:Assets/YooAsset/Samples/Space Shooter/GameRes/Material/MatCube.mat分配bundle:assets_yooasset_samples_space shooter_gameres_entity.bundle

发现bundle列表>1,重新分配bundle名
冗余:Assets/YooAsset/Samples/Space Shooter/GameRes/Material/MatCube.mat,分配bundleshare_assets_yooasset_samples_space shooter_gameres_material.bundle

生成BuildBundleInfo
bundleshare_assets_yooasset_samples_space shooter_gameres_material.bundle:塞入asset:Assets/YooAsset/Samples/Space Shooter/GameRes/Material/MatCube.mat

生成AB;bundle:share_assets_yooasset_samples_space shooter_gameres_material.bundle,assetNames;[“Assets/YooAsset/Samples/Space Shooter/GameRes/Material/MatCube.mat”]

报告bundleshare_assets_yooasset_samples_space shooter_gameres_material.bundle:里assets:[“Assets/YooAsset/Samples/Space Shooter/GameRes/Material/MatCube.mat”]

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

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

相关文章

Tree 树结构

Case 1st 最少的摄像头——亚马逊面试问题 给定一个二叉树&#xff0c;我们在树的节点上安装摄像头。 节点上的每个摄像机都可以监视其父级、自身及其直接子级。 计算监视树的所有节点所需的最小摄像机数。 例&#xff1a; Input: [0,0,null,0,0]Output: 1Explanation: One cam…

asp.net宠物购物商城系统MyPetShop

asp.net宠物购物商城系统 在线购物网站&#xff0c;电子商务系统 主要技术&#xff1a; 基于asp.net架构和sql server数据库 功能模块&#xff1a; 用户可以购买宠物&#xff0c;查看订单记录 修改密码等 运行环境&#xff1a; 运行需vs2013或者以上版本&#xff0c;sql serv…

183 · 木材加工

链接&#xff1a;LintCode 炼码 - ChatGPT&#xff01;更高效的学习体验&#xff01; 题解&#xff1a;九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧 class Solution { public:/*** param l: Given n pieces of wood wi…

Java8 Stream详解

Stream类继承关系 前置知识 Spliterator接口使用 Spliterator是在java 8引入的一个接口&#xff0c;它通常和stream一起使用&#xff0c;用来遍历和分割序列。 只要用到stream的地方都需要Spliterator&#xff0c;比如List&#xff0c;Collection&#xff0c;IO channel等等…

大语言模型的百家齐放

基础语言模型 概念 基础语言模型是指只在大规模文本语料中进行了预训练的模型&#xff0c;未经过指令和下游任务微调、以及人类反馈等任何对齐优化。 如何理解 只包含纯粹的语言表示能力,没有指导性或特定目标。 只在大量无标注文本上进行无监督预训练,用于学习语言表示。 …

unity制作手游fps僵尸游戏

文章目录 介绍制作基本UI枚举控制角色移动切枪、设置音效、设置子弹威力、设置子弹时间间隔、换弹准星控制射击僵尸动画、血条设置导航 介绍 利用协程、枚举、动画器、导航等知识点。 实现移动、切枪、换弹、射击、僵尸追踪、攻击。 制作基本UI 制作人类血条、僵尸血条、移动按…

百度智能车竞赛丝绸之路1——智能车设计与编程实现控制

百度智能车竞赛丝绸之路1——智能车设计与编程实现控制 百度智能车竞赛丝绸之路2——手柄控制 一、项目简介 本项目现已基于鲸鱼机器人开发套件对其整体外形进行设计&#xff0c;并且对应于实习内容——以“丝绸之路”为题&#xff0c;对机器人各个功能与机器人结构部分进行相…

【几何数学】【Python】【C++】判断两条线段是否相交,若相交则求出交点坐标

判断线段是否相交的办法&#xff08;使用了向量叉积的方法&#xff09;&#xff1a; 首先&#xff0c;通过给定的线段端点坐标p1、p2、p3和p4构建了四个向量v1、v2、v3和v4&#xff1a; v1表示从p1指向p2的向量&#xff0c;其分量为[p2[0] - p1[0], p2[1] - p1[1]]。 v2表示从…

Camtasia Studio2023标准版屏幕录制和视频剪辑软件

Camtasia Studio2023提供了强大的屏幕录像、视频的剪辑和编辑、视频菜单制作、视频剧场和视频播放功能等。它能在任何颜色模式下轻松地记录屏幕动作&#xff0c;包括影像、音效、鼠标移动的轨迹&#xff0c;解说声音等等&#xff0c;另外&#xff0c;它还具有及时播放和编辑压缩…

[前端]JS——join()与split()的使用

Array.join():数组转换为字符串,"()"里元素指定数组转为字符串用什么串联&#xff0c;默认为空。 Array.join()的使用&#xff1a; <script>let arr[1,2,3,4]console.log("arr未转换前:",arr,typeof(arr));console.log("arr使用join():"…

Netty核心技术八--Netty编解码器和handler的调用机制

1.基本说明 netty的组件设计&#xff1a;Netty的主要组件有Channel、EventLoop、ChannelFuture、 ChannelHandler、ChannelPipe等 ChannelHandler充当了处理入站和出站数据的应用程序逻辑的容器。 例如&#xff0c;实现ChannelInboundHandler接口&#xff08;或ChannelInbound…

Typora图床配置-OSS对象存储

Typora图床配置-OSS对象存储 1.PicGo下载 下载地址&#xff1a; Release 2.3.0 Molunerfinn/PicGo GitHub https://github.com/Molunerfinn/PicGo/releases/tag/v2.3.1 下载如下&#xff1a; 2.安装和配置 进入阿里云创建OSS对象存储服务。 设置为公共读才能被别人访问到。…

树与图的深度优先遍历

树的重心 本题的本质是树的dfs&#xff0c; 每次dfs可以确定以u为重心的最大连通块的节点数&#xff0c;并且更新一下ans。 也就是说&#xff0c;dfs并不直接返回答案&#xff0c;而是在每次更新中迭代一次答案。 这样的套路会经常用到&#xff0c;在 树的dfs 题目中 #includ…

IMU 互补滤波

IMU学名惯性测量单元&#xff0c;所有的运动都可以分解为一个直线运动和一个旋转运动&#xff0c;故这个惯性测量单元就是测量这两种运动&#xff0c;直线运动通过加速度计可以测量&#xff0c;旋转运动则通过陀螺。 void IMUupdate(float gx, float gy, float gz, float ax,fl…

Go 语言 context 都能做什么?

原文链接&#xff1a; Go 语言 context 都能做什么&#xff1f; 很多 Go 项目的源码&#xff0c;在读的过程中会发现一个很常见的参数 ctx&#xff0c;而且基本都是作为函数的第一个参数。 为什么要这么写呢&#xff1f;这个参数到底有什么用呢&#xff1f;带着这样的疑问&am…

postgresql数据库登录代理解析(包含登录协议包解析)

文章目录 postgresql数据库登录代理解析&#xff08;包含登录协议包解析&#xff09;背景描述版本不同对应的账号密码加密目标解析方法相关代码位置断点关键位置及相关重要变量 登录通信流程&#xff08;SCRAM-SHA-256方式&#xff09;代码实现相关参考资料 postgresql数据库登…

Python count()函数详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 count 1、指定搜索位置2、参数为负数3、列表的coun…

以太网OSI参考模型(四)

目录 OSI模型 一、物理层 二、数据链路层 三、网络层 四、传输层 五、会话层 六、表示层 七、应用层 OSI模型 OSI七层模型&#xff0c;是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)1984年联合制定的开放系统互联参考模型&#xff0c;为开放式互联信息系统提供…

06-C++学习笔记-指针的定义与使用

指针是C中非常重要的概念&#xff0c;它允许直接访问内存地址&#xff0c;并通过地址操作变量。本篇笔记将介绍指针的定义与使用方法&#xff0c;以及指针与数组的关系。 1️⃣ 指针的引入 指针的引入是为了解决需要直接访问内存地址的情况。通过指针&#xff0c;可以间接访问…

Android TextView 展示特殊字符高度变高问题解决

背景 #在我们的项目中&#xff0c;展示文字是很常见的需求&#xff0c;但是在线上展示中发现&#xff0c;有些信息是特殊字符展示的&#xff0c;而且这些字符的高度会导致TextView的高度变高&#xff08;与正常字符比&#xff09;。 效果如下&#xff1a; 很明显&#xff0…