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