123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- using XGame.Editor.Asset;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using UnityEditor;
- using UnityEngine;
- namespace XGame.Editor.Build.AssetBundles
- {
- public class DepBundleCollector
- {
- private BundleContext _context;
- public DepBundleCollector(BundleContext context)
- {
- _context = context;
- }
- /// <summary>
- /// 收集ResStatic目录下被引用的资源
- /// </summary>
- /// <param name="assetBundleBuilds"></param>
- /// <param name="filePaths"></param>
- public void Collect()
- {
- //<assetPath, List<bundleName>>
- var refBundlesMap = new Dictionary<string, HashSet<long>>();
- foreach (var item in _context.bundleDataMap)
- {
- if (item.Value.isTextureBundle)
- {
- continue;
- }
- var assetDependencies = _context.GetDependencies(item.Value.bundleId, item.Value.assetNames);
- foreach (var dependency in assetDependencies)
- {
- if (_context.bundleAssetPaths.Contains(dependency) || Asset.FileUtil.IsFileIgnore(dependency))
- continue;
- if (dependency.Contains(_context.ResStaticDir))
- {
- if (dependency.Contains(_context.UiPrefabDir) && dependency.EndsWith(_context.PrefabExt, StringComparison.OrdinalIgnoreCase))
- {
- //忽略ResStatic下的UI预制
- continue;
- }
- }
- else if (dependency.StartsWith(PathDefine.PackageRelative, StringComparison.OrdinalIgnoreCase))
- {
- if (dependency.EndsWith(_context.PrefabExt, StringComparison.OrdinalIgnoreCase))
- {
- //忽略预制体文件
- //Debug.LogWarning($"Bundle:{build.Value.bundleId} 依赖了Editor或者Resources资源. dependency:{dependency}");
- continue;
- }
- }
- else
- {
- //if (dependency.StartsWith(PathDefine.ResourcesRelative, StringComparison.OrdinalIgnoreCase))
- //{
- // Debug.LogWarning($"Bundle:{build.Value.bundleId} 依赖了Resources资源. dependency:{dependency}");
- //}
- continue;
- }
- if (!refBundlesMap.TryGetValue(dependency, out var bundles))
- {
- bundles = new HashSet<long>();
- refBundlesMap.Add(dependency, bundles);
- }
- if (!bundles.Contains(item.Value.bundleId))
- {
- bundles.Add(item.Value.bundleId);
- }
- //Debug.Log($"ResStatic dependency :{dependency} dir:{dir}");
- }
- }
- //<assetPath, bundleNames>
- var bundleNamesMap = new Dictionary<string, string>();
- foreach (var item in refBundlesMap)
- {
- //只被单个bundle引用的,不需要单独打包bundle
- if (item.Value.Count < 2) continue;
- var str = string.Join('_', item.Value);
- bundleNamesMap.Add(item.Key, str);
- }
- var groups = bundleNamesMap.GroupBy(p => p.Value);
- //由于AssetBundle的资源重名只认资源文件名,因此这里做好重名检测
- //用于排序,减少二次分包的次数
- var assetPaths = new List<string>();
- var fileNames = new HashSet<string>();
- foreach (var group in groups)
- {
- //先取出所有assetPath
- foreach (var item in group)
- {
- assetPaths.Add(item.Key);
- }
- //排序
- assetPaths.Sort((a, b) => string.Compare(a, b, StringComparison.OrdinalIgnoreCase));
- //是否重名
- var isNameSake = false;
- foreach (var assetPath in assetPaths)
- {
- var fileName = Path.GetFileName(assetPath);
- if (!fileNames.Add(fileName))
- {
- //有重名
- isNameSake = true;
- break;
- }
- }
- if (isNameSake)
- {
- var depAssetsMap = AssetsGroupByDependencies(assetPaths);
- //生成依赖包,bundleName由引用的BundleId拼接而成
- var firstKey = "0";
- var assets = depAssetsMap[firstKey];
- var bundleBuild = _context.AddRawAssetBundle(assets, group.Key, true);
- //var bundleBuild = new AssetBundleData(group.Key, KCDefine.BUNDLE_VARIANT, assets, assets);
- //_context.bundleBuildMap.TryAdd(bundleBuild);
- depAssetsMap.Remove(firstKey);
- foreach (var item in depAssetsMap)
- {
- var bundleName = $"{bundleBuild.bundleId}_{item.Key}";
- assets = item.Value;
- _context.AddRawAssetBundle(assets, bundleName, true);
- //var depBundle = new AssetBundleData(bundleName, KCDefine.BUNDLE_VARIANT, assets, assets);
- //_context.bundleBuildMap.TryAdd(depBundle);
- }
- }
- else
- {
- //生成依赖包,bundleName由引用的BundleId拼接而成
- var assets = assetPaths.ToArray();
- _context.AddRawAssetBundle(assets, group.Key, true);
- //var bundleBuild = new AssetBundleData(group.Key, KCDefine.BUNDLE_VARIANT, assets, assets);
- //_context.bundleBuildMap.TryAdd(bundleBuild);
- }
- assetPaths.Clear();
- fileNames.Clear();
- }
- }
- /// <summary>
- /// Assets根据依赖关系二次分组
- /// 返回<groupId, assetPath[]>
- /// </summary>
- /// <param name="assetPaths"></param>
- /// <returns></returns>
- private Dictionary<string, string[]> AssetsGroupByDependencies(List<string> assetPaths)
- {
- var result = new Dictionary<string, string[]>();
- var assetDependencies = new Dictionary<string, string[]>();
- var dependencies = new List<string>();
- //先收集assetPaths之间的依赖信息
- foreach (var assetPath in assetPaths)
- {
- var deps = AssetDatabase.GetDependencies(assetPath, true);
- foreach (var dep in deps)
- {
- if (!assetPath.Equals(dep) && assetPaths.Contains(dep))
- {
- dependencies.Add(dep);
- }
- }
- assetDependencies.Add(assetPath, dependencies.ToArray());
- dependencies.Clear();
- }
- var assetGroupMap = new Dictionary<string, int>();
- var pendingPaths = new List<string>();
- foreach (var item in assetDependencies)
- {
- if (item.Value.Length > 0)
- {
- pendingPaths.Add(item.Key);
- }
- else
- {
- //没有依赖的资源,直接保存到assetGroupMap
- assetGroupMap.Add(item.Key, 0);
- }
- }
- var groupId = 1;
- var tempPaths = new List<string>();
- var fileNames = new HashSet<string>();
- //递归查询
- while (pendingPaths.Count > 0)
- {
- foreach (var assetPath in pendingPaths)
- {
- var isTrue = true;
- foreach (var dep in assetDependencies[assetPath])
- {
- if (!assetGroupMap.ContainsKey(dep))
- {
- isTrue = false;
- break;
- }
- }
- if (isTrue)
- {
- //assetPath依赖的资源都有分组记录
- tempPaths.Add(assetPath);
- }
- }
- if (tempPaths.Count > 0)
- {
- //新增分组
- foreach (var assetPath in tempPaths)
- {
- pendingPaths.Remove(assetPath);
- assetGroupMap.Add(assetPath, groupId);
- }
- groupId += 1;
- tempPaths.Clear();
- }
- else
- {
- //有互相依赖的资源,直接归为同一个分组,这里面可能有重名的资源
- //由CheckAssetsNameRepeat方法统一报错处理
- var isNameSake = false;
- foreach (var assetPath in pendingPaths)
- {
- var fileName = Path.GetFileName(assetPath);
- if (!fileNames.Add(fileName))
- {
- //有重名资源
- isNameSake = true;
- break;
- }
- }
- if (isNameSake)
- {
- BuildLog.Error($"DepAssetbundle Group Error: 存在同名文件且Asset之间互相依赖。");
- foreach (var assetPath in pendingPaths)
- {
- BuildLog.Error($"Error File:{assetPath}");
- }
- }
- result.Add(groupId.ToString(), pendingPaths.ToArray());
- pendingPaths.Clear();
- fileNames.Clear();
- }
- }
- var groups = assetGroupMap.GroupBy(item => item.Value);
- foreach (var group in groups)
- {
- foreach (var item in group)
- {
- var assetPath = item.Key;
- var fileName = Path.GetFileName(assetPath);
- if (fileNames.Add(fileName))
- {
- tempPaths.Add(assetPath);
- }
- else
- {
- //有同名文件,该文件直接单独打包
- var guid = AssetDatabase.AssetPathToGUID(assetPath);
- result.Add($"{item.Value}_{guid}", new string[] { assetPath });
- }
- }
- if (tempPaths.Count > 0)
- {
- result.Add(group.Key.ToString(), tempPaths.ToArray());
- }
- else
- {
- BuildLog.Error($"DepAssetbundle Group Error: GroupId:{group.Key} Count:{group.Count()} 分组数据为空。");
- }
- tempPaths.Clear();
- fileNames.Clear();
- }
- return result;
- }
- }
- }
|