using XGame.Editor.Asset;
using XGame.Framework.Asset;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace XGame.Editor.Build.AssetBundles
{
internal partial class BundleManifestsController
{
///
/// ab加密的偏移值上限
///
internal readonly uint EncryptOffsetLimit = 256;
private BundleContext _context;
private AssetBundleCollector _bundleCollector;
private BundleDepsController _depsController;
private SceneManifestController _sceneController;
public BundleManifestsController(BundleContext context, AssetBundleCollector bundleCollector, BundleDepsController depsController, SceneManifestController sceneController)
{
_context = context;
_bundleCollector = bundleCollector;
_depsController = depsController;
_sceneController = sceneController;
}
public bool GenerateManifests()
{
_bundleCollector.CollectBundleBuilds(true);
//检查重名资源
if (!CheckAssetsNameRepeat())
{
//有同名资源就中断打包
return false;
}
if (!_bundleCollector.CollectSceneBundles())
{
//可能有同名Scene
return false;
}
//if (!_bundleCollector.MergeSceneBundles())
//{
// return false;
//}
//处理AssetBundle分组
//_groupController.ModifyBundleNameByGroup();
BuildLog.Log("BuildBundles count:" + _context.bundleDataMap.Count);
if (!Directory.Exists(PathDefine.ConfigsRelative))
{
Directory.CreateDirectory(PathDefine.ConfigsRelative);
}
if (!GenerateBundleManifest() || !_sceneController.GenerateManifest() || !GenReferencesManifest())
{
return false;
}
BuildLog.Log($"AssetBundle GenerateManifests completed.");
return true;
}
///
/// 收集bundle信息,后期可能需要改成异步操作
///
///
///
private bool GenerateBundleManifest()
{
if (_context.bundleDataMap.Count == 0)
{
return false;
}
if (!_depsController.CollectBundleDependencies())
{
return false;
}
//BundleManifest
string bundleManifestPath = PathDefine.BundleManifestPath;//"Assets/KCAssetBundlesData/KCAssetBundleManifest.asset";
var kcBundleManifest = AssetDatabase.LoadAssetAtPath(bundleManifestPath);
if (kcBundleManifest == null)
{
kcBundleManifest = ScriptableObject.CreateInstance();
AssetDatabase.CreateAsset(kcBundleManifest, bundleManifestPath);
}
//bundle信息
var bundleDataLst = _context.SortAssetBundleDatas();
var count = bundleDataLst.Count;
var bundleInfos = new AssetBundleInfo[count];
var backupInfos = new AssetBundleBackupInfo[count];
for (var index = 0; index < count; index++)
{
var bundleData = bundleDataLst[index];
EditorUtility.DisplayProgressBar("Collect AssetBundleInfo", bundleData.assetBundleName, index / (float)count);
var dependencies = _context.dependenciesMap[bundleData.bundleId];
//var bundleId = CreateBundleId(build.assetBundleName, build.assetBundleVariant, build.addressableNames);
//var bytes = System.Text.Encoding.UTF8.GetBytes(bundleData.originBundleName);
//originBundleName大部分为guid,固定32字节,用bundleId取余数增加点offset的差异
var originName = bundleData.originBundleName;
var offset = (uint)Math.Clamp(bundleData.bundleId % originName.Length, 4, EncryptOffsetLimit);
var bundleInfo = new AssetBundleInfo()
{
bundleName = bundleData.assetBundleName,
variantName = bundleData.assetBundleVariant,
bundleId = bundleData.bundleId,
assets = bundleData.addressableNames,
dependencies = dependencies,
//originBundleName = originName,
offset = offset,
};
bundleInfos[index] = bundleInfo;
// 备份数据
var backupInfo = new AssetBundleBackupInfo()
{
bundleName = bundleData.assetBundleName,
variantName = bundleData.assetBundleVariant,
bundleId = bundleData.bundleId,
assets = bundleData.addressableNames,
dependencies = dependencies,
offset = offset,
bundleType = bundleData.bundleType,
nameOrGuid = originName,
originAssetPath = _context.bundleNameMode == AssetBundleNameMode.Guid ? AssetDatabase.GUIDToAssetPath(originName) : string.Empty,
};
backupInfos[index] = backupInfo;
}
EditorUtility.ClearProgressBar();
//保存
kcBundleManifest.bundleInfos = bundleInfos;
EditorUtility.SetDirty(kcBundleManifest);
AssetBundleBackupManifest.Save(backupInfos, false);
AssetDatabase.SaveAssets();
BuildLog.Log("Save BundleManifest.");
AssetDatabase.Refresh();
return true;
}
bool GenReferencesManifest()
{
string refManifestPath = PathDefine.ReferenceManifestPath;
var referenceManifest = AssetDatabase.LoadAssetAtPath(refManifestPath);
if (referenceManifest == null)
{
referenceManifest = ScriptableObject.CreateInstance();
AssetDatabase.CreateAsset(referenceManifest, refManifestPath);
}
//asset被引用信息
var assetReferencesMap = new Dictionary>();
//addressable信息
//ResStatic的bundle不允许动态加载,因此不需要记录引用信息
var addressableMap = _context.GetAddressableInfoMap();
var sw = new System.Diagnostics.Stopwatch();
foreach (var item in addressableMap)
{
if (_context.allTexturePaths.Contains(item.Key))
{
//忽略贴图资源
continue;
}
var assetPath = item.Key;
var assetAddressable = item.Value;
sw.Start();
var dependencies = AssetDatabase.GetDependencies(assetPath, true);
sw.Stop();
foreach (var dep in dependencies)
{
if (dep != assetPath && addressableMap.TryGetValue(dep, out var depAddressableName))
{ // 同bundle内的asset引用也需要记录
if (assetReferencesMap.TryGetValue(depAddressableName, out var referenceLst) == false)
{
referenceLst = new HashSet();
assetReferencesMap.Add(depAddressableName, referenceLst);
}
referenceLst.Add(assetAddressable);
}
}
}
BuildLog.Log($"GenReferencesManifest GetDependencies Time:{sw.ElapsedMilliseconds}");
AssetReferenceInfo[] referenceInfos = new AssetReferenceInfo[assetReferencesMap.Count];
int index = 0;
foreach (var item in assetReferencesMap)
{
referenceInfos[index++] = new AssetReferenceInfo()
{
assetName = item.Key,
references = item.Value.ToArray()
};
}
referenceManifest.references = referenceInfos;
EditorUtility.SetDirty(referenceManifest);
AssetDatabase.SaveAssets();
BuildLog.Log("Save ReferenceManifest.");
AssetDatabase.Refresh();
return true;
}
///
/// 检查Assetbundle内是否存在同名资源
///
///
///
private bool CheckAssetsNameRepeat()
{
bool result = true;
Dictionary assetPathMap = new Dictionary();
var allAssetPaths = new HashSet();
foreach (var item in _context.bundleDataMap)
{
assetPathMap.Clear();
foreach (var assetPath in item.Value.assetNames)
{
var fileName = Path.GetFileName(assetPath);
if (assetPathMap.ContainsKey(fileName))
{
result = false;
BuildLog.Error($"[XBuild] AssetBundle存在重名资源。Bundle:{item.Value.originBundleName} 重名资源1:{assetPathMap[fileName]} 重名资源2:{assetPath}");
}
else
{
assetPathMap.Add(fileName, assetPath);
}
if (allAssetPaths.Contains(assetPath))
{
BuildLog.Error($"[XBuild] AssetBundle存在重复资源。Path:{assetPath}");
result = false;
continue;
}
allAssetPaths.Add(assetPath);
}
}
return result;
}
}
}