using System; using System.IO; using System.Collections; using System.Collections.Generic; using UnityEngine; using Cysharp.Threading.Tasks; public class AssetBundleUtility : SingletonMonobehaviour { private List m_AssetBundleInfoList = new List(); private List m_LoadingAssetBundleList = new List(); private List m_LoadingAssetList = new List(); private Dictionary m_AssetInfoDict = new Dictionary(); private Dictionary m_AssetBundleDict = new Dictionary(); private Dictionary> m_AssetDict = new Dictionary>(); public bool initialized { get; private set; } public bool initializedUIAssetBundle { get; private set; } public void InitBuiltInAsset() { var path = AssetVersionUtility.GetBuiltInAssetFilePath(StringUtility.Contact(AssetVersionUtility.EncodeFileName("builtin"), "_assetbundle"), false); var assetBundle = AssetBundle.LoadFromFile(path); if (assetBundle == null) { Debug.LogErrorFormat("AssetBundleManifest的包文件为空或者加载出错. Path:{0}", path); } var manifest = assetBundle.LoadAsset(ResourcesPath.AssetDependentFileAssetName); if (manifest == null) { Debug.LogErrorFormat("AssetBundleManifest的包文件为空或者加载出错. Path:{0}", path); } var bundles = manifest.GetAllAssetBundles(); foreach (var bundle in bundles) { var dependenices = manifest.GetAllDependencies(bundle); var hash = manifest.GetAssetBundleHash(bundle); var assetBundleInfo = new AssetBundleInfo(bundle, hash, dependenices); m_AssetBundleInfoList.Add(assetBundleInfo); } assetBundle.Unload(true); assetBundle = null; } public void ReInitBuiltInAsset() { // WindowConfig.Release(); // CloseAllIgnoreWindowConfig.Release(); UnloadAssetBundle("builtin/scriptableobjects", true, false); var path = AssetVersionUtility.GetBuiltInAssetFilePath(StringUtility.Contact(AssetVersionUtility.EncodeFileName("builtin"), "_assetbundle"), false); var assetBundle = AssetBundle.LoadFromFile(path); if (assetBundle == null) { Debug.LogErrorFormat("AssetBundleManifest的包文件为空或者加载出错. Path:{0}", path); } var manifest = assetBundle.LoadAsset(ResourcesPath.AssetDependentFileAssetName); if (manifest == null) { Debug.LogErrorFormat("AssetBundleManifest的包文件为空或者加载出错. Path:{0}", path); } for (int i = m_AssetBundleInfoList.Count - 1; i >= 0; i--) { var item = m_AssetBundleInfoList[i]; if (item.name.Contains("builtin")) { m_AssetBundleInfoList.Remove(item); } } var keys = new List(m_AssetBundleDict.Keys); for (int i = keys.Count - 1; i >= 0; i--) { var item = keys[i]; if (item.Contains("builtin")) { m_AssetBundleDict[item].Unload(false); m_AssetBundleDict.Remove(item); } } var bundles = manifest.GetAllAssetBundles(); foreach (var bundle in bundles) { var dependenices = manifest.GetAllDependencies(bundle); var hash = manifest.GetAssetBundleHash(bundle); var assetBundleInfo = new AssetBundleInfo(bundle, hash, dependenices); m_AssetBundleInfoList.Add(assetBundleInfo); } assetBundle.Unload(true); assetBundle = null; } public async UniTask Initialize() { await Co_LoadMainfestFile("audio"); await Co_LoadMainfestFile("video"); await Co_LoadMainfestFile("mobeffectshader"); await Co_LoadMainfestFile("config"); await Co_LoadMainfestFile("maps"); await Co_LoadMainfestFile("ui"); await Co_LoadAssetBundle(ResourcesPath.windowFileBundleName); await Co_LoadAssetBundle(ResourcesPath.uiprefabFileBundleName); initializedUIAssetBundle = true; initialized = true; } private async UniTask Co_LoadMainfestFile(string _category) { var path = AssetVersionUtility.GetAssetFilePath(StringUtility.Contact(AssetVersionUtility.EncodeFileName(_category), "_assetbundle"), false); var _assetBundle = AssetBundle.LoadFromFile(path); if (_assetBundle == null) { Debug.LogErrorFormat("AssetBundleManifest的包文件为空或者加载出错. Path:{0}", path); return; } AssetBundleManifest _assetBundleManifest = _assetBundle.LoadAsset(ResourcesPath.AssetDependentFileAssetName); if (_assetBundleManifest == null) { Debug.LogErrorFormat("AssetBundleManifest的包文件为空或者加载出错. Path:{0}", path); return; } string[] _assetBundleNames = _assetBundleManifest.GetAllAssetBundles(); foreach (var _assetBundleName in _assetBundleNames) { string[] _dependenices = _assetBundleManifest.GetAllDependencies(_assetBundleName); Hash128 _hash = _assetBundleManifest.GetAssetBundleHash(_assetBundleName); AssetBundleInfo _assetBundleInfo = new AssetBundleInfo(_assetBundleName, _hash, _dependenices); m_AssetBundleInfoList.Add(_assetBundleInfo); } _assetBundle.Unload(true); _assetBundle = null; } public AssetBundleInfo GetAssetBundleInfo(string assetBundleName) { return m_AssetBundleInfoList.Find((x) => { return x.name == assetBundleName; }); } #region 对AssetBundle资源进行异步协程加载的方法 public void Co_LoadAsset(AssetInfo assetInfo, Action callBack = null) { Co_LoadAsset(assetInfo.assetBundleName, assetInfo.name, callBack); } public void Co_LoadAsset(string assetBundleName, string assetName, Action callBack = null) { #if UNITY_5||UNITY_5_3_OR_NEWER assetBundleName = assetBundleName.ToLower(); #endif if (JudgeExistAsset(assetBundleName, assetName)) { if (callBack != null) { callBack(true, m_AssetDict[assetBundleName][assetName]); } return; } Co_DoLoadAsset(assetBundleName, assetName, callBack).Forget(); } private async UniTask Co_LoadAssetBundle(string assetBundleName) { #if UNITY_5||UNITY_5_3_OR_NEWER assetBundleName = assetBundleName.ToLower(); #endif if (JudgeExistAssetBundle(assetBundleName)) { return m_AssetBundleDict[assetBundleName]; } if (m_LoadingAssetBundleList.Contains(assetBundleName)) { while (!m_AssetBundleDict.ContainsKey(assetBundleName)) { // Debug.Log(Time.frameCount + " ] 正在加载AssetBundle: " + assetBundleName + ", 请等待..."); await UniTask.Yield(); } return m_AssetBundleDict[assetBundleName]; } m_LoadingAssetBundleList.Add(assetBundleName); var _assetBundleInfo = GetAssetBundleInfo(assetBundleName); if (_assetBundleInfo == null) { Debug.LogErrorFormat("Co_LoadAssetBundle(): {0}出现错误 => 不存在AssetBundleInfo. ", assetBundleName); m_LoadingAssetBundleList.Remove(assetBundleName); return null; } if (_assetBundleInfo.dependentBundles.Length > 0) { await Co_LoadAssetBundleDependenice(_assetBundleInfo); } var isBuiltin = assetBundleName.Contains("builtin"); var filePath = isBuiltin ? AssetVersionUtility.GetBuiltInAssetFilePath(assetBundleName) : AssetVersionUtility.GetAssetFilePath(assetBundleName); Debug.LogFormat("Co_LoadAssetBundle(): 将要加载的assetBundle包路径 => {0}", filePath); var _request = AssetBundle.LoadFromFileAsync(filePath); await _request; CacheAssetBundle(assetBundleName, _request.assetBundle); m_LoadingAssetBundleList.Remove(assetBundleName); return _request.assetBundle; } private async UniTask Co_LoadAssetBundleDependenice(AssetBundleInfo assetBundleInfo) { AssetBundle _assetBundle = null; if (assetBundleInfo.dependentBundles == null || assetBundleInfo.dependentBundles.Length == 0) { return; } for (int i = 0; i < assetBundleInfo.dependentBundles.Length; ++i) { if (m_AssetBundleDict.TryGetValue(assetBundleInfo.dependentBundles[i], out _assetBundle) == false) { await Co_LoadAssetBundle(assetBundleInfo.dependentBundles[i]); } else { if (_assetBundle == null) { await Co_LoadAssetBundle(assetBundleInfo.dependentBundles[i]); } } } } private async UniTask Co_DoLoadAsset(string assetBundleName, string assetName, Action callBack = null) { #if UNITY_5||UNITY_5_3_OR_NEWER assetBundleName = assetBundleName.ToLower(); #endif #if UNITY_EDITOR RunTimeABLoadLog.AddLog(assetBundleName, assetName, UnityEngine.SceneManagement.SceneManager.GetActiveScene().name); #endif await Co_LoadAssetBundle(assetBundleName); if (!m_AssetBundleDict.ContainsKey(assetBundleName)) { if (callBack != null) { callBack(false, null); } return; } string _checkTag = assetBundleName + "@" + assetName; if (m_LoadingAssetList.Contains(_checkTag)) { while (!m_AssetDict.ContainsKey(assetBundleName) || !m_AssetDict[assetBundleName].ContainsKey(assetName)) { // Debug.Log(Time.frameCount + " ] 正在加载Asset: " + _checkTag + ", 请等待..."); await UniTask.Yield(); } if (callBack != null) { callBack(true, m_AssetDict[assetBundleName][assetName]); } return; } m_LoadingAssetList.Add(_checkTag); var request = m_AssetBundleDict[assetBundleName].LoadAssetAsync(assetName); await request; if (request.asset != null) { CacheAsset(assetBundleName, assetName, request.asset); if (callBack != null) { callBack(true, m_AssetDict[assetBundleName][assetName]); } } else { if (callBack != null) { callBack(false, null); } } m_LoadingAssetList.Remove(_checkTag); } private async UniTask Co_DoLoadAsset(AssetInfo assetInfo, Action callBack = null) { if (assetInfo == null) { Debug.LogErrorFormat("Co_DoLoadAsset(): {0}, 出现错误 => 存入的AssetInfo为null. ", assetInfo); return; } await Co_DoLoadAsset(assetInfo.assetBundleName, assetInfo.name, callBack); } #endregion #region 对AssetBundle资源进行同步加载的方法 public void Sync_LoadAll(string assetBundleName) { if (JudgeExistAssetBundle(assetBundleName)) { return; } #if UNITY_5||UNITY_5_3_OR_NEWER assetBundleName = assetBundleName.ToLower(); #endif Sync_LoadAssetBundle(assetBundleName); } public void Sync_LoadAllAssets(string assetBundleName) { if (JudgeExistAssetBundle(assetBundleName)) { return; } #if UNITY_5||UNITY_5_3_OR_NEWER assetBundleName = assetBundleName.ToLower(); #endif Sync_LoadAssetBundle(assetBundleName); if (m_AssetBundleDict.ContainsKey(assetBundleName)) { var assetBundle = m_AssetBundleDict[assetBundleName]; assetBundle.LoadAllAssets(); } } public UnityEngine.Object Sync_LoadAsset(AssetInfo assetInfo, Type _type = null) { return Sync_LoadAsset(assetInfo.assetBundleName, assetInfo.name, _type); } public UnityEngine.Object Sync_LoadAsset(string assetBundleName, string assetName, Type _type = null) { #if UNITY_5||UNITY_5_3_OR_NEWER assetBundleName = assetBundleName.ToLower(); #endif UnityEngine.Object _object = null; if (JudgeExistAsset(assetBundleName, assetName)) { _object = m_AssetDict[assetBundleName][assetName]; } else { #if UNITY_EDITOR RunTimeABLoadLog.AddLog(assetBundleName, assetName, UnityEngine.SceneManagement.SceneManager.GetActiveScene().name); #endif Sync_LoadAssetBundle(assetBundleName); if (m_AssetBundleDict.ContainsKey(assetBundleName)) { if (_type != null) { _object = m_AssetBundleDict[assetBundleName].LoadAsset(assetName, _type); } else { _object = m_AssetBundleDict[assetBundleName].LoadAsset(assetName); } if (_object != null) { CacheAsset(assetBundleName, assetName, _object); } } } if (_object == null) { Debug.LogErrorFormat("Sync_LoadAsset(): {0} 出现错误 => null. ", assetName); } return _object; } private void Sync_LoadAssetBundle(string assetBundleName) { if (JudgeExistAssetBundle(assetBundleName)) { return; } AssetBundleInfo _assetBundleInfo = GetAssetBundleInfo(assetBundleName); if (_assetBundleInfo == null) { Debug.LogErrorFormat("Sync_LoadAssetBundle(): {0} 出现错误 => 不存在AssetBundleInfo. ", assetBundleName); return; } Sync_LoadAssetBundleDependenice(_assetBundleInfo); var isBuiltin = assetBundleName.Contains("builtin"); string _path = isBuiltin ? AssetVersionUtility.GetBuiltInAssetFilePath(assetBundleName) : AssetVersionUtility.GetAssetFilePath(assetBundleName); AssetBundle _assetBundle = AssetBundle.LoadFromFile(_path); CacheAssetBundle(assetBundleName, _assetBundle); } private void Sync_LoadAssetBundleDependenice(AssetBundleInfo assetBundleInfo) { if (assetBundleInfo.dependentBundles == null || assetBundleInfo.dependentBundles.Length == 0) { return; } AssetBundle _assetBundle = null; for (int i = 0; i < assetBundleInfo.dependentBundles.Length; ++i) { if (m_AssetBundleDict.TryGetValue(assetBundleInfo.dependentBundles[i], out _assetBundle) == false) { Sync_LoadAssetBundle(assetBundleInfo.dependentBundles[i]); } else { if (_assetBundle == null) { Sync_LoadAssetBundle(assetBundleInfo.dependentBundles[i]); } } } } #endregion #region 对AssetBundle资源进行异步线程加载的方法 #endregion #region AssetBundle资源卸载方法 public void UnloadAssetBundle(string assetBundleName, bool unloadAllLoadedObjects, bool includeDependenice) { #if UNITY_5||UNITY_5_3_OR_NEWER assetBundleName = assetBundleName.ToLower(); #endif if (JudgeExistAssetBundle(assetBundleName) == false) { Debug.LogWarningFormat("UnloadAssetBundle(): 要卸载的包不在缓存中或者已经被卸载 => {0}. ", assetBundleName); return; } AssetBundleInfo _assetBundleInfo = GetAssetBundleInfo(assetBundleName); UnloadAssetBundle(_assetBundleInfo, unloadAllLoadedObjects, includeDependenice); } public void UnloadAsset(string assetBundleName, string assetName) { #if UNITY_5||UNITY_5_3_OR_NEWER assetBundleName = assetBundleName.ToLower(); #endif string _assembleName = StringUtility.Contact(assetBundleName, "@", assetName); if (JudgeExistAsset(assetBundleName, assetName) == false) { Debug.LogWarningFormat("UnloadAsset(): 要卸载的资源不在缓存中 => {0}. ", _assembleName); return; } UnityEngine.Object _assetObject = m_AssetDict[assetBundleName][assetName]; m_AssetDict[assetBundleName].Remove(assetName); if (_assetObject is GameObject) { Debug.LogFormat("UnloadAsset(): 成功卸载asset资源 => {0}. 类型为{1}, 不做其他处理. ", assetName, _assetObject.GetType().Name); } else { Resources.UnloadAsset(_assetObject); Debug.LogFormat("UnloadAsset(): 成功卸载asset资源 => {0}. 类型为{1}, 执行Resources.UnloadAsset(). ", assetName, _assetObject.GetType().Name); } if (Application.isEditor) { Transform _asset = transform.Find(assetBundleName + "/Asset:" + assetName); if (_asset) { Destroy(_asset.gameObject); } } } public void UnloadAsset(AssetInfo assetInfo) { UnloadAsset(assetInfo.assetBundleName, assetInfo.name); } public void UnloadAll() { List _assetBundleNameList = new List(m_AssetBundleDict.Keys); foreach (var _assetBundleName in _assetBundleNameList) { UnloadAssetBundle(_assetBundleName, true, true); } } private void UnloadAssetBundle(AssetBundleInfo assetBundleInfo, bool unloadAllLoadedObjects, bool includeDependenice) { // 是否卸载依赖资源 if (includeDependenice) { if (assetBundleInfo.dependentBundles != null && assetBundleInfo.dependentBundles.Length > 0) { for (int i = 0; i < assetBundleInfo.dependentBundles.Length; ++i) { UnloadAssetBundle(assetBundleInfo.dependentBundles[i], unloadAllLoadedObjects, includeDependenice); } } } if (m_AssetDict.ContainsKey(assetBundleInfo.name)) { List _assetNames = new List(m_AssetDict[assetBundleInfo.name].Keys); // 卸载对应缓存住的asset资源 foreach (var _assetName in _assetNames) { UnloadAsset(assetBundleInfo.name, _assetName); } m_AssetDict.Remove(assetBundleInfo.name); } else { Debug.LogFormat("UnloadAssetBundle(): 要卸载assetBundle包 {0} 没有资源被加载. ", assetBundleInfo.name); } // assetBundle包卸载 m_AssetBundleDict[assetBundleInfo.name].Unload(unloadAllLoadedObjects); //m_AssetDict.Remove(assetBundleInfo.name); // 卸载缓存的assetBundle资源 m_AssetBundleDict.Remove(assetBundleInfo.name); Debug.LogFormat("UnloadAssetBundle(): 成功卸载assetBundle包 => {0}. ", assetBundleInfo.name); if (Application.isEditor) { Transform _asset = transform.Find(assetBundleInfo.name); Transform _parent = _asset.parent; if (_asset) { DestroyImmediate(_asset.gameObject); } if (_parent.childCount == 0 && _parent != transform) { DestroyImmediate(_parent.gameObject); } } } #endregion public bool JudgeExistAsset(string assetBundleName, string assetName) { #if UNITY_5||UNITY_5_3_OR_NEWER assetBundleName = assetBundleName.ToLower(); #endif if (string.IsNullOrEmpty(assetBundleName) || string.IsNullOrEmpty(assetName)) { return false; } if (JudgeExistAssetBundle(assetBundleName) == false) { return false; } if (m_AssetDict.ContainsKey(assetBundleName) == false || m_AssetDict[assetBundleName].ContainsKey(assetName) == false || m_AssetDict[assetBundleName][assetName] == null) { return false; } return true; } public bool JudgeExistAssetBundle(string assetBundleName) { assetBundleName = assetBundleName.ToLower(); if (m_AssetBundleDict.ContainsKey(assetBundleName) == false) { return false; } if (m_AssetBundleDict[assetBundleName] == null) { return false; } return true; } private void CacheAsset(string assetBundleName, string assetName, UnityEngine.Object asset) { if (asset == null) { return; } if (asset is GameObject) { (asset as GameObject).SetActive(true); } if (m_AssetDict.ContainsKey(assetBundleName) == false) { Dictionary _temp = new Dictionary(); m_AssetDict.Add(assetBundleName, _temp); } m_AssetDict[assetBundleName][assetName] = asset; string _assembleName = StringUtility.Contact(assetBundleName, "@", assetName); if (m_AssetInfoDict.ContainsKey(_assembleName) == false) { AssetInfo _assetInfo = new AssetInfo(assetBundleName, assetName); m_AssetInfoDict[_assembleName] = _assetInfo; } Debug.LogFormat("CacheAsset(): 成功缓存asset => {0}. ", assetName); // if (Application.isEditor) // { // GameObject _go = new GameObject("Asset:" + assetName); // Transform _parent = transform.Find(assetBundleName); // if (_parent) // { // _go.transform.SetParent(_parent); // } // } } private void CacheAssetBundle(string assetBundleName, AssetBundle assetBundle) { if (assetBundle == null) { Debug.LogErrorFormat("CacheAssetBundle(): {0}出现错误 => 将要缓存的包为 null. ", assetBundleName); return; } if (m_AssetBundleDict.ContainsKey(assetBundleName)) { Debug.LogErrorFormat("CacheAssetBundle(): {0}出现错误 => 将要缓存的包已经在缓存中. ", assetBundleName); return; } m_AssetBundleDict[assetBundleName] = assetBundle; if (Application.isEditor) { string[] _names = assetBundleName.Split('/'); string _selfPath = string.Empty; string _parentPath = string.Empty; for (int i = 0; i < _names.Length; ++i) { _selfPath = _names[0]; for (int j = 1; j <= i; ++j) { _selfPath = _selfPath + "/" + _names[j]; } if (transform.Find(_selfPath)) { continue; } GameObject _go = new GameObject(_names[i]); if (i == 0) { _go.transform.parent = transform; } else { _parentPath = _names[0]; for (int j = 1; j < i; ++j) { _parentPath = _parentPath + "/" + _names[j]; } Transform _parent = transform.Find(_parentPath); if (_parent) { _go.transform.parent = _parent; } } } } Debug.LogFormat("CacheAssetBundle(): 成功缓存assetBundle包资源 => {0}. 目前有 {1} 个资源.", assetBundleName, m_AssetBundleDict.Count); } }