123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- using XGame.Editor.Asset;
- using XGame.Framework.Asset.Addressable.Data;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEditor;
- using UnityEngine;
- using XGame.Framework.i18n;
- namespace XGame.Editor.Build.AssetBundles
- {
- /// <summary>
- /// assbundle的上下文
- /// </summary>
- public class BundleContext
- {
- public readonly string ResStaticDir = $"/{PathDefine.ResStaticName}/";
- public readonly string UiPrefabDir = "/UI/Prefabs/";
- public readonly string EditorDir = "/Editor/";
- public readonly string ResourcesDir = "/Resources/";
- public readonly string PrefabExt = ".prefab";
- public readonly string ShaderExt = ".shader";
- /// <summary>
- /// key:guid
- /// value:AssetInfo
- /// </summary>
- private Dictionary<string, AssetInfo> _assetInfoMap;
- /// <summary>
- /// key:assetPath
- /// value:guid
- /// </summary>
- private Dictionary<string, string> _assetPathToGuidMap;
- public Dictionary<long, AssetBundleData> bundleDataMap;
- /// <summary>
- /// key:bundleId
- /// value:dependencies
- /// </summary>
- private Dictionary<long, string[]> _bundleDependenciesMap;
- public HashSet<string> bundleAssetPaths;
- public Dictionary<long, uint[]> dependenciesMap;
- #region Addressable资源
- public string[] assetsRoots;
- /// <summary>
- /// 等待处理的资源
- /// </summary>
- public HashSet<string> waittingAssetPaths;
- #endregion
- /// <summary>
- /// 贴图资源没有依赖,缓存一份贴图路径数据节省一些判断
- /// </summary>
- public HashSet<string> allTexturePaths;
- public AssetBundleNameMode bundleNameMode;
- /// <summary>
- /// 是否合并shader
- /// </summary>
- public bool isMergeShader;
- /// <summary>
- /// ab分组名字
- /// key:assetPath
- /// value:groupName
- /// </summary>
- public Dictionary<string, string> groupNameMap;
- /// <summary>
- /// 排序好的AssetBundle数据
- /// </summary>
- private List<AssetBundleData> _bundleDataLst;
- /// <summary>
- /// 排序好的AssetBundle数据
- /// </summary>
- public List<AssetBundleData> BundleDataLst => _bundleDataLst;
- public BundleContext(Dictionary<string, AssetInfo> assetInfoMap)
- {
- _assetInfoMap = assetInfoMap;
- bundleDataMap = new Dictionary<long, AssetBundleData>();
- _bundleDependenciesMap = new Dictionary<long, string[]>();
- bundleAssetPaths = new HashSet<string>();
- dependenciesMap = new Dictionary<long, uint[]>();
- waittingAssetPaths = new HashSet<string>();
- allTexturePaths = new HashSet<string>();
- groupNameMap = new Dictionary<string, string>();
- Init();
- }
- private void Init()
- {
- _assetPathToGuidMap = new Dictionary<string, string>();
- foreach (var guid in _assetInfoMap.Keys)
- {
- var assetPath = AssetDatabase.GUIDToAssetPath(guid);
- if (!string.IsNullOrEmpty(assetPath))
- {
- _assetPathToGuidMap.Add(assetPath, guid);
- }
- }
- }
- #region addressable
- public bool IsAddressableAsset(string guid)
- {
- return _assetInfoMap.ContainsKey(guid);
- }
- public bool TryGetAddressableNameByGuid(string guid, out string addressableName)
- {
- if (_assetInfoMap.TryGetValue(guid, out var info))
- {
- addressableName = info.addressableName;
- return true;
- }
- addressableName = string.Empty;
- return false;
- }
- public bool TryGetAddressableNameByPath(string assetPath, out string addressableName)
- {
- if (_assetPathToGuidMap.TryGetValue(assetPath, out var guid))
- {
- addressableName = _assetInfoMap[guid].addressableName;
- return true;
- }
- addressableName = string.Empty;
- return false;
- }
- /// <summary>
- /// key:assetPath
- /// value:addressableName
- /// </summary>
- /// <returns></returns>
- public Dictionary<string, string> GetAddressableInfoMap()
- {
- var map = new Dictionary<string, string>();
- foreach(var item in _assetPathToGuidMap)
- {
- var assetInfo = _assetInfoMap[item.Value];
- if (!string.IsNullOrEmpty(assetInfo.relativePath))
- {
- //忽略Resources的资源
- continue;
- }
- map.Add(item.Key, assetInfo.addressableName);
- }
- return map;
- }
- /// <summary>
- /// 资源路径是否有效
- /// </summary>
- /// <param name="assetPath"></param>
- /// <returns></returns>
- public bool IsValidPath(string assetPath)
- {
- if (string.IsNullOrEmpty(assetPath))
- {
- return false;
- }
- foreach (var root in assetsRoots)
- {
- if (assetPath.StartsWith(root))
- {
- return true;
- }
- }
- return false;
- }
- #endregion
- /// <summary>
- /// 支持addressable加载
- /// 多语言的单独分文件夹
- /// 根据分组配置划分文件夹
- /// originGuid 用于生成bundleId,一般使用guid
- /// 默认为资源所属文件夹、图集为*.spriteatlas、单资源打包则为资源自己的guid
- /// </summary>
- /// <param name="assetPaths"></param>
- /// <param name="originGuid"></param>
- public void AddAddressableBundle(string[] assetPaths, string originGuid)
- {
- string groupName;
- var firstAsset = assetPaths[0];
- var langFlag = AddressableHelper.GetLanguageTypeByAssetPath(firstAsset);
- if (langFlag == LanguageType.NONE)
- {
- // 取Group配置
- groupNameMap.TryGetValue(firstAsset, out groupName);
- }
- else
- {
- groupName = langFlag.ToString().ToLower();
- }
- var originName = bundleNameMode == AssetBundleNameMode.Guid ? originGuid : AssetDatabase.GUIDToAssetPath(originGuid);
- var bundleId = Crc32.GetCrc32(originName);
- var count = assetPaths.Length;
- var addressableNames = new string[count];
- var isTextureBundle = true;
- for (var i = 0; i < count; i++)
- {
- var assetPath = assetPaths[i];
- if (isTextureBundle && allTexturePaths.Contains(assetPath) == false)
- { // 有一个资源非贴图
- isTextureBundle = false;
- }
- if (TryGetAddressableNameByPath(assetPath, out var addressableName) == false)
- {
- Debug.LogWarning($"Asset can't find addressableName. Path:{assetPath}");
- addressableName = assetPath;
- }
- addressableNames[i] = addressableName;
- // 移除等待
- waittingAssetPaths.Remove(assetPath);
- }
- var bundle = new AssetBundleData()
- {
- assetBundleName = string.IsNullOrEmpty(groupName) ? bundleId.ToString() : $"{groupName}/{bundleId}",
- assetBundleVariant = Framework.Asset.Define.BUNDLE_VARIANT,
- assetNames = assetPaths,
- addressableNames = addressableNames,
- bundleId = bundleId,
- originBundleName = originName,
- isTextureBundle = isTextureBundle,
- bundleType = AssetBundleType.Addressable
- };
- TryAddAssetBundle(ref bundle);
- }
- /// <summary>
- /// 普通的ab包,不支持addressable加载
- /// 全部生成在根目录下,不支持分组
- /// originName 用于生成bundleId,一般使用guid
- /// 默认为资源所属文件夹、图集为*.spriteatlas、单资源打包则为资源自己的guid
- /// </summary>
- /// <param name="assetPaths"></param>
- /// <param name="originName"></param>
- /// <param name="isDependency"></param>
- /// <returns></returns>
- public AssetBundleData AddRawAssetBundle(string[] assetPaths, string originName, bool isDependency)
- {
- if (bundleNameMode == AssetBundleNameMode.AssetPath && isDependency == false)
- {
- var path = AssetDatabase.GUIDToAssetPath(originName);
- if (string.IsNullOrEmpty(path))
- {
- Log.Error($"AddRawAssetBundle originName is not guid. originName:{originName}");
- }
- else
- {
- originName = path;
- }
- }
- var bundleId = Crc32.GetCrc32(originName);
- var bundle = new AssetBundleData()
- {
- assetBundleName = bundleId.ToString(),
- assetBundleVariant = Framework.Asset.Define.BUNDLE_VARIANT,
- assetNames = assetPaths,
- addressableNames = assetPaths,
- bundleId = bundleId,
- originBundleName = originName,
- isTextureBundle = IsTexturePaths(assetPaths),
- bundleType = isDependency ? AssetBundleType.Dependency : AssetBundleType.Raw
- };
- TryAddAssetBundle(ref bundle);
- return bundle;
- }
- private bool IsTexturePaths(string[] assetPaths)
- {
- foreach(var assetPath in assetPaths)
- {
- if (allTexturePaths.Contains(assetPath) == false)
- {
- return false;
- }
- }
- return true;
- }
- private void TryAddAssetBundle(ref AssetBundleData bundle)
- {
- var bundleId = bundle.bundleId;
- bundleAssetPaths.UnionWith(bundle.assetNames);
- if (bundleDataMap.ContainsKey(bundleId))
- {
- var lastName = bundleDataMap[bundleId].originBundleName;
- var nextName = bundle.originBundleName;
- Debug.LogError($"[XBuild] AssetBundleId重复. Id:{bundleId} LastName:{lastName} LastPath:{AssetDatabase.GUIDToAssetPath(lastName)} NextName:{nextName} NextPath:{AssetDatabase.GUIDToAssetPath(nextName)}");
- return;
- }
- bundleDataMap.Add(bundleId, bundle);
- }
- private List<string> tempLst = new List<string>();
- public string[] ToArrayBySort(HashSet<string> assetPaths)
- {
- if (assetPaths.Count > 1)
- {
- tempLst.AddRange(assetPaths);
- tempLst.Sort((a, b) => string.Compare(a, b, StringComparison.OrdinalIgnoreCase));
- var array = tempLst.ToArray();
- tempLst.Clear();
- return array;
- }
- return assetPaths.ToArray();
- }
- /// <summary>
- /// 将所有AssetBundleData转成List并排序
- /// </summary>
- public List<AssetBundleData> SortAssetBundleDatas()
- {
- _bundleDataLst = bundleDataMap.Values.ToList();
- _bundleDataLst.Sort(CompareAssetBundle);
- return _bundleDataLst;
- }
- public int CompareAssetBundle(AssetBundleData bundleA, AssetBundleData bundleB)
- {
- if (bundleNameMode == AssetBundleNameMode.AssetPath)
- {
- var guidA = AssetDatabase.AssetPathToGUID(bundleA.originBundleName);
- var guidB = AssetDatabase.AssetPathToGUID(bundleB.originBundleName);
- //有assetPath的bundle排前面
- var idx_0 = string.IsNullOrEmpty(guidA) == false ? -1 : 1;
- var idx_1 = string.IsNullOrEmpty(guidB) == false ? -1 : 1;
- var remain = idx_0 - idx_1;
- if (remain != 0)
- {
- return remain;
- }
- }
- else
- {
- var pathA = AssetDatabase.GUIDToAssetPath(bundleA.originBundleName);
- var pathB = AssetDatabase.GUIDToAssetPath(bundleB.originBundleName);
- //有assetPath的bundle排前面
- var idx_0 = string.IsNullOrEmpty(pathA) == false ? -1 : 1;
- var idx_1 = string.IsNullOrEmpty(pathB) == false ? -1 : 1;
- var remain = idx_0 - idx_1;
- if (remain != 0)
- {
- return remain;
- }
- if (idx_0 == -1)
- {
- return string.Compare(pathA, pathB, StringComparison.OrdinalIgnoreCase);
- }
- }
- return string.Compare(bundleA.originBundleName, bundleB.originBundleName, StringComparison.OrdinalIgnoreCase);
- }
- public System.Diagnostics.Stopwatch bundleDependenciesSw = new System.Diagnostics.Stopwatch();
- public string[] GetDependencies(uint bundleId, string[] assetNames)
- {
- if (_bundleDependenciesMap.TryGetValue(bundleId, out var dependencies) == false)
- {
- bundleDependenciesSw.Start();
- dependencies = AssetDatabase.GetDependencies(assetNames, true);
- bundleDependenciesSw.Stop();
- _bundleDependenciesMap.Add(bundleId, dependencies);
- }
- return dependencies;
- }
- }
- }
|