using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace XGame.Editor.Build.AssetBundles
{
///
/// 收集bundle依赖
///
internal class BundleDepsController
{
private BundleContext _context;
public BundleDepsController(BundleContext context)
{
_context = context;
}
///
/// key: assetPath
/// value: bundleId
///
///
private Dictionary GetAssetPathMap()
{
var assetPathMap = new Dictionary();
foreach (var keyValue in _context.bundleDataMap)
{
var build = keyValue.Value;
foreach (var assetPath in build.assetNames)
{
if (assetPathMap.ContainsKey(assetPath))
{
BuildLog.Error($"assetPath repeat. Id:{build.bundleId} Name:{build.originBundleName} Asset:{assetPath}");
}
else
{
assetPathMap.Add(assetPath, build.bundleId);
}
}
}
return assetPathMap;
}
///
/// 收集所有bundle的依赖bundleId
///
///
public bool CollectBundleDependencies()
{
var assetPathToBundleIdMap = GetAssetPathMap();
var dependenciesMap = _context.dependenciesMap;
dependenciesMap.Clear();
var depAssetsMap = new Dictionary>();
int index = 0;
var tempAssetPaths = new HashSet();
foreach (var item in _context.bundleDataMap)
{
EditorUtility.DisplayProgressBar("Collect Asset Dependencies", item.Value.assetBundleName, (++index) / (float)_context.bundleDataMap.Count);
tempAssetPaths.UnionWith(item.Value.assetNames);
var assetPaths = new HashSet();
if (item.Value.isTextureBundle == false)
{ //全是贴图的bundle不用查找
var dependencies = _context.GetDependencies(item.Value.bundleId, item.Value.assetNames);
foreach (var depPath in dependencies)
{
if (assetPathToBundleIdMap.ContainsKey(depPath) && !tempAssetPaths.Contains(depPath))
{
assetPaths.Add(depPath);
}
}
}
depAssetsMap.Add(item.Key, assetPaths);
tempAssetPaths.Clear();
}
EditorUtility.ClearProgressBar();
Debug.Log($"AssetBundle GetDependencies Time:{_context.bundleDependenciesSw.ElapsedMilliseconds}");
var bundleIds = new HashSet();
foreach (var item in depAssetsMap)
{
if (item.Value.Count == 0)
{
dependenciesMap.Add(item.Key, new uint[0]);
//Debug.Log($"Assetbundle依赖为零. Name:{item.Key}");
}
else
{
bundleIds.Add(item.Key);
}
}
var tempIds = new HashSet();
var depBundleIds = new List();
while (bundleIds.Count > 0)
{
EditorUtility.DisplayProgressBar("Collect Bundle Dependencies", $"剩余: {bundleIds.Count}", dependenciesMap.Count / (float)_context.bundleDataMap.Count);
foreach (var bundleId in bundleIds)
{
var dependencies = depAssetsMap[bundleId];
var isTrue = true;
foreach (var dependency in dependencies)
{
var depBundleId = assetPathToBundleIdMap[dependency];
if (!dependenciesMap.ContainsKey(depBundleId))
{
isTrue = false;
break;
}
}
if (isTrue)
{
tempIds.Add(bundleId);
}
}
if (tempIds.Count > 0)
{
foreach (var bundleId in tempIds)
{
bundleIds.Remove(bundleId);
var dependencies = depAssetsMap[bundleId];
foreach (var dependency in dependencies)
{
var depId = (uint)assetPathToBundleIdMap[dependency];
depBundleIds.Add(depId);
depBundleIds.AddRange(dependenciesMap[depId]);
//if (bundleId == 2940165715 || bundleId == 1899048051 || bundleId == 2238712722)
//{
// var sb = new System.Text.StringBuilder();
// sb.Append(bundleId);
// sb.Append(" depBundle:");
// sb.Append(depId);
// sb.Append(" dependencies:");
// foreach (var item in depBundleIdsMap[depId])
// {
// sb.Append(item);
// sb.Append("; ");
// }
// Debug.Log(sb.ToString());
//}
}
depBundleIds = depBundleIds.Distinct().ToList();
depBundleIds.Remove((uint)bundleId);
dependenciesMap.Add(bundleId, depBundleIds.ToArray());
depBundleIds.Clear();
}
tempIds.Clear();
}
else
{
EditorUtility.ClearProgressBar();
//理论上这个肯定不会触发
Log.Error($"CollectBundleDependencies failed. 如果是Assetbundle出现互相依赖,请调整相关资源使相互依赖的Asset在同一个Assetbundle内. Success: {dependenciesMap.Count} Failure: {bundleIds.Count}");
foreach (var bundleId in bundleIds)
{
var build = _context.bundleDataMap[bundleId];
var dependencies = depAssetsMap[bundleId];
foreach (var dep in dependencies)
{
if (assetPathToBundleIdMap.TryGetValue(dep, out var depBundleId) && dependenciesMap.ContainsKey(depBundleId) == false)
{
Log.Error($"bundleId:{bundleId} Name:{build.originBundleName} dependence:{dep} depBundleId:{depBundleId}");
}
}
}
return false;
}
}
EditorUtility.ClearProgressBar();
return true;
}
}
}