using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using UnityEngine; using UnityEngine.SceneManagement; namespace YooAsset { internal class AssetSystemImpl { private readonly Dictionary _loaderDic = new Dictionary(5000); private readonly List _loaderList = new List(5000); private readonly Dictionary _providerDic = new Dictionary(5000); private readonly List _providerList = new List(5000); private readonly static Dictionary _sceneHandles = new Dictionary(100); private static long _sceneCreateCount = 0; private bool _isUnloadSafe = true; private string _packageName; private bool _simulationOnEditor; private long _loadingMaxTimeSlice; public int DownloadFailedTryAgain { private set; get; } public IDecryptionServices DecryptionServices { private set; get; } public IBundleServices BundleServices { private set; get; } // 计时器相关 private Stopwatch _watch; private long _frameTime; private bool IsBusy { get { return _watch.ElapsedMilliseconds - _frameTime >= _loadingMaxTimeSlice; } } /// /// 初始化 /// 注意:在使用AssetSystem之前需要初始化 /// public void Initialize(string packageName, bool simulationOnEditor, long loadingMaxTimeSlice, int downloadFailedTryAgain, IDecryptionServices decryptionServices, IBundleServices bundleServices) { _packageName = packageName; _simulationOnEditor = simulationOnEditor; _loadingMaxTimeSlice = loadingMaxTimeSlice; DownloadFailedTryAgain = downloadFailedTryAgain; DecryptionServices = decryptionServices; BundleServices = bundleServices; _watch = Stopwatch.StartNew(); } /// /// 更新 /// public void Update() { _frameTime = _watch.ElapsedMilliseconds; // 更新加载器 foreach (var loader in _loaderList) { loader.Update(); } // 更新资源提供者 // 注意:循环更新的时候,可能会扩展列表 _isUnloadSafe = false; for (int i = 0; i < _providerList.Count; i++) { if (IsBusy) break; _providerList[i].Update(); } _isUnloadSafe = true; } /// /// 资源回收(卸载引用计数为零的资源) /// public void UnloadUnusedAssets() { if (_isUnloadSafe == false) { YooLogger.Warning("Can not unload unused assets when processing resource loading !"); return; } // 注意:资源包之间可能存在多层深层嵌套,需要多次循环释放。 int loopCount = 10; for (int i = 0; i < loopCount; i++) { UnloadUnusedAssetsInternal(); } } private void UnloadUnusedAssetsInternal() { for (int i = _loaderList.Count - 1; i >= 0; i--) { BundleLoaderBase loader = _loaderList[i]; loader.TryDestroyAllProviders(); } for (int i = _loaderList.Count - 1; i >= 0; i--) { BundleLoaderBase loader = _loaderList[i]; if (loader.CanDestroy()) { string bundleName = loader.MainBundleInfo.Bundle.BundleName; loader.Destroy(); _loaderList.RemoveAt(i); _loaderDic.Remove(bundleName); } } } /// /// 强制回收所有资源 /// public void ForceUnloadAllAssets() { #if UNITY_WEBGL throw new Exception($"WebGL not support invoke {nameof(ForceUnloadAllAssets)}"); #else foreach (var provider in _providerList) { provider.WaitForAsyncComplete(); provider.Destroy(); } foreach (var loader in _loaderList) { loader.WaitForAsyncComplete(); loader.Destroy(); } _providerList.Clear(); _providerDic.Clear(); _loaderList.Clear(); _loaderDic.Clear(); ClearSceneHandle(); // 注意:调用底层接口释放所有资源 Resources.UnloadUnusedAssets(); #endif } /// /// 加载场景 /// public SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode, bool suspendLoad, int priority) { if (assetInfo.IsInvalid) { YooLogger.Error($"Failed to load scene ! {assetInfo.Error}"); CompletedProvider completedProvider = new CompletedProvider(assetInfo); completedProvider.SetCompleted(assetInfo.Error); return completedProvider.CreateHandle(); } // 如果加载的是主场景,则卸载所有缓存的场景 if (sceneMode == LoadSceneMode.Single) { UnloadAllScene(); } // 注意:同一个场景的ProviderGUID每次加载都会变化 string providerGUID = $"{assetInfo.GUID}-{++_sceneCreateCount}"; ProviderBase provider; { if (_simulationOnEditor) provider = new DatabaseSceneProvider(this, providerGUID, assetInfo, sceneMode, suspendLoad, priority); else provider = new BundledSceneProvider(this, providerGUID, assetInfo, sceneMode, suspendLoad, priority); provider.InitSpawnDebugInfo(); _providerList.Add(provider); _providerDic.Add(providerGUID, provider); } var handle = provider.CreateHandle(); handle.PackageName = _packageName; _sceneHandles.Add(providerGUID, handle); return handle; } /// /// 加载资源对象 /// public AssetOperationHandle LoadAssetAsync(AssetInfo assetInfo) { if (assetInfo.IsInvalid) { YooLogger.Error($"Failed to load asset ! {assetInfo.Error}"); CompletedProvider completedProvider = new CompletedProvider(assetInfo); completedProvider.SetCompleted(assetInfo.Error); return completedProvider.CreateHandle(); } string providerGUID = assetInfo.GUID; ProviderBase provider = TryGetProvider(providerGUID); if (provider == null) { if (_simulationOnEditor) provider = new DatabaseAssetProvider(this, providerGUID, assetInfo); else provider = new BundledAssetProvider(this, providerGUID, assetInfo); provider.InitSpawnDebugInfo(); _providerList.Add(provider); _providerDic.Add(providerGUID, provider); } return provider.CreateHandle(); } /// /// 加载子资源对象 /// public SubAssetsOperationHandle LoadSubAssetsAsync(AssetInfo assetInfo) { if (assetInfo.IsInvalid) { YooLogger.Error($"Failed to load sub assets ! {assetInfo.Error}"); CompletedProvider completedProvider = new CompletedProvider(assetInfo); completedProvider.SetCompleted(assetInfo.Error); return completedProvider.CreateHandle(); } string providerGUID = assetInfo.GUID; ProviderBase provider = TryGetProvider(providerGUID); if (provider == null) { if (_simulationOnEditor) provider = new DatabaseSubAssetsProvider(this, providerGUID, assetInfo); else provider = new BundledSubAssetsProvider(this, providerGUID, assetInfo); provider.InitSpawnDebugInfo(); _providerList.Add(provider); _providerDic.Add(providerGUID, provider); } return provider.CreateHandle(); } /// /// 加载所有资源对象 /// public AllAssetsOperationHandle LoadAllAssetsAsync(AssetInfo assetInfo) { if (assetInfo.IsInvalid) { YooLogger.Error($"Failed to load all assets ! {assetInfo.Error}"); CompletedProvider completedProvider = new CompletedProvider(assetInfo); completedProvider.SetCompleted(assetInfo.Error); return completedProvider.CreateHandle(); } string providerGUID = assetInfo.GUID; ProviderBase provider = TryGetProvider(providerGUID); if (provider == null) { if (_simulationOnEditor) provider = new DatabaseAllAssetsProvider(this, providerGUID, assetInfo); else provider = new BundledAllAssetsProvider(this, providerGUID, assetInfo); provider.InitSpawnDebugInfo(); _providerList.Add(provider); _providerDic.Add(providerGUID, provider); } return provider.CreateHandle(); } /// /// 加载原生文件 /// public RawFileOperationHandle LoadRawFileAsync(AssetInfo assetInfo) { if (assetInfo.IsInvalid) { YooLogger.Error($"Failed to load raw file ! {assetInfo.Error}"); CompletedProvider completedProvider = new CompletedProvider(assetInfo); completedProvider.SetCompleted(assetInfo.Error); return completedProvider.CreateHandle(); } string providerGUID = assetInfo.GUID; ProviderBase provider = TryGetProvider(providerGUID); if (provider == null) { if (_simulationOnEditor) provider = new DatabaseRawFileProvider(this, providerGUID, assetInfo); else provider = new BundledRawFileProvider(this, providerGUID, assetInfo); provider.InitSpawnDebugInfo(); _providerList.Add(provider); _providerDic.Add(providerGUID, provider); } return provider.CreateHandle(); } internal void UnloadSubScene(ProviderBase provider) { string providerGUID = provider.ProviderGUID; if (_sceneHandles.ContainsKey(providerGUID) == false) throw new Exception("Should never get here !"); // 释放子场景句柄 _sceneHandles[providerGUID].ReleaseInternal(); _sceneHandles.Remove(providerGUID); } internal void UnloadAllScene() { // 释放所有场景句柄 foreach (var valuePair in _sceneHandles) { valuePair.Value.ReleaseInternal(); } _sceneHandles.Clear(); } internal void ClearSceneHandle() { // 释放资源包下的所有场景 if (BundleServices.IsServicesValid()) { string packageName = _packageName; List removeList = new List(); foreach (var valuePair in _sceneHandles) { if (valuePair.Value.PackageName == packageName) { removeList.Add(valuePair.Key); } } foreach (var key in removeList) { _sceneHandles.Remove(key); } } } internal BundleLoaderBase CreateOwnerAssetBundleLoader(AssetInfo assetInfo) { BundleInfo bundleInfo = BundleServices.GetBundleInfo(assetInfo); return CreateAssetBundleLoaderInternal(bundleInfo); } internal List CreateDependAssetBundleLoaders(AssetInfo assetInfo) { BundleInfo[] depends = BundleServices.GetAllDependBundleInfos(assetInfo); List result = new List(depends.Length); foreach (var bundleInfo in depends) { BundleLoaderBase dependLoader = CreateAssetBundleLoaderInternal(bundleInfo); result.Add(dependLoader); } return result; } internal void RemoveBundleProviders(List providers) { foreach (var provider in providers) { _providerList.Remove(provider); _providerDic.Remove(provider.ProviderGUID); } } internal bool CheckBundleDestroyed(int bundleID) { string bundleName = BundleServices.GetBundleName(bundleID); BundleLoaderBase loader = TryGetAssetBundleLoader(bundleName); if (loader == null) return true; return loader.IsDestroyed; } private BundleLoaderBase CreateAssetBundleLoaderInternal(BundleInfo bundleInfo) { // 如果加载器已经存在 string bundleName = bundleInfo.Bundle.BundleName; BundleLoaderBase loader = TryGetAssetBundleLoader(bundleName); if (loader != null) return loader; // 新增下载需求 if (_simulationOnEditor) { loader = new VirtualBundleFileLoader(this, bundleInfo); } else { #if UNITY_WEBGL if (bundleInfo.Bundle.IsRawFile) loader = new RawBundleWebLoader(this, bundleInfo); else loader = new AssetBundleWebLoader(this, bundleInfo); #else if (bundleInfo.Bundle.IsRawFile) loader = new RawBundleFileLoader(this, bundleInfo); else loader = new AssetBundleFileLoader(this, bundleInfo); #endif } _loaderList.Add(loader); _loaderDic.Add(bundleName, loader); return loader; } private BundleLoaderBase TryGetAssetBundleLoader(string bundleName) { if (_loaderDic.TryGetValue(bundleName, out BundleLoaderBase value)) return value; else return null; } private ProviderBase TryGetProvider(string providerGUID) { if (_providerDic.TryGetValue(providerGUID, out ProviderBase value)) return value; else return null; } #region 调试信息 internal List GetDebugReportInfos() { List result = new List(_providerList.Count); foreach (var provider in _providerList) { DebugProviderInfo providerInfo = new DebugProviderInfo(); providerInfo.AssetPath = provider.MainAssetInfo.AssetPath; providerInfo.SpawnScene = provider.SpawnScene; providerInfo.SpawnTime = provider.SpawnTime; providerInfo.LoadingTime = provider.LoadingTime; providerInfo.RefCount = provider.RefCount; providerInfo.Status = provider.Status.ToString(); providerInfo.DependBundleInfos = new List(); provider.GetBundleDebugInfos(providerInfo.DependBundleInfos); result.Add(providerInfo); } return result; } internal List GetLoadedBundleInfos() { List result = new List(100); foreach (var loader in _loaderList) { result.Add(loader.MainBundleInfo); } return result; } #endregion } }