using System; using System.Collections.Generic; using System.IO; using System.Linq; using Fantasy.Async; using UnityEngine; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; namespace NBC.Asset { public static class Assets { private static GameObject _monoGameObject; private static bool _isInitialize; private static NTaskStatus _initializeTaskStatus = NTaskStatus.None; private static string _initializeError = string.Empty; public static InitializationTask Initialize() { if (_isInitialize) throw new Exception($"Repeated initialization!"); return InitConfirm(); } #region 资源清理 /// /// 清理所有缓存 /// public static void ClearAllCache() { if (Directory.Exists(Const.SavePath)) { Directory.Delete(Const.SavePath, true); } } #endregion #region 资源加载 public static T Load(string path) where T : Object { var assetProvider = LoadAsset(path, typeof(T)); if (assetProvider != null) { return assetProvider.Asset as T; } return default(T); } public static async FTask LoadAsync(string path) where T : Object { var assetProvider = LoadAssetAsync(path, typeof(T)); await assetProvider.Task; if (assetProvider.Asset != null) { return assetProvider.Asset as T; } return null; } public static AssetProvider LoadAsset(string path) { return LoadAsset(path, typeof(T)); } public static AssetProvider LoadAsset(string path, Type type) { var req = LoadAssetAsync(path, type); req?.WaitForAsyncComplete(); return req; } public static AssetProvider LoadAssetAsync(string path) { return LoadAssetAsync(path, typeof(T)); } public static AssetProvider LoadAssetAsync(string path, Type type) { var assetInfo = Addressable.GetAssetInfo(path, type); return AssetProvider.GetAssetProvider(assetInfo); } public static AssetProvider LoadAssetAll(string path) { return LoadAssetAll(path, typeof(T)); } public static AssetProvider LoadAssetAll(string path, Type type) { var req = LoadAssetAllAsync(path, type); req?.WaitForAsyncComplete(); return req; } public static AssetProvider LoadAssetAllAsync(string path) { return LoadAssetAllAsync(path, typeof(T)); } public static AssetProvider LoadAssetAllAsync(string path, Type type) { var assetInfo = Addressable.GetAssetInfo(path, type); return AssetProvider.GetAssetProvider(assetInfo, true); } #endregion #region 场景加载 public static SceneProvider LoadScene(string path, bool additive = false) { var assetInfo = Addressable.GetAssetInfo(path, typeof(Scene)); if (assetInfo == null) { throw new Exception($"Scene is null,path={path}"); } return SceneProvider.GetSceneProvider(assetInfo, additive); } #endregion #region 资源卸载 /// /// 释放所有资源 /// /// 强制释放 public static void ReleaseAllAssets(bool force = true) { AssetProvider.ReleaseAllAssets(force); SceneProvider.ReleaseAllAssets(force); } /// /// 根据标签,释放所有资源 /// /// 标签 /// 强制释放 public static void ReleaseAllAssetsByTag(string[] tags, bool force = true) { AssetProvider.ReleaseAllAssetsByTag(tags, force); SceneProvider.ReleaseAllAssetsByTag(tags, force); } #endregion #region 检查解压 /// /// 可以解压的bundle包数量 /// /// public static int CanUnpackBundleCount() { var arr = Addressable.GetCanUnpackBundles(); return arr != null ? arr.Length : 0; } /// /// 解压资源包任务(解压本地存在的所有资源) /// /// 自动运行 /// public static UnpackPackagesTask CreateUnpackPackagesTask(bool run = true) { var task = new UnpackPackagesTask(); if (run) task.Run(TaskRunner.Def); return task; } #endregion #region 检查更新 /// /// 获取当前版本可以下载到本地的bundle包 /// /// public static List GetCanDownloadBundles() { List ret = new List(); var bundles = Addressable.GetCanDownloadBundles(); foreach (var bundleInfo in bundles) { var bundleData = bundleInfo.Bundle; //可优化。缓存所有packageName,但该逻辑理论全局只会调用一次,是否需要缓存值得考虑 if (bundleData != null && IsNeedfulPackage(bundleData.PackageName)) { ret.Add(bundleInfo); } } return ret; } /// /// 主动下载需要的bundles包任务 /// /// 需要下载的bundle /// 自动运行 /// public static DownloadBundlesTask CreateDownloadBundlesTask(List downloadBundles, bool run = true) { var task = new DownloadBundlesTask(downloadBundles); if (run) task.Run(); return task; } /// /// 创建检查更新任务 /// /// public static CheckUpdateTask CreateCheckUpdateTask(bool run = true) { var task = new CheckUpdateTask(); if (run) task.Run(TaskRunner.Def); return task; } /// /// 创建版本更新任务 /// public static UpdateVersionTask CreateUpdateVersionTask(UpdateContext context, bool run = true) { var task = new UpdateVersionTask(context); if (run) task.Run(); return task; } #endregion #region 默认资源包 private static readonly HashSet _defaultPackage = new HashSet(); /// /// 添加一个包进入需要列表 /// /// public static void AddNeedfulPackage(string packageName) { _defaultPackage.Add(packageName); } /// /// 移除一个需要的资源包 /// /// public static void RemoveNeedfulPackage(string packageName) { if (_defaultPackage.Contains(packageName)) _defaultPackage.Remove(packageName); } /// /// 移除全部额外需要包 /// public static void RemoveAllNeedful() { _defaultPackage.Clear(); } /// /// 是否需要这个资源包 /// /// /// public static bool IsNeedfulPackage(string packageName) { var ret = _defaultPackage.Contains(packageName); if (!ret) { var package = Addressable.GetPackageData(packageName); if (package != null) { return package.Def == 1; } } return ret; } #endregion #region 调试 #if DEBUG private static DebugRemoteServer _debugRemoteServer; public static void StartDebugRemoteServer() { _debugRemoteServer = _monoGameObject.AddComponent(); } public static void StopDebugRemoteServer() { if (_debugRemoteServer != null) { Object.DestroyImmediate(_debugRemoteServer); } } public static DebugInfo GetDebugInfos() { DebugInfo info = new DebugInfo(); info.Frame = Time.frameCount; var assetProviders = AssetProvider.GetAssetProviders(); foreach (var asset in assetProviders) { var i = CreateDebugAssetInfo(asset.AssetInfo, asset.IsAll); SetDebugBaseInfo(asset, i); info.AssetInfos.Add(i); } var sceneProviders = SceneProvider.GetSceneProviders(); foreach (var scene in sceneProviders) { var i = CreateDebugAssetInfo(scene.AssetInfo, false); SetDebugBaseInfo(scene, i); info.AssetInfos.Add(i); } var bundleProviders = BundledProvider.GetBundleProviders(); foreach (var bundle in bundleProviders) { var bundleInfo = new DebugBundleInfo { BundleName = bundle.BundleInfo.Bundle.Name }; SetDebugBaseInfo(bundle, bundleInfo); info.BundleInfos.Add(bundleInfo); } return info; } private static DebugAssetInfo CreateDebugAssetInfo(AssetInfo asset, bool isAll) { var assetInfo = new DebugAssetInfo { Path = asset.Path, Type = asset.AssetType.Name, IsAll = isAll, }; var bundleInfos = Addressable.GetAllDependBundleInfos(asset); foreach (var bundle in bundleInfos) { assetInfo.Dependency.Add(bundle.Bundle.Name); } return assetInfo; } private static void SetDebugBaseInfo(ProviderBase provider, DebugBaseInfo info) { info.LoadScene = provider.LoadScene; info.Ref = provider.RefCount; info.Status = provider.Status.ToString(); info.LoadTime = provider.LoadTime; info.LoadTotalTime = provider.LoadTotalTime; } #endif #endregion #region Private private static void Update() { TaskRunner.Update(); Recycler.Update(); } private static InitializationTask InitConfirm() { _monoGameObject = new GameObject("Assets", typeof(Mono)); Mono.AddUpdate(Update); InitializationTask task; #if UNITY_STANDALONE_WIN Const.NotCache = true; #endif if (Const.Simulate) { task = new EditorInitializationTask(); AssetProvider.CreateLoader = AssetLoadFromDatabase.CreateInstance; SceneProvider.CreateLoader = SceneLoadFromDatabase.CreateInstance; } else if (Const.Offline) { task = new OfflineInitializationTask(); } else { task = new OnlineInitializationTask(); } if (Const.IsWebGLPlatform) { Const.RemoteUrl = $"{Application.streamingAssetsPath}/"; } task.OnCompleted(InitDone); task.Run(TaskRunner.Def); _isInitialize = true; return task; } /// /// 初始化完成回调 /// /// private static void InitDone(ITask taskBase) { Debug.Log("初始化完成==="); _initializeTaskStatus = taskBase.Status; _initializeError = taskBase.ErrorMsg; } #endregion } }