【m】框架大更新

This commit is contained in:
2025-10-31 11:18:23 +08:00
parent ae6e7c804b
commit 8e1d52ddbf
1883 changed files with 213934 additions and 640 deletions

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
public class TaskCopyBuildinFiles
{
/// <summary>
/// 拷贝首包资源文件
/// </summary>
internal void CopyBuildinFilesToStreaming(BuildParametersContext buildParametersContext, PackageManifest manifest)
{
EBuildinFileCopyOption copyOption = buildParametersContext.Parameters.BuildinFileCopyOption;
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
string buildinRootDirectory = buildParametersContext.GetBuildinRootDirectory();
string buildPackageName = buildParametersContext.Parameters.PackageName;
string buildPackageVersion = buildParametersContext.Parameters.PackageVersion;
// 清空内置文件的目录
if (copyOption == EBuildinFileCopyOption.ClearAndCopyAll || copyOption == EBuildinFileCopyOption.ClearAndCopyByTags)
{
EditorTools.ClearFolder(buildinRootDirectory);
}
// 拷贝补丁清单文件
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(buildPackageName, buildPackageVersion);
string sourcePath = $"{packageOutputDirectory}/{fileName}";
string destPath = $"{buildinRootDirectory}/{fileName}";
EditorTools.CopyFile(sourcePath, destPath, true);
}
// 拷贝补丁清单哈希文件
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(buildPackageName, buildPackageVersion);
string sourcePath = $"{packageOutputDirectory}/{fileName}";
string destPath = $"{buildinRootDirectory}/{fileName}";
EditorTools.CopyFile(sourcePath, destPath, true);
}
// 拷贝补丁清单版本文件
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(buildPackageName);
string sourcePath = $"{packageOutputDirectory}/{fileName}";
string destPath = $"{buildinRootDirectory}/{fileName}";
EditorTools.CopyFile(sourcePath, destPath, true);
}
// 拷贝文件列表(所有文件)
if (copyOption == EBuildinFileCopyOption.ClearAndCopyAll || copyOption == EBuildinFileCopyOption.OnlyCopyAll)
{
foreach (var packageBundle in manifest.BundleList)
{
string sourcePath = $"{packageOutputDirectory}/{packageBundle.FileName}";
string destPath = $"{buildinRootDirectory}/{packageBundle.FileName}";
EditorTools.CopyFile(sourcePath, destPath, true);
}
}
// 拷贝文件列表(带标签的文件)
if (copyOption == EBuildinFileCopyOption.ClearAndCopyByTags || copyOption == EBuildinFileCopyOption.OnlyCopyByTags)
{
string[] tags = buildParametersContext.Parameters.BuildinFileCopyParams.Split(';');
foreach (var packageBundle in manifest.BundleList)
{
if (packageBundle.HasTag(tags) == false)
continue;
string sourcePath = $"{packageOutputDirectory}/{packageBundle.FileName}";
string destPath = $"{buildinRootDirectory}/{packageBundle.FileName}";
EditorTools.CopyFile(sourcePath, destPath, true);
}
}
// 刷新目录
AssetDatabase.Refresh();
BuildLogger.Log($"Buildin files copy complete: {buildinRootDirectory}");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aecf05051992ad14e833529101559071
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
namespace YooAsset.Editor
{
public class TaskCreateCatalog
{
/// <summary>
/// 生成内置资源记录文件
/// </summary>
internal void CreateCatalogFile(BuildParametersContext buildParametersContext)
{
string buildinRootDirectory = buildParametersContext.GetBuildinRootDirectory();
string buildPackageName = buildParametersContext.Parameters.PackageName;
var manifestServices = buildParametersContext.Parameters.ManifestRestoreServices;
CatalogTools.CreateCatalogFile(manifestServices, buildPackageName, buildinRootDirectory);
// 刷新目录
AssetDatabase.Refresh();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cef6068e037c6904eaed386f5bc3f71a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,405 @@
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
namespace YooAsset.Editor
{
public class ManifestContext : IContextObject
{
internal PackageManifest Manifest;
}
public abstract class TaskCreateManifest
{
private readonly Dictionary<string, int> _cachedBundleIndexIDs = new Dictionary<string, int>(10000);
private readonly Dictionary<int, HashSet<string>> _cacheBundleTags = new Dictionary<int, HashSet<string>>(10000);
/// <summary>
/// 创建补丁清单文件到输出目录
/// </summary>
protected void CreateManifestFile(bool processBundleDepends, bool processBundleTags, BuildContext context)
{
var buildMapContext = context.GetContextObject<BuildMapContext>();
var buildParametersContext = context.GetContextObject<BuildParametersContext>();
var buildParameters = buildParametersContext.Parameters;
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
// 检测资源包哈希冲突
CheckBundleHashConflict(buildMapContext);
// 创建新补丁清单
PackageManifest manifest = new PackageManifest();
manifest.FileVersion = ManifestDefine.FileVersion;
manifest.EnableAddressable = buildMapContext.Command.EnableAddressable;
manifest.SupportExtensionless = buildMapContext.Command.SupportExtensionless;
manifest.LocationToLower = buildMapContext.Command.LocationToLower;
manifest.IncludeAssetGUID = buildMapContext.Command.IncludeAssetGUID;
manifest.OutputNameStyle = (int)buildParameters.FileNameStyle;
manifest.BuildBundleType = buildParameters.BuildBundleType;
manifest.BuildPipeline = buildParameters.BuildPipeline;
manifest.PackageName = buildParameters.PackageName;
manifest.PackageVersion = buildParameters.PackageVersion;
manifest.PackageNote = buildParameters.PackageNote;
manifest.AssetList = CreatePackageAssetList(buildMapContext);
manifest.BundleList = CreatePackageBundleList(buildMapContext);
// 1. 处理资源清单的资源对象
ProcessPacakgeAsset(manifest);
// 2. 处理资源包的依赖列表
if (processBundleDepends)
ProcessBundleDepends(context, manifest);
// 3. 处理资源包的标签集合
if (processBundleTags)
ProcessBundleTags(manifest);
// 4. 处理内置资源包
if (processBundleDepends)
ProcessBuiltinBundleDependency(context, manifest);
// 创建资源清单文本文件
{
string fileName = YooAssetSettingsData.GetManifestJsonFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string filePath = $"{packageOutputDirectory}/{fileName}";
ManifestTools.SerializeToJson(filePath, manifest);
BuildLogger.Log($"Create package manifest file: {filePath}");
}
// 创建资源清单二进制文件
string packageHash;
string packagePath;
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(buildParameters.PackageName, buildParameters.PackageVersion);
packagePath = $"{packageOutputDirectory}/{fileName}";
ManifestTools.SerializeToBinary(packagePath, manifest, buildParameters.ManifestProcessServices);
packageHash = HashUtility.FileCRC32(packagePath);
BuildLogger.Log($"Create package manifest file: {packagePath}");
}
// 创建资源清单哈希文件
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string filePath = $"{packageOutputDirectory}/{fileName}";
FileUtility.WriteAllText(filePath, packageHash);
BuildLogger.Log($"Create package manifest hash file: {filePath}");
}
// 创建资源清单版本文件
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(buildParameters.PackageName);
string filePath = $"{packageOutputDirectory}/{fileName}";
FileUtility.WriteAllText(filePath, buildParameters.PackageVersion);
BuildLogger.Log($"Create package manifest version file: {filePath}");
}
// 填充上下文
{
ManifestContext manifestContext = new ManifestContext();
byte[] bytesData = FileUtility.ReadAllBytes(packagePath);
manifestContext.Manifest = ManifestTools.DeserializeFromBinary(bytesData, buildParameters.ManifestRestoreServices);
context.SetContextObject(manifestContext);
}
}
/// <summary>
/// 检测资源包哈希冲突
/// </summary>
private void CheckBundleHashConflict(BuildMapContext buildMapContext)
{
// 说明:在特殊情况下,例如某些文件加密算法会导致加密后的文件哈希值冲突!
// 说明:二进制完全相同的原生文件也会冲突!
HashSet<string> guids = new HashSet<string>();
foreach (var bundleInfo in buildMapContext.Collection)
{
if (guids.Contains(bundleInfo.PackageFileHash))
{
string message = BuildLogger.GetErrorMessage(ErrorCode.BundleHashConflict, $"Bundle hash conflict : {bundleInfo.BundleName}");
throw new Exception(message);
}
else
{
guids.Add(bundleInfo.PackageFileHash);
}
}
}
/// <summary>
/// 获取资源包的依赖集合
/// </summary>
protected abstract string[] GetBundleDepends(BuildContext context, string bundleName);
/// <summary>
/// 创建资源对象列表
/// </summary>
private List<PackageAsset> CreatePackageAssetList(BuildMapContext buildMapContext)
{
List<PackageAsset> result = new List<PackageAsset>(1000);
foreach (var bundleInfo in buildMapContext.Collection)
{
var assetInfos = bundleInfo.GetAllManifestAssetInfos();
foreach (var assetInfo in assetInfos)
{
PackageAsset packageAsset = new PackageAsset();
packageAsset.Address = buildMapContext.Command.EnableAddressable ? assetInfo.Address : string.Empty;
packageAsset.AssetPath = assetInfo.AssetInfo.AssetPath;
packageAsset.AssetGUID = buildMapContext.Command.IncludeAssetGUID ? assetInfo.AssetInfo.AssetGUID : string.Empty;
packageAsset.AssetTags = assetInfo.AssetTags.ToArray();
packageAsset.TempDataInEditor = assetInfo;
result.Add(packageAsset);
}
}
// 按照AssetPath排序
result.Sort((a, b) => a.AssetPath.CompareTo(b.AssetPath));
return result;
}
/// <summary>
/// 创建资源包列表
/// </summary>
private List<PackageBundle> CreatePackageBundleList(BuildMapContext buildMapContext)
{
List<PackageBundle> result = new List<PackageBundle>(1000);
foreach (var bundleInfo in buildMapContext.Collection)
{
var packageBundle = bundleInfo.CreatePackageBundle();
result.Add(packageBundle);
}
// 按照BundleName排序
result.Sort((a, b) => a.BundleName.CompareTo(b.BundleName));
return result;
}
/// <summary>
/// 处理资源清单的资源对象列表
/// </summary>
private void ProcessPacakgeAsset(PackageManifest manifest)
{
// 注意:优先缓存资源包索引
for (int index = 0; index < manifest.BundleList.Count; index++)
{
string bundleName = manifest.BundleList[index].BundleName;
_cachedBundleIndexIDs.Add(bundleName, index);
}
// 记录资源对象所属的资源包ID
foreach (var packageAsset in manifest.AssetList)
{
var assetInfo = packageAsset.TempDataInEditor as BuildAssetInfo;
packageAsset.BundleID = GetCachedBundleIndexID(assetInfo.BundleName);
}
// 记录资源对象依赖的资源包ID集合
// 注意:依赖关系非引擎构建结果里查询!
foreach (var packageAsset in manifest.AssetList)
{
var mainAssetInfo = packageAsset.TempDataInEditor as BuildAssetInfo;
packageAsset.DependBundleIDs = GetAssetDependBundleIDs(mainAssetInfo);
}
}
/// <summary>
/// 处理资源包的依赖集合
/// </summary>
private void ProcessBundleDepends(BuildContext context, PackageManifest manifest)
{
// 查询引擎生成的资源包依赖关系,然后记录到清单
foreach (var packageBundle in manifest.BundleList)
{
int mainBundleID = GetCachedBundleIndexID(packageBundle.BundleName);
string[] dependNames = GetBundleDepends(context, packageBundle.BundleName);
List<int> dependIDs = new List<int>(dependNames.Length);
foreach (var dependName in dependNames)
{
int dependBundleID = GetCachedBundleIndexID(dependName);
if (dependBundleID != mainBundleID)
dependIDs.Add(dependBundleID);
}
// 排序并填充数据
dependIDs.Sort();
packageBundle.DependBundleIDs = dependIDs.ToArray();
}
}
/// <summary>
/// 处理资源包的标签集合
/// </summary>
private void ProcessBundleTags(PackageManifest manifest)
{
foreach (var packageBundle in manifest.BundleList)
{
packageBundle.Tags = Array.Empty<string>();
}
// 将主资源的标签信息传染给其依赖的资源包集合
foreach (var packageAsset in manifest.AssetList)
{
var assetTags = packageAsset.AssetTags;
int bundleID = packageAsset.BundleID;
CacheBundleTags(bundleID, assetTags);
if (packageAsset.DependBundleIDs != null)
{
foreach (var dependBundleID in packageAsset.DependBundleIDs)
{
CacheBundleTags(dependBundleID, assetTags);
}
}
}
// 将缓存的资源标签赋值给资源包
for (int index = 0; index < manifest.BundleList.Count; index++)
{
var packageBundle = manifest.BundleList[index];
if (_cacheBundleTags.TryGetValue(index, out var value))
{
packageBundle.Tags = value.ToArray();
}
else
{
// 注意SBP构建管线会自动剔除一些冗余资源的引用关系导致游离资源包没有被任何主资源包引用。
string warning = BuildLogger.GetErrorMessage(ErrorCode.FoundStrayBundle, $"Found stray bundle ! Bundle ID : {index} Bundle name : {packageBundle.BundleName}");
BuildLogger.Warning(warning);
}
}
}
private void CacheBundleTags(int bundleID, string[] assetTags)
{
if (_cacheBundleTags.ContainsKey(bundleID) == false)
_cacheBundleTags.Add(bundleID, new HashSet<string>());
foreach (var assetTag in assetTags)
{
if (_cacheBundleTags[bundleID].Contains(assetTag) == false)
_cacheBundleTags[bundleID].Add(assetTag);
}
}
/// <summary>
/// 获取缓存的资源包的索引ID
/// </summary>
private int GetCachedBundleIndexID(string bundleName)
{
if (_cachedBundleIndexIDs.TryGetValue(bundleName, out int value) == false)
{
throw new Exception($"Should never get here ! Not found bundle index ID : {bundleName}");
}
return value;
}
/// <summary>
/// 是否包含该资源包的索引ID
/// </summary>
private bool ContainsCachedBundleIndexID(string bundleName)
{
return _cachedBundleIndexIDs.ContainsKey(bundleName);
}
#region YOOASSET_LEGACY_DEPENDENCY
private void ProcessBuiltinBundleDependency(BuildContext context, PackageManifest manifest)
{
// 注意:初始化资源清单建立引用关系
ManifestTools.InitManifest(manifest);
// 注意:如果是可编程构建管线,需要补充内置资源包
// 注意:该步骤依赖前面的操作!
var buildResultContext = context.TryGetContextObject<TaskBuilding_SBP.BuildResultContext>();
if (buildResultContext != null)
{
ProcessBuiltinBundleReference(manifest, buildResultContext.BuiltinShadersBundleName);
ProcessBuiltinBundleReference(manifest, buildResultContext.MonoScriptsBundleName);
var buildParametersContext = context.TryGetContextObject<BuildParametersContext>();
var buildParameters = buildParametersContext.Parameters;
if (buildParameters is ScriptableBuildParameters scriptableBuildParameters)
{
if (scriptableBuildParameters.TrackSpriteAtlasDependencies)
{
// 注意:检测是否开启图集模式
// 说明:需要记录主资源对象对图集的依赖关系!
if (EditorSettings.spritePackerMode != SpritePackerMode.Disabled)
{
var buildMapContext = context.GetContextObject<BuildMapContext>();
foreach (var spriteAtlasAsset in buildMapContext.SpriteAtlasAssetList)
{
string spriteAtlasBundleName = spriteAtlasAsset.BundleName;
ProcessBuiltinBundleReference(manifest, spriteAtlasBundleName);
}
}
}
}
}
}
private void ProcessBuiltinBundleReference(PackageManifest manifest, string builtinBundleName)
{
if (string.IsNullOrEmpty(builtinBundleName))
return;
// 查询内置资源包是否存在
if (ContainsCachedBundleIndexID(builtinBundleName) == false)
return;
// 获取内置资源包
int builtinBundleID = GetCachedBundleIndexID(builtinBundleName);
var builtinPackageBundle = manifest.BundleList[builtinBundleID];
// 更新依赖资源包ID集合
HashSet<int> cacheBundleIDs = new HashSet<int>(builtinPackageBundle.ReferenceBundleIDs);
HashSet<string> tempTags = new HashSet<string>();
foreach (var packageAsset in manifest.AssetList)
{
if (cacheBundleIDs.Contains(packageAsset.BundleID))
{
if (packageAsset.DependBundleIDs.Contains(builtinBundleID) == false)
{
var tempBundleIDs = new List<int>(packageAsset.DependBundleIDs);
tempBundleIDs.Add(builtinBundleID);
packageAsset.DependBundleIDs = tempBundleIDs.ToArray();
}
foreach (var tag in packageAsset.AssetTags)
{
if (tempTags.Contains(tag) == false)
tempTags.Add(tag);
}
}
}
// 更新内置资源包的标签集合
foreach (var tag in builtinPackageBundle.Tags)
{
if (tempTags.Contains(tag) == false)
tempTags.Add(tag);
}
builtinPackageBundle.Tags = tempTags.ToArray();
}
private int[] GetAssetDependBundleIDs(BuildAssetInfo mainAssetInfo)
{
HashSet<int> result = new HashSet<int>();
int mainBundleID = GetCachedBundleIndexID(mainAssetInfo.BundleName);
foreach (var dependAssetInfo in mainAssetInfo.AllDependAssetInfos)
{
if (dependAssetInfo.HasBundleName())
{
int bundleID = GetCachedBundleIndexID(dependAssetInfo.BundleName);
if (mainBundleID != bundleID)
{
if (result.Contains(bundleID) == false)
result.Add(bundleID);
}
}
}
// 排序并返回数据
List<int> listResult = new List<int>(result);
listResult.Sort();
return listResult.ToArray();
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ee2c2f00a1d67d45adee1d5200870cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,235 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
namespace YooAsset.Editor
{
public class TaskCreateReport
{
protected void CreateReportFile(BuildParametersContext buildParametersContext, BuildMapContext buildMapContext, ManifestContext manifestContext)
{
var buildParameters = buildParametersContext.Parameters;
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
PackageManifest manifest = manifestContext.Manifest;
BuildReport buildReport = new BuildReport();
// 概述信息
{
buildReport.Summary.YooVersion = EditorTools.GetPackageManagerYooVersion();
buildReport.Summary.UnityVersion = UnityEngine.Application.unityVersion;
buildReport.Summary.BuildDate = DateTime.Now.ToString();
buildReport.Summary.BuildSeconds = BuildRunner.TotalSeconds;
buildReport.Summary.BuildTarget = buildParameters.BuildTarget;
buildReport.Summary.BuildPipeline = buildParameters.BuildPipeline;
buildReport.Summary.BuildBundleType = buildParameters.BuildBundleType;
buildReport.Summary.BuildPackageName = buildParameters.PackageName;
buildReport.Summary.BuildPackageVersion = buildParameters.PackageVersion;
buildReport.Summary.BuildPackageNote = buildParameters.PackageNote;
// 收集器配置
buildReport.Summary.UniqueBundleName = buildMapContext.Command.UniqueBundleName;
buildReport.Summary.EnableAddressable = buildMapContext.Command.EnableAddressable;
buildReport.Summary.SupportExtensionless = buildMapContext.Command.SupportExtensionless;
buildReport.Summary.LocationToLower = buildMapContext.Command.LocationToLower;
buildReport.Summary.IncludeAssetGUID = buildMapContext.Command.IncludeAssetGUID;
buildReport.Summary.AutoCollectShaders = buildMapContext.Command.AutoCollectShaders;
buildReport.Summary.IgnoreRuleName = buildMapContext.Command.IgnoreRule.GetType().FullName;
// 构建参数
buildReport.Summary.ClearBuildCacheFiles = buildParameters.ClearBuildCacheFiles;
buildReport.Summary.UseAssetDependencyDB = buildParameters.UseAssetDependencyDB;
buildReport.Summary.EnableSharePackRule = buildParameters.EnableSharePackRule;
buildReport.Summary.SingleReferencedPackAlone = buildParameters.SingleReferencedPackAlone;
buildReport.Summary.FileNameStyle = buildParameters.FileNameStyle;
buildReport.Summary.EncryptionServicesClassName = buildParameters.EncryptionServices == null ? "null" : buildParameters.EncryptionServices.GetType().FullName;
buildReport.Summary.ManifestProcessServicesClassName = buildParameters.ManifestProcessServices == null ? "null" : buildParameters.ManifestProcessServices.GetType().FullName;
buildReport.Summary.ManifestRestoreServicesClassName = buildParameters.ManifestRestoreServices == null ? "null" : buildParameters.ManifestRestoreServices.GetType().FullName;
if (buildParameters is BuiltinBuildParameters)
{
var builtinBuildParameters = buildParameters as BuiltinBuildParameters;
buildReport.Summary.CompressOption = builtinBuildParameters.CompressOption;
buildReport.Summary.DisableWriteTypeTree = builtinBuildParameters.DisableWriteTypeTree;
buildReport.Summary.IgnoreTypeTreeChanges = builtinBuildParameters.IgnoreTypeTreeChanges;
}
else if (buildParameters is ScriptableBuildParameters)
{
var scriptableBuildParameters = buildParameters as ScriptableBuildParameters;
buildReport.Summary.CompressOption = scriptableBuildParameters.CompressOption;
buildReport.Summary.DisableWriteTypeTree = scriptableBuildParameters.DisableWriteTypeTree;
buildReport.Summary.IgnoreTypeTreeChanges = scriptableBuildParameters.IgnoreTypeTreeChanges;
buildReport.Summary.WriteLinkXML = scriptableBuildParameters.WriteLinkXML;
buildReport.Summary.CacheServerHost = scriptableBuildParameters.CacheServerHost;
buildReport.Summary.CacheServerPort = scriptableBuildParameters.CacheServerPort;
buildReport.Summary.BuiltinShadersBundleName = scriptableBuildParameters.BuiltinShadersBundleName;
buildReport.Summary.MonoScriptsBundleName = scriptableBuildParameters.MonoScriptsBundleName;
}
// 构建结果
buildReport.Summary.AssetFileTotalCount = buildMapContext.AssetFileCount;
buildReport.Summary.MainAssetTotalCount = GetMainAssetCount(manifest);
buildReport.Summary.AllBundleTotalCount = GetAllBundleCount(manifest);
buildReport.Summary.AllBundleTotalSize = GetAllBundleSize(manifest);
buildReport.Summary.EncryptedBundleTotalCount = GetEncryptedBundleCount(manifest);
buildReport.Summary.EncryptedBundleTotalSize = GetEncryptedBundleSize(manifest);
}
// 资源对象列表
buildReport.AssetInfos = new List<ReportAssetInfo>(manifest.AssetList.Count);
foreach (var packageAsset in manifest.AssetList)
{
var mainBundle = manifest.BundleList[packageAsset.BundleID];
ReportAssetInfo reportAssetInfo = new ReportAssetInfo();
reportAssetInfo.Address = packageAsset.Address;
reportAssetInfo.AssetPath = packageAsset.AssetPath;
reportAssetInfo.AssetTags = packageAsset.AssetTags;
reportAssetInfo.AssetGUID = AssetDatabase.AssetPathToGUID(packageAsset.AssetPath);
reportAssetInfo.MainBundleName = mainBundle.BundleName;
reportAssetInfo.MainBundleSize = mainBundle.FileSize;
reportAssetInfo.DependAssets = GetAssetDependAssets(buildMapContext, mainBundle.BundleName, packageAsset.AssetPath);
reportAssetInfo.DependBundles = GetAssetDependBundles(manifest, packageAsset);
buildReport.AssetInfos.Add(reportAssetInfo);
}
// 资源包列表
buildReport.BundleInfos = new List<ReportBundleInfo>(manifest.BundleList.Count);
foreach (var packageBundle in manifest.BundleList)
{
ReportBundleInfo reportBundleInfo = new ReportBundleInfo();
reportBundleInfo.BundleName = packageBundle.BundleName;
reportBundleInfo.FileName = packageBundle.FileName;
reportBundleInfo.FileHash = packageBundle.FileHash;
reportBundleInfo.FileCRC = packageBundle.FileCRC;
reportBundleInfo.FileSize = packageBundle.FileSize;
reportBundleInfo.Encrypted = packageBundle.Encrypted;
reportBundleInfo.Tags = packageBundle.Tags;
reportBundleInfo.DependBundles = GetBundleDependBundles(manifest, packageBundle);
reportBundleInfo.ReferenceBundles = GetBundleReferenceBundles(manifest, packageBundle);
reportBundleInfo.BundleContents = GetBundleContents(buildMapContext, packageBundle.BundleName);
buildReport.BundleInfos.Add(reportBundleInfo);
}
// 其它资源列表
buildReport.IndependAssets = new List<ReportIndependAsset>(buildMapContext.IndependAssets);
// 序列化文件
string fileName = YooAssetSettingsData.GetBuildReportFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string filePath = $"{packageOutputDirectory}/{fileName}";
BuildReport.Serialize(filePath, buildReport);
BuildLogger.Log($"Create build report file: {filePath}");
}
/// <summary>
/// 获取资源对象依赖的其它所有资源
/// </summary>
private List<AssetInfo> GetAssetDependAssets(BuildMapContext buildMapContext, string bundleName, string assetPath)
{
List<AssetInfo> result = new List<AssetInfo>();
var bundleInfo = buildMapContext.GetBundleInfo(bundleName);
var assetInfo = bundleInfo.GetPackAssetInfo(assetPath);
foreach (var dependAssetInfo in assetInfo.AllDependAssetInfos)
{
result.Add(dependAssetInfo.AssetInfo);
}
result.Sort();
return result;
}
/// <summary>
/// 获取资源对象依赖的资源包集合
/// </summary>
private List<string> GetAssetDependBundles(PackageManifest manifest, PackageAsset packageAsset)
{
List<string> dependBundles = new List<string>(packageAsset.DependBundleIDs.Length);
foreach (int index in packageAsset.DependBundleIDs)
{
string dependBundleName = manifest.BundleList[index].BundleName;
dependBundles.Add(dependBundleName);
}
dependBundles.Sort();
return dependBundles;
}
/// <summary>
/// 获取资源包依赖的资源包集合
/// </summary>
private List<string> GetBundleDependBundles(PackageManifest manifest, PackageBundle packageBundle)
{
List<string> dependBundles = new List<string>(packageBundle.DependBundleIDs.Length);
foreach (int index in packageBundle.DependBundleIDs)
{
string dependBundleName = manifest.BundleList[index].BundleName;
dependBundles.Add(dependBundleName);
}
dependBundles.Sort();
return dependBundles;
}
/// <summary>
/// 获取引用该资源包的资源包集合
/// </summary>
private List<string> GetBundleReferenceBundles(PackageManifest manifest, PackageBundle packageBundle)
{
List<string> referenceBundles = new List<string>(packageBundle.ReferenceBundleIDs.Count);
foreach (int index in packageBundle.ReferenceBundleIDs)
{
string dependBundleName = manifest.BundleList[index].BundleName;
referenceBundles.Add(dependBundleName);
}
referenceBundles.Sort();
return referenceBundles;
}
/// <summary>
/// 获取资源包内部所有资产
/// </summary>
private List<AssetInfo> GetBundleContents(BuildMapContext buildMapContext, string bundleName)
{
var bundleInfo = buildMapContext.GetBundleInfo(bundleName);
List<AssetInfo> result = bundleInfo.GetBundleContents();
result.Sort();
return result;
}
private int GetMainAssetCount(PackageManifest manifest)
{
return manifest.AssetList.Count;
}
private int GetAllBundleCount(PackageManifest manifest)
{
return manifest.BundleList.Count;
}
private long GetAllBundleSize(PackageManifest manifest)
{
long fileBytes = 0;
foreach (var packageBundle in manifest.BundleList)
{
fileBytes += packageBundle.FileSize;
}
return fileBytes;
}
private int GetEncryptedBundleCount(PackageManifest manifest)
{
int fileCount = 0;
foreach (var packageBundle in manifest.BundleList)
{
if (packageBundle.Encrypted)
fileCount++;
}
return fileCount;
}
private long GetEncryptedBundleSize(PackageManifest manifest)
{
long fileBytes = 0;
foreach (var packageBundle in manifest.BundleList)
{
if (packageBundle.Encrypted)
fileBytes += packageBundle.FileSize;
}
return fileBytes;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 869f8e34d5e3221428dc9016adf1d2b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,50 @@
using System;
using System.Linq;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset.Editor
{
public class TaskEncryption
{
/// <summary>
/// 加密文件
/// </summary>
public void EncryptingBundleFiles(BuildParametersContext buildParametersContext, BuildMapContext buildMapContext)
{
var encryptionServices = buildParametersContext.Parameters.EncryptionServices;
if (encryptionServices == null)
return;
if (encryptionServices.GetType() == typeof(EncryptionNone))
return;
int progressValue = 0;
string pipelineOutputDirectory = buildParametersContext.GetPipelineOutputDirectory();
foreach (var bundleInfo in buildMapContext.Collection)
{
EncryptFileInfo fileInfo = new EncryptFileInfo();
fileInfo.BundleName = bundleInfo.BundleName;
fileInfo.FileLoadPath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
var encryptResult = encryptionServices.Encrypt(fileInfo);
if (encryptResult.Encrypted)
{
string filePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}.encrypt";
FileUtility.WriteAllBytes(filePath, encryptResult.EncryptedData);
bundleInfo.EncryptedFilePath = filePath;
bundleInfo.Encrypted = true;
BuildLogger.Log($"Bundle file encryption complete: {filePath}");
}
else
{
bundleInfo.Encrypted = false;
}
// 进度条
EditorTools.DisplayProgressBar("Encrypting bundle", ++progressValue, buildMapContext.Collection.Count);
}
EditorTools.ClearProgressBar();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f269175a60e227428b7029f09e2578e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,241 @@
using System;
using System.IO;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
namespace YooAsset.Editor
{
public class TaskGetBuildMap
{
/// <summary>
/// 生成资源构建上下文
/// </summary>
public BuildMapContext CreateBuildMap(bool simulateBuild, BuildParameters buildParameters)
{
BuildMapContext context = new BuildMapContext();
var packageName = buildParameters.PackageName;
Dictionary<string, BuildAssetInfo> allBuildAssetInfos = new Dictionary<string, BuildAssetInfo>(1000);
// 1. 获取所有收集器收集的资源
bool useAssetDependencyDB = buildParameters.UseAssetDependencyDB;
var collectResult = AssetBundleCollectorSettingData.Setting.BeginCollect(packageName, simulateBuild, useAssetDependencyDB);
List<CollectAssetInfo> allCollectAssets = collectResult.CollectAssets;
// 2. 剔除未被引用的依赖项资源
RemoveZeroReferenceAssets(context, allCollectAssets);
// 3. 录入所有收集器主动收集的资源
foreach (var collectAssetInfo in allCollectAssets)
{
if (allBuildAssetInfos.ContainsKey(collectAssetInfo.AssetInfo.AssetPath))
{
throw new Exception($"Should never get here !");
}
if (collectAssetInfo.CollectorType != ECollectorType.MainAssetCollector)
{
if (collectAssetInfo.AssetTags.Count > 0)
{
collectAssetInfo.AssetTags.Clear();
string warning = BuildLogger.GetErrorMessage(ErrorCode.RemoveInvalidTags, $"Remove asset tags that don't work, see the asset collector type : {collectAssetInfo.AssetInfo.AssetPath}");
BuildLogger.Warning(warning);
}
}
var buildAssetInfo = new BuildAssetInfo(collectAssetInfo.CollectorType, collectAssetInfo.BundleName, collectAssetInfo.Address, collectAssetInfo.AssetInfo);
buildAssetInfo.AddAssetTags(collectAssetInfo.AssetTags);
allBuildAssetInfos.Add(collectAssetInfo.AssetInfo.AssetPath, buildAssetInfo);
}
// 4. 录入所有收集资源依赖的其它资源
foreach (var collectAssetInfo in allCollectAssets)
{
string bundleName = collectAssetInfo.BundleName;
foreach (var dependAsset in collectAssetInfo.DependAssets)
{
if (allBuildAssetInfos.TryGetValue(dependAsset.AssetPath, out var value))
{
value.AddReferenceBundleName(bundleName);
}
else
{
var buildAssetInfo = new BuildAssetInfo(dependAsset);
buildAssetInfo.AddReferenceBundleName(bundleName);
allBuildAssetInfos.Add(dependAsset.AssetPath, buildAssetInfo);
}
}
}
// 5. 填充所有收集资源的依赖列表
foreach (var collectAssetInfo in allCollectAssets)
{
var dependAssetInfos = new List<BuildAssetInfo>(collectAssetInfo.DependAssets.Count);
foreach (var dependAsset in collectAssetInfo.DependAssets)
{
if (allBuildAssetInfos.TryGetValue(dependAsset.AssetPath, out BuildAssetInfo value))
dependAssetInfos.Add(value);
else
throw new Exception("Should never get here !");
}
allBuildAssetInfos[collectAssetInfo.AssetInfo.AssetPath].SetDependAssetInfos(dependAssetInfos);
}
// 6. 自动收集所有依赖的着色器
if (collectResult.Command.AutoCollectShaders)
{
// 获取着色器打包规则结果
PackRuleResult shaderPackRuleResult = DefaultPackRule.CreateShadersPackRuleResult();
string shaderBundleName = shaderPackRuleResult.GetBundleName(collectResult.Command.PackageName, collectResult.Command.UniqueBundleName);
foreach (var buildAssetInfo in allBuildAssetInfos.Values)
{
if (buildAssetInfo.CollectorType == ECollectorType.None)
{
if (buildAssetInfo.AssetInfo.IsShaderAsset())
{
buildAssetInfo.SetBundleName(shaderBundleName);
}
}
}
}
// 7. 计算共享资源的包名
if (buildParameters.EnableSharePackRule)
{
PreProcessPackShareBundle(buildParameters, collectResult.Command, allBuildAssetInfos);
foreach (var buildAssetInfo in allBuildAssetInfos.Values)
{
if (buildAssetInfo.HasBundleName() == false)
{
ProcessingPackShareBundle(buildParameters, collectResult.Command, buildAssetInfo);
}
}
PostProcessPackShareBundle(buildParameters, collectResult.Command, allBuildAssetInfos);
}
// 8. 记录关键信息
context.AssetFileCount = allBuildAssetInfos.Count;
context.Command = collectResult.Command;
// 9. 移除不参与构建的资源
List<BuildAssetInfo> removeBuildList = new List<BuildAssetInfo>();
foreach (var buildAssetInfo in allBuildAssetInfos.Values)
{
if (buildAssetInfo.HasBundleName() == false)
removeBuildList.Add(buildAssetInfo);
}
foreach (var removeValue in removeBuildList)
{
allBuildAssetInfos.Remove(removeValue.AssetInfo.AssetPath);
}
// 10. 构建资源列表
var allPackAssets = allBuildAssetInfos.Values.ToList();
if (allPackAssets.Count == 0)
{
string message = BuildLogger.GetErrorMessage(ErrorCode.PackAssetListIsEmpty, "The pack asset info is empty !");
throw new Exception(message);
}
foreach (var assetInfo in allPackAssets)
{
context.PackAsset(assetInfo);
}
return context;
}
private void RemoveZeroReferenceAssets(BuildMapContext context, List<CollectAssetInfo> allCollectAssets)
{
// 1. 检测依赖资源收集器是否存在
if (allCollectAssets.Exists(x => x.CollectorType == ECollectorType.DependAssetCollector) == false)
return;
// 2. 获取所有主资源的依赖资源集合
HashSet<string> allDependAsset = new HashSet<string>();
foreach (var collectAsset in allCollectAssets)
{
var collectorType = collectAsset.CollectorType;
if (collectorType == ECollectorType.MainAssetCollector || collectorType == ECollectorType.StaticAssetCollector)
{
foreach (var dependAsset in collectAsset.DependAssets)
{
if (allDependAsset.Contains(dependAsset.AssetPath) == false)
allDependAsset.Add(dependAsset.AssetPath);
}
}
}
// 3. 找出所有零引用的依赖资源集合
List<CollectAssetInfo> removeList = new List<CollectAssetInfo>();
foreach (var collectAssetInfo in allCollectAssets)
{
var collectorType = collectAssetInfo.CollectorType;
if (collectorType == ECollectorType.DependAssetCollector)
{
if (allDependAsset.Contains(collectAssetInfo.AssetInfo.AssetPath) == false)
removeList.Add(collectAssetInfo);
}
}
// 4. 移除所有零引用的依赖资源
foreach (var removeValue in removeList)
{
string warning = BuildLogger.GetErrorMessage(ErrorCode.FoundUndependedAsset, $"Found undepended asset and remove it : {removeValue.AssetInfo.AssetPath}");
BuildLogger.Warning(warning);
var independAsset = new ReportIndependAsset();
independAsset.AssetPath = removeValue.AssetInfo.AssetPath;
independAsset.AssetGUID = removeValue.AssetInfo.AssetGUID;
independAsset.AssetType = removeValue.AssetInfo.AssetType.ToString();
independAsset.FileSize = FileUtility.GetFileSize(removeValue.AssetInfo.AssetPath);
context.IndependAssets.Add(independAsset);
allCollectAssets.Remove(removeValue);
}
}
#region
/// <summary>
/// 共享资源打包前置处理
/// </summary>
protected virtual void PreProcessPackShareBundle(BuildParameters buildParameters, CollectCommand command, Dictionary<string, BuildAssetInfo> allBuildAssetInfos)
{
}
/// <summary>
/// 共享资源打包机制
/// </summary>
protected virtual void ProcessingPackShareBundle(BuildParameters buildParameters, CollectCommand command, BuildAssetInfo buildAssetInfo)
{
PackRuleResult packRuleResult = GetShareBundleName(buildAssetInfo);
if (packRuleResult.IsValid() == false)
return;
// 处理单个引用的共享资源
if (buildAssetInfo.GetReferenceBundleCount() <= 1)
{
if (buildParameters.SingleReferencedPackAlone == false)
return;
}
// 设置共享资源包名
string shareBundleName = packRuleResult.GetShareBundleName(command.PackageName, command.UniqueBundleName);
buildAssetInfo.SetBundleName(shareBundleName);
}
private PackRuleResult GetShareBundleName(BuildAssetInfo buildAssetInfo)
{
string bundleName = Path.GetDirectoryName(buildAssetInfo.AssetInfo.AssetPath);
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
return result;
}
/// <summary>
/// 共享资源打包后置处理
/// </summary>
protected virtual void PostProcessPackShareBundle(BuildParameters buildParameters, CollectCommand command, Dictionary<string, BuildAssetInfo> allBuildAssetInfos)
{
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b0ea8b7c5a6b8ee4dabc4ccfd1516fc5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
using System;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
namespace YooAsset.Editor
{
public abstract class TaskUpdateBundleInfo
{
public void UpdateBundleInfo(BuildContext context)
{
var buildParametersContext = context.GetContextObject<BuildParametersContext>();
var buildMapContext = context.GetContextObject<BuildMapContext>();
string pipelineOutputDirectory = buildParametersContext.GetPipelineOutputDirectory();
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
int outputNameStyle = (int)buildParametersContext.Parameters.FileNameStyle;
// 1.检测文件名长度
foreach (var bundleInfo in buildMapContext.Collection)
{
// NOTE检测文件名长度不要超过260字符。
string fileName = bundleInfo.BundleName;
if (fileName.Length >= 260)
{
string message = BuildLogger.GetErrorMessage(ErrorCode.CharactersOverTheLimit, $"Bundle file name character count exceeds limit : {fileName}");
throw new Exception(message);
}
}
// 2.更新构建输出的文件路径
foreach (var bundleInfo in buildMapContext.Collection)
{
bundleInfo.BuildOutputFilePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
if (bundleInfo.Encrypted)
bundleInfo.PackageSourceFilePath = bundleInfo.EncryptedFilePath;
else
bundleInfo.PackageSourceFilePath = bundleInfo.BuildOutputFilePath;
}
// 3.更新文件其它信息
foreach (var bundleInfo in buildMapContext.Collection)
{
bundleInfo.PackageUnityHash = GetUnityHash(bundleInfo, context);
bundleInfo.PackageUnityCRC = GetUnityCRC(bundleInfo, context);
bundleInfo.PackageFileHash = GetBundleFileHash(bundleInfo, buildParametersContext);
bundleInfo.PackageFileCRC = GetBundleFileCRC(bundleInfo, buildParametersContext);
bundleInfo.PackageFileSize = GetBundleFileSize(bundleInfo, buildParametersContext);
}
// 4.更新补丁包输出的文件路径
foreach (var bundleInfo in buildMapContext.Collection)
{
string bundleName = bundleInfo.BundleName;
string fileHash = bundleInfo.PackageFileHash;
string fileExtension = ManifestTools.GetRemoteBundleFileExtension(bundleName);
string fileName = ManifestTools.GetRemoteBundleFileName(outputNameStyle, bundleName, fileExtension, fileHash);
bundleInfo.PackageDestFilePath = $"{packageOutputDirectory}/{fileName}";
}
}
protected abstract string GetUnityHash(BuildBundleInfo bundleInfo, BuildContext context);
protected abstract uint GetUnityCRC(BuildBundleInfo bundleInfo, BuildContext context);
protected abstract string GetBundleFileHash(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext);
protected abstract uint GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext);
protected abstract long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1dda2f1ef3b6c4e48a398217335b55f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: