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; } } }