Initial commit
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
public class TaskBuilding : IBuildTask
|
||||
{
|
||||
public class UnityManifestContext : IContextObject
|
||||
{
|
||||
public AssetBundleManifest UnityManifest;
|
||||
}
|
||||
|
||||
void IBuildTask.Run(BuildContext context)
|
||||
{
|
||||
var buildParametersContext = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
|
||||
var buildMapContext = context.GetContextObject<TaskGetBuildMap.BuildMapContext>();
|
||||
|
||||
Debug.Log($"开始构建......");
|
||||
BuildAssetBundleOptions opt = buildParametersContext.GetPipelineBuildOptions();
|
||||
AssetBundleManifest unityManifest = BuildPipeline.BuildAssetBundles(buildParametersContext.PipelineOutputDirectory, buildMapContext.GetPipelineBuilds(), opt, buildParametersContext.Parameters.BuildTarget);
|
||||
if (unityManifest == null)
|
||||
throw new Exception("构建过程中发生错误!");
|
||||
|
||||
UnityManifestContext unityManifestContext = new UnityManifestContext();
|
||||
unityManifestContext.UnityManifest = unityManifest;
|
||||
context.SetContextObject(unityManifestContext);
|
||||
|
||||
// 拷贝原生文件
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
if (bundleInfo.IsRawFile)
|
||||
{
|
||||
string dest = $"{buildParametersContext.PipelineOutputDirectory}/{bundleInfo.BundleName}";
|
||||
foreach(var buildAsset in bundleInfo.Assets)
|
||||
{
|
||||
if(buildAsset.IsRawAsset)
|
||||
EditorTools.CopyFile(buildAsset.AssetPath, dest, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证构建结果
|
||||
if (buildParametersContext.Parameters.IsVerifyBuildingResult)
|
||||
{
|
||||
VerifyingBuildingResult(context, unityManifest);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证构建结果
|
||||
/// </summary>
|
||||
private void VerifyingBuildingResult(BuildContext context, AssetBundleManifest unityManifest)
|
||||
{
|
||||
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
|
||||
var buildMapContext = context.GetContextObject<TaskGetBuildMap.BuildMapContext>();
|
||||
string[] buildedBundles = unityManifest.GetAllAssetBundles();
|
||||
|
||||
// 1. 过滤掉原生Bundle
|
||||
List<BuildBundleInfo> expectBundles = new List<BuildBundleInfo>(buildedBundles.Length);
|
||||
foreach(var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
if (bundleInfo.IsRawFile == false)
|
||||
expectBundles.Add(bundleInfo);
|
||||
}
|
||||
|
||||
// 2. 验证数量
|
||||
if (buildedBundles.Length != expectBundles.Count)
|
||||
{
|
||||
Debug.LogWarning($"构建过程中可能存在无效的资源,导致和预期构建的Bundle数量不一致!");
|
||||
}
|
||||
|
||||
// 3. 正向验证Bundle
|
||||
foreach (var bundleName in buildedBundles)
|
||||
{
|
||||
if (buildMapContext.IsContainsBundle(bundleName) == false)
|
||||
{
|
||||
throw new Exception($"Should never get here !");
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 反向验证Bundle
|
||||
bool isPass = true;
|
||||
foreach (var expectBundle in expectBundles)
|
||||
{
|
||||
bool isMatch = false;
|
||||
foreach (var buildedBundle in buildedBundles)
|
||||
{
|
||||
if (buildedBundle == expectBundle.BundleName)
|
||||
{
|
||||
isMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isMatch == false)
|
||||
{
|
||||
isPass = false;
|
||||
Debug.LogWarning($"没有找到预期构建的Bundle文件 : {expectBundle.BundleName}");
|
||||
}
|
||||
}
|
||||
if(isPass == false)
|
||||
{
|
||||
throw new Exception("构建结果验证没有通过,请参考警告日志!");
|
||||
}
|
||||
|
||||
// 5. 验证Asset
|
||||
int progressValue = 0;
|
||||
foreach (var buildedBundle in buildedBundles)
|
||||
{
|
||||
string filePath = $"{buildParameters.PipelineOutputDirectory}/{buildedBundle}";
|
||||
string[] allBuildinAssetPaths = GetAssetBundleAllAssets(filePath);
|
||||
string[] expectBuildinAssetPaths = buildMapContext.GetBuildinAssetPaths(buildedBundle);
|
||||
if (expectBuildinAssetPaths.Length != allBuildinAssetPaths.Length)
|
||||
{
|
||||
Debug.LogWarning($"构建的Bundle文件内的资源对象数量和预期不匹配 : {buildedBundle}");
|
||||
isPass = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var buildinAssetPath in allBuildinAssetPaths)
|
||||
{
|
||||
var guid = AssetDatabase.AssetPathToGUID(buildinAssetPath);
|
||||
if (string.IsNullOrEmpty(guid))
|
||||
{
|
||||
Debug.LogWarning($"无效的资源路径,请检查路径是否带有特殊符号或中文:{buildinAssetPath}");
|
||||
isPass = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isMatch = false;
|
||||
foreach (var exceptBuildAssetPath in expectBuildinAssetPaths)
|
||||
{
|
||||
var guidExcept = AssetDatabase.AssetPathToGUID(exceptBuildAssetPath);
|
||||
if (guid == guidExcept)
|
||||
{
|
||||
isMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isMatch == false)
|
||||
{
|
||||
Debug.LogWarning($"在构建的Bundle文件里发现了没有匹配的资源对象:{buildinAssetPath}");
|
||||
isPass = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
EditorTools.DisplayProgressBar("验证构建结果", ++progressValue, buildedBundles.Length);
|
||||
}
|
||||
EditorTools.ClearProgressBar();
|
||||
if (isPass == false)
|
||||
{
|
||||
throw new Exception("构建结果验证没有通过,请参考警告日志!");
|
||||
}
|
||||
|
||||
// 卸载所有加载的Bundle
|
||||
Debug.Log("构建结果验证成功!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析.manifest文件并获取资源列表
|
||||
/// </summary>
|
||||
private string[] GetAssetBundleAllAssets(string filePath)
|
||||
{
|
||||
string manifestFilePath = $"{filePath}.manifest";
|
||||
List<string> assetLines = new List<string>();
|
||||
using (StreamReader reader = File.OpenText(manifestFilePath))
|
||||
{
|
||||
string content;
|
||||
bool findTarget = false;
|
||||
while (null != (content = reader.ReadLine()))
|
||||
{
|
||||
if (content.StartsWith("Dependencies:"))
|
||||
break;
|
||||
if (findTarget == false && content.StartsWith("Assets:"))
|
||||
findTarget = true;
|
||||
if (findTarget)
|
||||
{
|
||||
if (content.StartsWith("- "))
|
||||
{
|
||||
string assetPath = content.TrimStart("- ".ToCharArray());
|
||||
assetLines.Add(assetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return assetLines.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9466e826c135e994c84961e4b921ca5f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 拷贝内置文件到StreamingAssets
|
||||
/// </summary>
|
||||
public class TaskCopyBuildinFiles : IBuildTask
|
||||
{
|
||||
void IBuildTask.Run(BuildContext context)
|
||||
{
|
||||
// 注意:我们只有在强制重建的时候才会拷贝
|
||||
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
|
||||
if(buildParameters.Parameters.IsForceRebuild)
|
||||
{
|
||||
// 清空流目录
|
||||
AssetBundleBuilderHelper.ClearStreamingAssetsFolder();
|
||||
|
||||
// 拷贝内置文件
|
||||
var pipelineOutputDirectory = buildParameters.PipelineOutputDirectory;
|
||||
CopyBuildinFilesToStreaming(pipelineOutputDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyBuildinFilesToStreaming(string pipelineOutputDirectory)
|
||||
{
|
||||
// 加载补丁清单
|
||||
PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(pipelineOutputDirectory);
|
||||
|
||||
// 拷贝文件列表
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.IsBuildin == false)
|
||||
continue;
|
||||
|
||||
string sourcePath = $"{pipelineOutputDirectory}/{patchBundle.BundleName}";
|
||||
string destPath = $"{Application.dataPath}/StreamingAssets/{patchBundle.Hash}";
|
||||
Debug.Log($"拷贝内置文件到流目录:{patchBundle.BundleName}");
|
||||
EditorTools.CopyFile(sourcePath, destPath, true);
|
||||
}
|
||||
|
||||
// 拷贝清单文件
|
||||
{
|
||||
string sourcePath = $"{pipelineOutputDirectory}/{ResourceSettingData.Setting.PatchManifestFileName}";
|
||||
string destPath = $"{Application.dataPath}/StreamingAssets/{ResourceSettingData.Setting.PatchManifestFileName}";
|
||||
EditorTools.CopyFile(sourcePath, destPath, true);
|
||||
}
|
||||
|
||||
// 拷贝清单哈希文件
|
||||
{
|
||||
string sourcePath = $"{pipelineOutputDirectory}/{ResourceSettingData.Setting.PatchManifestHashFileName}";
|
||||
string destPath = $"{Application.dataPath}/StreamingAssets/{ResourceSettingData.Setting.PatchManifestHashFileName}";
|
||||
EditorTools.CopyFile(sourcePath, destPath, true);
|
||||
}
|
||||
|
||||
// 刷新目录
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c77e17c3a3a57548a218f1cd26f5a55
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using YooAsset.Utility;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建补丁清单文件
|
||||
/// </summary>
|
||||
public class TaskCreatePatchManifest : IBuildTask
|
||||
{
|
||||
void IBuildTask.Run(BuildContext context)
|
||||
{
|
||||
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
|
||||
var encryptionContext = context.GetContextObject<TaskEncryption.EncryptionContext>();
|
||||
var buildMapContext = context.GetContextObject<TaskGetBuildMap.BuildMapContext>();
|
||||
CreatePatchManifestFile(buildParameters, buildMapContext, encryptionContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建补丁清单文件到输出目录
|
||||
/// </summary>
|
||||
private void CreatePatchManifestFile(AssetBundleBuilder.BuildParametersContext buildParameters,
|
||||
TaskGetBuildMap.BuildMapContext buildMapContext, TaskEncryption.EncryptionContext encryptionContext)
|
||||
{
|
||||
// 创建新补丁清单
|
||||
PatchManifest patchManifest = new PatchManifest();
|
||||
patchManifest.ResourceVersion = buildParameters.Parameters.BuildVersion;
|
||||
patchManifest.BuildinTags = buildParameters.Parameters.BuildinTags;
|
||||
patchManifest.BundleList = GetAllPatchBundle(buildParameters, buildMapContext, encryptionContext);
|
||||
patchManifest.AssetList = GetAllPatchAsset(buildMapContext, patchManifest.BundleList);
|
||||
|
||||
// 创建补丁清单文件
|
||||
string manifestFilePath = $"{buildParameters.PipelineOutputDirectory}/{ResourceSettingData.Setting.PatchManifestFileName}";
|
||||
UnityEngine.Debug.Log($"创建补丁清单文件:{manifestFilePath}");
|
||||
PatchManifest.Serialize(manifestFilePath, patchManifest);
|
||||
|
||||
// 创建补丁清单哈希文件
|
||||
string manifestHashFilePath = $"{buildParameters.PipelineOutputDirectory}/{ResourceSettingData.Setting.PatchManifestHashFileName}";
|
||||
string manifestHash = HashUtility.FileMD5(manifestFilePath);
|
||||
UnityEngine.Debug.Log($"创建补丁清单哈希文件:{manifestHashFilePath}");
|
||||
FileUtility.CreateFile(manifestHashFilePath, manifestHash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源包列表
|
||||
/// </summary>
|
||||
private List<PatchBundle> GetAllPatchBundle(AssetBundleBuilder.BuildParametersContext buildParameters,
|
||||
TaskGetBuildMap.BuildMapContext buildMapContext, TaskEncryption.EncryptionContext encryptionContext)
|
||||
{
|
||||
List<PatchBundle> result = new List<PatchBundle>(1000);
|
||||
|
||||
// 内置标记列表
|
||||
List<string> buildinTags = buildParameters.Parameters.GetBuildinTags();
|
||||
|
||||
// 加载旧补丁清单
|
||||
PatchManifest oldPatchManifest = null;
|
||||
if (buildParameters.Parameters.IsForceRebuild == false)
|
||||
{
|
||||
oldPatchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory);
|
||||
}
|
||||
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
var bundleName = bundleInfo.BundleName;
|
||||
string filePath = $"{buildParameters.PipelineOutputDirectory}/{bundleName}";
|
||||
string hash = HashUtility.FileMD5(filePath);
|
||||
string crc = HashUtility.FileCRC32(filePath);
|
||||
long size = FileUtility.GetFileSize(filePath);
|
||||
int version = buildParameters.Parameters.BuildVersion;
|
||||
string[] tags = buildMapContext.GetAssetTags(bundleName);
|
||||
bool isEncrypted = encryptionContext.IsEncryptFile(bundleName);
|
||||
bool isBuildin = IsBuildinBundle(tags, buildinTags);
|
||||
bool isRawFile = bundleInfo.IsRawFile;
|
||||
|
||||
// 附加文件扩展名
|
||||
if (buildParameters.Parameters.AppendFileExtension)
|
||||
{
|
||||
hash += bundleInfo.GetAppendExtension();
|
||||
}
|
||||
|
||||
// 注意:如果文件没有变化使用旧版本号
|
||||
if (oldPatchManifest != null && oldPatchManifest.Bundles.TryGetValue(bundleName, out PatchBundle value))
|
||||
{
|
||||
if (value.Hash == hash)
|
||||
version = value.Version;
|
||||
}
|
||||
|
||||
PatchBundle patchBundle = new PatchBundle(bundleName, hash, crc, size, version, tags);
|
||||
patchBundle.SetFlagsValue(isEncrypted, isBuildin, isRawFile);
|
||||
result.Add(patchBundle);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
private bool IsBuildinBundle(string[] bundleTags, List<string> buildinTags)
|
||||
{
|
||||
// 注意:没有任何标记的Bundle文件默认为内置文件
|
||||
if (bundleTags.Length == 0)
|
||||
return true;
|
||||
|
||||
foreach (var tag in bundleTags)
|
||||
{
|
||||
if (buildinTags.Contains(tag))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源列表
|
||||
/// </summary>
|
||||
private List<PatchAsset> GetAllPatchAsset(TaskGetBuildMap.BuildMapContext buildMapContext, List<PatchBundle> bundleList)
|
||||
{
|
||||
List<PatchAsset> result = new List<PatchAsset>(1000);
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
var assetInfos = bundleInfo.GetCollectAssetInfos();
|
||||
foreach (var assetInfo in assetInfos)
|
||||
{
|
||||
PatchAsset patchAsset = new PatchAsset();
|
||||
patchAsset.AssetPath = assetInfo.AssetPath;
|
||||
patchAsset.BundleID = GetAssetBundleID(assetInfo.GetBundleName(), bundleList);
|
||||
patchAsset.DependIDs = GetAssetBundleDependIDs(assetInfo, bundleList);
|
||||
result.Add(patchAsset);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private int[] GetAssetBundleDependIDs(BuildAssetInfo assetInfo, List<PatchBundle> bundleList)
|
||||
{
|
||||
List<int> result = new List<int>();
|
||||
foreach (var dependAssetInfo in assetInfo.AllDependAssetInfos)
|
||||
{
|
||||
if (dependAssetInfo.CheckBundleNameValid() == false)
|
||||
continue;
|
||||
int bundleID = GetAssetBundleID(dependAssetInfo.GetBundleName(), bundleList);
|
||||
if (result.Contains(bundleID) == false)
|
||||
result.Add(bundleID);
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
private int GetAssetBundleID(string bundleName, List<PatchBundle> bundleList)
|
||||
{
|
||||
for (int index = 0; index < bundleList.Count; index++)
|
||||
{
|
||||
if (bundleList[index].BundleName == bundleName)
|
||||
return index;
|
||||
}
|
||||
throw new Exception($"Not found bundle name : {bundleName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 566c37f5a59f2e84397a9527981a7310
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 制作补丁包
|
||||
/// </summary>
|
||||
public class TaskCreatePatchPackage : IBuildTask
|
||||
{
|
||||
void IBuildTask.Run(BuildContext context)
|
||||
{
|
||||
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
|
||||
CopyPatchFiles(buildParameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拷贝补丁文件到补丁包目录
|
||||
/// </summary>
|
||||
private void CopyPatchFiles(AssetBundleBuilder.BuildParametersContext buildParameters)
|
||||
{
|
||||
string packageDirectory = buildParameters.GetPackageDirectory();
|
||||
UnityEngine.Debug.Log($"开始拷贝补丁文件到补丁包目录:{packageDirectory}");
|
||||
|
||||
// 拷贝Readme文件
|
||||
{
|
||||
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{ResourceSettingData.Setting.ReadmeFileName}";
|
||||
string destPath = $"{packageDirectory}/{ResourceSettingData.Setting.ReadmeFileName}";
|
||||
EditorTools.CopyFile(sourcePath, destPath, true);
|
||||
UnityEngine.Debug.Log($"拷贝Readme文件到:{destPath}");
|
||||
}
|
||||
|
||||
// 拷贝PatchManifest文件
|
||||
{
|
||||
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{ResourceSettingData.Setting.PatchManifestFileName}";
|
||||
string destPath = $"{packageDirectory}/{ResourceSettingData.Setting.PatchManifestFileName}";
|
||||
EditorTools.CopyFile(sourcePath, destPath, true);
|
||||
UnityEngine.Debug.Log($"拷贝PatchManifest文件到:{destPath}");
|
||||
}
|
||||
|
||||
// 拷贝PatchManifest哈希文件
|
||||
{
|
||||
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{ResourceSettingData.Setting.PatchManifestHashFileName}";
|
||||
string destPath = $"{packageDirectory}/{ResourceSettingData.Setting.PatchManifestHashFileName}";
|
||||
EditorTools.CopyFile(sourcePath, destPath, true);
|
||||
UnityEngine.Debug.Log($"拷贝PatchManifest哈希文件到:{destPath}");
|
||||
}
|
||||
|
||||
// 拷贝UnityManifest序列化文件
|
||||
{
|
||||
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{ResourceSettingData.Setting.UnityManifestFileName}";
|
||||
string destPath = $"{packageDirectory}/{ResourceSettingData.Setting.UnityManifestFileName}";
|
||||
EditorTools.CopyFile(sourcePath, destPath, true);
|
||||
UnityEngine.Debug.Log($"拷贝UnityManifest文件到:{destPath}");
|
||||
}
|
||||
|
||||
// 拷贝UnityManifest文本文件
|
||||
{
|
||||
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{ResourceSettingData.Setting.UnityManifestFileName}.manifest";
|
||||
string destPath = $"{packageDirectory}/{ResourceSettingData.Setting.UnityManifestFileName}.manifest";
|
||||
EditorTools.CopyFile(sourcePath, destPath, true);
|
||||
}
|
||||
|
||||
// 拷贝所有补丁文件
|
||||
// 注意:拷贝的补丁文件都是需要玩家热更新的文件
|
||||
int progressValue = 0;
|
||||
PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory);
|
||||
int patchFileTotalCount = patchManifest.BundleList.Count;
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.Version == buildParameters.Parameters.BuildVersion)
|
||||
{
|
||||
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{patchBundle.BundleName}";
|
||||
string destPath = $"{packageDirectory}/{patchBundle.Hash}";
|
||||
EditorTools.CopyFile(sourcePath, destPath, true);
|
||||
UnityEngine.Debug.Log($"拷贝补丁文件到补丁包:{patchBundle.BundleName}");
|
||||
EditorTools.DisplayProgressBar("拷贝补丁文件", ++progressValue, patchFileTotalCount);
|
||||
}
|
||||
}
|
||||
EditorTools.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d110092f543e3fe40a4d3882e1a718e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建说明文件
|
||||
/// </summary>
|
||||
public class TaskCreateReadme : IBuildTask
|
||||
{
|
||||
void IBuildTask.Run(BuildContext context)
|
||||
{
|
||||
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
|
||||
var buildMapContext = context.GetContextObject<TaskGetBuildMap.BuildMapContext>();
|
||||
CreateReadmeFile(buildParameters, buildMapContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建Readme文件到输出目录
|
||||
/// </summary>
|
||||
private void CreateReadmeFile(AssetBundleBuilder.BuildParametersContext buildParameters, TaskGetBuildMap.BuildMapContext buildMapContext)
|
||||
{
|
||||
PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory);
|
||||
|
||||
// 删除旧文件
|
||||
string filePath = $"{buildParameters.PipelineOutputDirectory}/{ResourceSettingData.Setting.ReadmeFileName}";
|
||||
if (File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
|
||||
UnityEngine.Debug.Log($"创建说明文件:{filePath}");
|
||||
|
||||
StringBuilder content = new StringBuilder();
|
||||
AppendData(content, $"构建时间:{DateTime.Now}");
|
||||
AppendData(content, $"构建平台:{buildParameters.Parameters.BuildTarget}");
|
||||
AppendData(content, $"构建版本:{buildParameters.Parameters.BuildVersion}");
|
||||
AppendData(content, $"冗余机制:{buildParameters.Parameters.ApplyRedundancy}");
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--着色器--");
|
||||
AppendData(content, $"IsCollectAllShaders:{AssetBundleCollectorSettingData.Setting.IsCollectAllShaders}");
|
||||
AppendData(content, $"ShadersBundleName:{AssetBundleCollectorSettingData.Setting.ShadersBundleName}");
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--配置信息--");
|
||||
for (int i = 0; i < AssetBundleCollectorSettingData.Setting.Collectors.Count; i++)
|
||||
{
|
||||
AssetBundleCollectorSetting.Collector wrapper = AssetBundleCollectorSettingData.Setting.Collectors[i];
|
||||
AppendData(content, wrapper.ToString());
|
||||
}
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--构建参数--");
|
||||
AppendData(content, $"CompressOption:{buildParameters.Parameters.CompressOption}");
|
||||
AppendData(content, $"IsForceRebuild:{buildParameters.Parameters.IsForceRebuild}");
|
||||
AppendData(content, $"BuildinTags:{buildParameters.Parameters.BuildinTags}");
|
||||
AppendData(content, $"IsAppendHash:{buildParameters.Parameters.IsAppendHash}");
|
||||
AppendData(content, $"IsDisableWriteTypeTree:{buildParameters.Parameters.IsDisableWriteTypeTree}");
|
||||
AppendData(content, $"IsIgnoreTypeTreeChanges:{buildParameters.Parameters.IsIgnoreTypeTreeChanges}");
|
||||
AppendData(content, $"IsDisableLoadAssetByFileName : {buildParameters.Parameters.IsDisableLoadAssetByFileName}");
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--构建信息--");
|
||||
AppendData(content, $"参与构建的资源总数:{buildMapContext.GetAllAssets().Count}");
|
||||
GetBundleFileCountAndTotalSize(patchManifest, out int fileCount1, out long fileTotalSize1);
|
||||
AppendData(content, $"构建的资源包总数:{fileCount1} 文件总大小:{fileTotalSize1 / (1024 * 1024)}MB");
|
||||
GetBuildinFileCountAndTotalSize(patchManifest, out int fileCount2, out long fileTotalSize2);
|
||||
AppendData(content, $"内置的资源包总数:{fileCount2} 文件总大小:{fileTotalSize2 / (1024 * 1024)}MB");
|
||||
GetNotBuildinFileCountAndTotalSize(patchManifest, out int fileCount3, out long fileTotalSize3);
|
||||
AppendData(content, $"非内置的资源包总数:{fileCount3} 文件总大小:{fileTotalSize3 / (1024 * 1024)}MB");
|
||||
GetEncryptedFileCountAndTotalSize(patchManifest, out int fileCount4, out long fileTotalSize4);
|
||||
AppendData(content, $"加密的资源包总数:{fileCount4} 文件总大小:{fileTotalSize4 / (1024 * 1024)}MB");
|
||||
GetRawFileCountAndTotalSize(patchManifest, out int fileCount5, out long fileTotalSize5);
|
||||
AppendData(content, $"原生的资源包总数:{fileCount5} 文件总大小:{fileTotalSize5 / (1024 * 1024)}MB");
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--冗余列表--");
|
||||
for (int i = 0; i < buildMapContext.RedundancyList.Count; i++)
|
||||
{
|
||||
string redundancyAssetPath = buildMapContext.RedundancyList[i];
|
||||
AppendData(content, redundancyAssetPath);
|
||||
}
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--构建列表--");
|
||||
for (int i = 0; i < buildMapContext.BundleInfos.Count; i++)
|
||||
{
|
||||
string bundleName = buildMapContext.BundleInfos[i].BundleName;
|
||||
AppendData(content, bundleName);
|
||||
}
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--内置文件列表--");
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.IsBuildin)
|
||||
{
|
||||
AppendData(content, patchBundle.BundleName);
|
||||
}
|
||||
}
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--非内置文件列表--");
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.IsBuildin == false)
|
||||
{
|
||||
AppendData(content, patchBundle.BundleName);
|
||||
}
|
||||
}
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--加密文件列表--");
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.IsEncrypted)
|
||||
{
|
||||
AppendData(content, patchBundle.BundleName);
|
||||
}
|
||||
}
|
||||
|
||||
AppendData(content, "");
|
||||
AppendData(content, $"--原生文件列表--");
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.IsRawFile)
|
||||
{
|
||||
AppendData(content, patchBundle.BundleName);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新文件
|
||||
File.WriteAllText(filePath, content.ToString(), Encoding.UTF8);
|
||||
}
|
||||
private void AppendData(StringBuilder sb, string data)
|
||||
{
|
||||
sb.Append(data);
|
||||
sb.Append("\r\n");
|
||||
}
|
||||
|
||||
private void GetBundleFileCountAndTotalSize(PatchManifest patchManifest, out int fileCount, out long fileBytes)
|
||||
{
|
||||
fileCount = patchManifest.BundleList.Count;
|
||||
fileBytes = 0;
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
fileBytes += patchBundle.SizeBytes;
|
||||
}
|
||||
}
|
||||
private void GetBuildinFileCountAndTotalSize(PatchManifest patchManifest, out int fileCount, out long fileBytes)
|
||||
{
|
||||
fileCount = 0;
|
||||
fileBytes = 0;
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.IsBuildin)
|
||||
{
|
||||
fileCount++;
|
||||
fileBytes += patchBundle.SizeBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void GetNotBuildinFileCountAndTotalSize(PatchManifest patchManifest, out int fileCount, out long fileBytes)
|
||||
{
|
||||
fileCount = 0;
|
||||
fileBytes = 0;
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.IsBuildin == false)
|
||||
{
|
||||
fileCount++;
|
||||
fileBytes += patchBundle.SizeBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void GetEncryptedFileCountAndTotalSize(PatchManifest patchManifest, out int fileCount, out long fileBytes)
|
||||
{
|
||||
fileCount = 0;
|
||||
fileBytes = 0;
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.IsEncrypted)
|
||||
{
|
||||
fileCount++;
|
||||
fileBytes += patchBundle.SizeBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void GetRawFileCountAndTotalSize(PatchManifest patchManifest, out int fileCount, out long fileBytes)
|
||||
{
|
||||
fileCount = 0;
|
||||
fileBytes = 0;
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
if (patchBundle.IsRawFile)
|
||||
{
|
||||
fileCount++;
|
||||
fileBytes += patchBundle.SizeBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1660a082a6449f4429fcca15e4383f0b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using YooAsset.Utility;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
public class TaskEncryption : IBuildTask
|
||||
{
|
||||
public class EncryptionContext : IContextObject
|
||||
{
|
||||
public List<string> EncryptList;
|
||||
|
||||
/// <summary>
|
||||
/// 检测是否为加密文件
|
||||
/// </summary>
|
||||
public bool IsEncryptFile(string bundleName)
|
||||
{
|
||||
return EncryptList.Contains(bundleName);
|
||||
}
|
||||
}
|
||||
|
||||
void IBuildTask.Run(BuildContext context)
|
||||
{
|
||||
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
|
||||
var buildMapContext = context.GetContextObject<TaskGetBuildMap.BuildMapContext>();
|
||||
|
||||
var encrypter = CreateAssetEncrypter();
|
||||
List<string> encryptList = EncryptFiles(encrypter, buildParameters, buildMapContext);
|
||||
|
||||
EncryptionContext encryptionContext = new EncryptionContext();
|
||||
encryptionContext.EncryptList = encryptList;
|
||||
context.SetContextObject(encryptionContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建加密类
|
||||
/// </summary>
|
||||
/// <returns>如果没有定义类型,则返回NULL</returns>
|
||||
private IAssetEncrypter CreateAssetEncrypter()
|
||||
{
|
||||
var types = AssemblyUtility.GetAssignableTypes(AssemblyUtility.UnityDefaultAssemblyEditorName, typeof(IAssetEncrypter));
|
||||
if (types.Count == 0)
|
||||
return null;
|
||||
if (types.Count != 1)
|
||||
throw new Exception($"Found more {nameof(IAssetEncrypter)} types. We only support one.");
|
||||
|
||||
UnityEngine.Debug.Log($"创建实例类 : {types[0].FullName}");
|
||||
return (IAssetEncrypter)Activator.CreateInstance(types[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加密文件
|
||||
/// </summary>
|
||||
private List<string> EncryptFiles(IAssetEncrypter encrypter, AssetBundleBuilder.BuildParametersContext buildParameters, TaskGetBuildMap.BuildMapContext buildMapContext)
|
||||
{
|
||||
// 加密资源列表
|
||||
List<string> encryptList = new List<string>();
|
||||
|
||||
// 如果没有设置加密类
|
||||
if (encrypter == null)
|
||||
return encryptList;
|
||||
|
||||
UnityEngine.Debug.Log($"开始加密资源文件");
|
||||
int progressValue = 0;
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
var bundleName = bundleInfo.BundleName;
|
||||
string filePath = $"{buildParameters.PipelineOutputDirectory}/{bundleName}";
|
||||
if (encrypter.Check(filePath))
|
||||
{
|
||||
encryptList.Add(bundleName);
|
||||
|
||||
// 注意:通过判断文件合法性,规避重复加密一个文件
|
||||
byte[] fileData = File.ReadAllBytes(filePath);
|
||||
if (EditorTools.CheckBundleFileValid(fileData))
|
||||
{
|
||||
byte[] bytes = encrypter.Encrypt(fileData);
|
||||
File.WriteAllBytes(filePath, bytes);
|
||||
UnityEngine.Debug.Log($"文件加密完成:{filePath}");
|
||||
}
|
||||
}
|
||||
|
||||
// 进度条
|
||||
EditorTools.DisplayProgressBar("加密资源包", ++progressValue, buildMapContext.BundleInfos.Count);
|
||||
}
|
||||
EditorTools.ClearProgressBar();
|
||||
|
||||
return encryptList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c78d471226b9c8d429a2d962370f480b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,331 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using YooAsset.Utility;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
public class TaskGetBuildMap : IBuildTask
|
||||
{
|
||||
public class BuildMapContext : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源包列表
|
||||
/// </summary>
|
||||
public readonly List<BuildBundleInfo> BundleInfos = new List<BuildBundleInfo>(1000);
|
||||
|
||||
/// <summary>
|
||||
/// 冗余的资源列表
|
||||
/// </summary>
|
||||
public readonly List<string> RedundancyList = new List<string>(1000);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个打包资源
|
||||
/// </summary>
|
||||
public void PackAsset(BuildAssetInfo assetInfo)
|
||||
{
|
||||
if (TryGetBundleInfo(assetInfo.GetBundleName(), out BuildBundleInfo bundleInfo))
|
||||
{
|
||||
bundleInfo.PackAsset(assetInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
BuildBundleInfo newBundleInfo = new BuildBundleInfo(assetInfo.BundleLabel, assetInfo.BundleVariant);
|
||||
newBundleInfo.PackAsset(assetInfo);
|
||||
BundleInfos.Add(newBundleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有的打包资源
|
||||
/// </summary>
|
||||
public List<BuildAssetInfo> GetAllAssets()
|
||||
{
|
||||
List<BuildAssetInfo> result = new List<BuildAssetInfo>(BundleInfos.Count);
|
||||
foreach (var bundleInfo in BundleInfos)
|
||||
{
|
||||
result.AddRange(bundleInfo.Assets);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取AssetBundle内包含的标记列表
|
||||
/// </summary>
|
||||
public string[] GetAssetTags(string bundleFullName)
|
||||
{
|
||||
if (TryGetBundleInfo(bundleFullName, out BuildBundleInfo bundleInfo))
|
||||
{
|
||||
return bundleInfo.GetAssetTags();
|
||||
}
|
||||
throw new Exception($"Not found {nameof(BuildBundleInfo)} : {bundleFullName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取AssetBundle内收集的资源路径列表
|
||||
/// </summary>
|
||||
public string[] GetCollectAssetPaths(string bundleFullName)
|
||||
{
|
||||
if (TryGetBundleInfo(bundleFullName, out BuildBundleInfo bundleInfo))
|
||||
{
|
||||
return bundleInfo.GetCollectAssetPaths();
|
||||
}
|
||||
throw new Exception($"Not found {nameof(BuildBundleInfo)} : {bundleFullName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取AssetBundle内构建的资源路径列表
|
||||
/// </summary>
|
||||
public string[] GetBuildinAssetPaths(string bundleFullName)
|
||||
{
|
||||
if (TryGetBundleInfo(bundleFullName, out BuildBundleInfo bundleInfo))
|
||||
{
|
||||
return bundleInfo.GetBuildinAssetPaths();
|
||||
}
|
||||
throw new Exception($"Not found {nameof(BuildBundleInfo)} : {bundleFullName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取构建管线里需要的数据
|
||||
/// </summary>
|
||||
public UnityEditor.AssetBundleBuild[] GetPipelineBuilds()
|
||||
{
|
||||
List<AssetBundleBuild> builds = new List<AssetBundleBuild>(BundleInfos.Count);
|
||||
foreach (var bundleInfo in BundleInfos)
|
||||
{
|
||||
if (bundleInfo.IsRawFile == false)
|
||||
builds.Add(bundleInfo.CreatePipelineBuild());
|
||||
}
|
||||
return builds.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测是否包含BundleName
|
||||
/// </summary>
|
||||
public bool IsContainsBundle(string bundleFullName)
|
||||
{
|
||||
return TryGetBundleInfo(bundleFullName, out BuildBundleInfo bundleInfo);
|
||||
}
|
||||
|
||||
private bool TryGetBundleInfo(string bundleFullName, out BuildBundleInfo result)
|
||||
{
|
||||
foreach (var bundleInfo in BundleInfos)
|
||||
{
|
||||
if (bundleInfo.BundleName == bundleFullName)
|
||||
{
|
||||
result = bundleInfo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IBuildTask.Run(BuildContext context)
|
||||
{
|
||||
var buildParametersContext = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
|
||||
BuildMapContext buildMapContext = new BuildMapContext();
|
||||
context.SetContextObject(buildMapContext);
|
||||
SetupBuildMap(buildMapContext, buildParametersContext);
|
||||
|
||||
// 检测构建结果
|
||||
CheckBuildMapContent(buildMapContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 组织构建的资源包
|
||||
/// </summary>
|
||||
private void SetupBuildMap(BuildMapContext buildMapContext, AssetBundleBuilder.BuildParametersContext buildParameters)
|
||||
{
|
||||
Dictionary<string, BuildAssetInfo> buildAssets = new Dictionary<string, BuildAssetInfo>();
|
||||
|
||||
// 1. 获取主动收集的资源
|
||||
List<AssetCollectInfo> allCollectInfos = AssetBundleCollectorSettingData.GetAllCollectAssets();
|
||||
|
||||
// 2. 对收集的资源进行依赖分析
|
||||
int progressValue = 0;
|
||||
foreach (AssetCollectInfo collectInfo in allCollectInfos)
|
||||
{
|
||||
string mainAssetPath = collectInfo.AssetPath;
|
||||
|
||||
// 获取所有依赖资源
|
||||
List<BuildAssetInfo> depends = GetAllDependencies(mainAssetPath);
|
||||
for (int i = 0; i < depends.Count; i++)
|
||||
{
|
||||
string assetPath = depends[i].AssetPath;
|
||||
|
||||
// 如果已经存在,则增加该资源的依赖计数
|
||||
if (buildAssets.ContainsKey(assetPath))
|
||||
{
|
||||
buildAssets[assetPath].DependCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
buildAssets.Add(assetPath, depends[i]);
|
||||
}
|
||||
|
||||
// 添加资源标记
|
||||
buildAssets[assetPath].AddAssetTags(collectInfo.AssetTags);
|
||||
|
||||
// 注意:检测是否为主动收集资源
|
||||
if (assetPath == mainAssetPath)
|
||||
{
|
||||
buildAssets[mainAssetPath].IsCollectAsset = true;
|
||||
buildAssets[mainAssetPath].IsRawAsset = collectInfo.IsRawAsset;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加所有的依赖资源列表
|
||||
// 注意:不包括自己
|
||||
var allDependAssetInfos = new List<BuildAssetInfo>(depends.Count);
|
||||
for (int i = 0; i < depends.Count; i++)
|
||||
{
|
||||
string assetPath = depends[i].AssetPath;
|
||||
if (assetPath != mainAssetPath)
|
||||
allDependAssetInfos.Add(buildAssets[assetPath]);
|
||||
}
|
||||
buildAssets[mainAssetPath].SetAllDependAssetInfos(allDependAssetInfos);
|
||||
|
||||
EditorTools.DisplayProgressBar("依赖文件分析", ++progressValue, allCollectInfos.Count);
|
||||
}
|
||||
EditorTools.ClearProgressBar();
|
||||
|
||||
// 3. 移除零依赖的资源
|
||||
var redundancy = CreateAssetRedundancy();
|
||||
List<BuildAssetInfo> undependentAssets = new List<BuildAssetInfo>();
|
||||
foreach (KeyValuePair<string, BuildAssetInfo> pair in buildAssets)
|
||||
{
|
||||
var buildAssetInfo = pair.Value;
|
||||
if (buildAssetInfo.IsCollectAsset)
|
||||
continue;
|
||||
|
||||
if (buildAssetInfo.DependCount == 0)
|
||||
{
|
||||
undependentAssets.Add(buildAssetInfo);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 冗余扩展
|
||||
if(redundancy != null)
|
||||
{
|
||||
if(redundancy.Check(buildAssetInfo.AssetPath))
|
||||
{
|
||||
undependentAssets.Add(buildAssetInfo);
|
||||
buildMapContext.RedundancyList.Add(buildAssetInfo.AssetPath);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 冗余机制
|
||||
if (buildParameters.Parameters.ApplyRedundancy)
|
||||
{
|
||||
if (AssetBundleCollectorSettingData.HasCollector(buildAssetInfo.AssetPath) == false)
|
||||
{
|
||||
undependentAssets.Add(buildAssetInfo);
|
||||
buildMapContext.RedundancyList.Add(buildAssetInfo.AssetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var assetInfo in undependentAssets)
|
||||
{
|
||||
buildAssets.Remove(assetInfo.AssetPath);
|
||||
}
|
||||
|
||||
// 4. 设置资源包名
|
||||
progressValue = 0;
|
||||
foreach (KeyValuePair<string, BuildAssetInfo> pair in buildAssets)
|
||||
{
|
||||
var assetInfo = pair.Value;
|
||||
var bundleLabel = AssetBundleCollectorSettingData.GetBundleLabel(assetInfo.AssetPath);
|
||||
if (assetInfo.IsRawAsset)
|
||||
assetInfo.SetBundleLabelAndVariant(bundleLabel, ResourceSettingData.Setting.RawFileVariant);
|
||||
else
|
||||
assetInfo.SetBundleLabelAndVariant(bundleLabel, ResourceSettingData.Setting.AssetBundleFileVariant);
|
||||
EditorTools.DisplayProgressBar("设置资源包名", ++progressValue, buildAssets.Count);
|
||||
}
|
||||
EditorTools.ClearProgressBar();
|
||||
|
||||
// 4. 构建资源包
|
||||
var allAssets = buildAssets.Values.ToList();
|
||||
if (allAssets.Count == 0)
|
||||
throw new Exception("构建的资源列表不能为空");
|
||||
UnityEngine.Debug.Log($"构建的资源列表里总共有{allAssets.Count}个资源");
|
||||
foreach (var assetInfo in allAssets)
|
||||
{
|
||||
buildMapContext.PackAsset(assetInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定资源依赖的所有资源列表
|
||||
/// 注意:返回列表里已经包括主资源自己
|
||||
/// </summary>
|
||||
private List<BuildAssetInfo> GetAllDependencies(string mainAssetPath)
|
||||
{
|
||||
List<BuildAssetInfo> result = new List<BuildAssetInfo>();
|
||||
string[] depends = AssetDatabase.GetDependencies(mainAssetPath, true);
|
||||
foreach (string assetPath in depends)
|
||||
{
|
||||
if (AssetBundleCollectorSettingData.IsValidateAsset(assetPath))
|
||||
{
|
||||
BuildAssetInfo assetInfo = new BuildAssetInfo(assetPath);
|
||||
result.Add(assetInfo);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测构建结果
|
||||
/// </summary>
|
||||
private void CheckBuildMapContent(BuildMapContext buildMapContext)
|
||||
{
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
// 注意:原生文件资源包只能包含一个原生文件
|
||||
bool isRawFile = bundleInfo.IsRawFile;
|
||||
if (isRawFile)
|
||||
{
|
||||
if (bundleInfo.Assets.Count != 1)
|
||||
throw new Exception("The bundle does not support multiple raw asset : {bundleInfo.BundleName}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 注意:原生文件不能被其它资源文件依赖
|
||||
foreach (var assetInfo in bundleInfo.Assets)
|
||||
{
|
||||
if (assetInfo.AllDependAssetInfos != null)
|
||||
{
|
||||
foreach (var dependAssetInfo in assetInfo.AllDependAssetInfos)
|
||||
{
|
||||
if (dependAssetInfo.IsRawAsset)
|
||||
throw new Exception($"{assetInfo.AssetPath} can not depend raw asset : {dependAssetInfo.AssetPath}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建冗余类
|
||||
/// </summary>
|
||||
/// <returns>如果没有定义类型,则返回NULL</returns>
|
||||
private IAssetRedundancy CreateAssetRedundancy()
|
||||
{
|
||||
var types = AssemblyUtility.GetAssignableTypes(AssemblyUtility.UnityDefaultAssemblyEditorName, typeof(IAssetRedundancy));
|
||||
if (types.Count == 0)
|
||||
return null;
|
||||
if (types.Count != 1)
|
||||
throw new Exception($"Found more {nameof(IAssetRedundancy)} types. We only support one.");
|
||||
|
||||
UnityEngine.Debug.Log($"创建实例类 : {types[0].FullName}");
|
||||
return (IAssetRedundancy)Activator.CreateInstance(types[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baee18c5c7b76584b90413bf20fdae9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
public class TaskPrepare : IBuildTask
|
||||
{
|
||||
void IBuildTask.Run(BuildContext context)
|
||||
{
|
||||
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
|
||||
|
||||
// 检测构建平台是否合法
|
||||
if (buildParameters.Parameters.BuildTarget == BuildTarget.NoTarget)
|
||||
throw new Exception("请选择目标平台");
|
||||
|
||||
// 检测构建版本是否合法
|
||||
if (buildParameters.Parameters.BuildVersion <= 0)
|
||||
throw new Exception("请先设置版本号");
|
||||
|
||||
// 检测输出目录是否为空
|
||||
if (string.IsNullOrEmpty(buildParameters.PipelineOutputDirectory))
|
||||
throw new Exception("输出目录不能为空");
|
||||
|
||||
// 检测资源收集配置文件
|
||||
if (AssetBundleCollectorSettingData.GetCollecterCount() == 0)
|
||||
throw new Exception("配置的资源收集路径为空");
|
||||
|
||||
// 增量更新时候的必要检测
|
||||
if (buildParameters.Parameters.IsForceRebuild == false)
|
||||
{
|
||||
// 检测历史版本是否存在
|
||||
if (AssetBundleBuilderHelper.HasAnyPackageVersion(buildParameters.Parameters.BuildTarget, buildParameters.Parameters.OutputRoot) == false)
|
||||
throw new Exception("没有发现任何历史版本,请尝试强制重建");
|
||||
|
||||
// 检测构建版本是否合法
|
||||
int maxPackageVersion = AssetBundleBuilderHelper.GetMaxPackageVersion(buildParameters.Parameters.BuildTarget, buildParameters.Parameters.OutputRoot);
|
||||
if (buildParameters.Parameters.BuildVersion <= maxPackageVersion)
|
||||
throw new Exception("构建版本不能小于历史版本");
|
||||
|
||||
// 检测补丁包是否已经存在
|
||||
string packageDirectory = buildParameters.GetPackageDirectory();
|
||||
if (Directory.Exists(packageDirectory))
|
||||
throw new Exception($"补丁包已经存在:{packageDirectory}");
|
||||
|
||||
// 检测内置资源标记是否一致
|
||||
PatchManifest oldPatchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory);
|
||||
if (buildParameters.Parameters.BuildinTags != oldPatchManifest.BuildinTags)
|
||||
throw new Exception($"增量更新时内置资源标记必须一致:{buildParameters.Parameters.BuildinTags} != {oldPatchManifest.BuildinTags}");
|
||||
}
|
||||
|
||||
// 如果是强制重建
|
||||
if (buildParameters.Parameters.IsForceRebuild)
|
||||
{
|
||||
// 删除平台总目录
|
||||
string platformDirectory = $"{buildParameters.Parameters.OutputRoot}/{buildParameters.Parameters.BuildTarget}";
|
||||
if (EditorTools.DeleteDirectory(platformDirectory))
|
||||
{
|
||||
UnityEngine.Debug.Log($"删除平台总目录:{platformDirectory}");
|
||||
}
|
||||
}
|
||||
|
||||
// 如果输出目录不存在
|
||||
if (EditorTools.CreateDirectory(buildParameters.PipelineOutputDirectory))
|
||||
{
|
||||
UnityEngine.Debug.Log($"创建输出目录:{buildParameters.PipelineOutputDirectory}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0dee755cccd608d48b6581ec33c99b39
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user