using System; using System.Collections; using System.Collections.Generic; namespace YooAsset { public static class YooAssets { /// /// 运行模式 /// private enum EPlayMode { /// /// 编辑器下模拟运行模式 /// EditorPlayMode, /// /// 离线模式 /// OfflinePlayMode, /// /// 网络模式 /// HostPlayMode, } public abstract class CreateParameters { /// /// 资源定位的根路径 /// 例如:Assets/MyResource /// public string LocationRoot; /// /// 文件解密接口 /// public IDecryptServices DecryptServices = null; /// /// 资源系统自动释放零引用资源的间隔秒数 /// 注意:如果小于等于零代表不自动释放,可以使用YooAssets.UnloadUnusedAssets接口主动释放 /// public float AutoReleaseInterval = -1; /// /// 资源加载的最大数量 /// public int AssetLoadingMaxNumber = int.MaxValue; } /// /// 编辑器下模拟运行(只支持在编辑器下运行) /// public class EditorPlayModeParameters : CreateParameters { } /// /// 离线模式(本地打包运行模式) /// public class OfflinePlayModeParameters : CreateParameters { } /// /// 网络模式(网络打包运行模式) /// public class HostPlayModeParameters : CreateParameters { /// /// 当缓存池被污染的时候清理缓存池 /// public bool ClearCacheWhenDirty; /// /// 忽略资源版本号 /// public bool IgnoreResourceVersion; /// /// 默认的资源服务器下载地址 /// public string DefaultHostServer; /// /// 备用的资源服务器下载地址 /// public string FallbackHostServer; } private static bool _isInitialize = false; private static string _locationRoot; private static EPlayMode _playMode; private static IBundleServices _bundleServices; private static EditorPlayModeImpl _editorPlayModeImpl; private static OfflinePlayModeImpl _offlinePlayModeImpl; private static HostPlayModeImpl _hostPlayModeImpl; private static float _releaseTimer; private static float _releaseCD = -1f; /// /// 异步初始化 /// public static InitializationOperation InitializeAsync(CreateParameters parameters) { if (parameters == null) throw new Exception($"YooAsset create parameters is invalid."); #if !UNITY_EDITOR if (parameters is EditorPlayModeParameters) throw new Exception($"Editor play mode only support unity editor."); #endif // 创建驱动器 if (_isInitialize == false) { _isInitialize = true; UnityEngine.GameObject driverGo = new UnityEngine.GameObject("[YooAsset]"); driverGo.AddComponent(); UnityEngine.Object.DontDestroyOnLoad(driverGo); } else { throw new Exception("YooAsset is initialized yet."); } // 检测创建参数 if (parameters.AssetLoadingMaxNumber < 3) { parameters.AssetLoadingMaxNumber = 3; Logger.Warning($"{nameof(parameters.AssetLoadingMaxNumber)} minimum is 3"); } // 创建间隔计时器 if (parameters.AutoReleaseInterval > 0) { _releaseCD = parameters.AutoReleaseInterval; } if (string.IsNullOrEmpty(parameters.LocationRoot) == false) _locationRoot = AssetPathHelper.GetRegularPath(parameters.LocationRoot); // 运行模式 if (parameters is EditorPlayModeParameters) _playMode = EPlayMode.EditorPlayMode; else if (parameters is OfflinePlayModeParameters) _playMode = EPlayMode.OfflinePlayMode; else if (parameters is HostPlayModeParameters) _playMode = EPlayMode.HostPlayMode; else throw new NotImplementedException(); // 初始化 if (_playMode == EPlayMode.EditorPlayMode) { _editorPlayModeImpl = new EditorPlayModeImpl(); _bundleServices = _editorPlayModeImpl; AssetSystem.Initialize(true, parameters.AssetLoadingMaxNumber, parameters.DecryptServices, _bundleServices); return _editorPlayModeImpl.InitializeAsync(); } else if (_playMode == EPlayMode.OfflinePlayMode) { _offlinePlayModeImpl = new OfflinePlayModeImpl(); _bundleServices = _offlinePlayModeImpl; AssetSystem.Initialize(false, parameters.AssetLoadingMaxNumber, parameters.DecryptServices, _bundleServices); return _offlinePlayModeImpl.InitializeAsync(); } else if (_playMode == EPlayMode.HostPlayMode) { _hostPlayModeImpl = new HostPlayModeImpl(); _bundleServices = _hostPlayModeImpl; AssetSystem.Initialize(false, parameters.AssetLoadingMaxNumber, parameters.DecryptServices, _bundleServices); var hostPlayModeParameters = parameters as HostPlayModeParameters; return _hostPlayModeImpl.InitializeAsync( hostPlayModeParameters.ClearCacheWhenDirty, hostPlayModeParameters.IgnoreResourceVersion, hostPlayModeParameters.DefaultHostServer, hostPlayModeParameters.FallbackHostServer); } else { throw new NotImplementedException(); } } /// /// 向网络端请求并更新补丁清单 /// /// 更新的资源版本号 /// 超时时间 public static UpdateManifestOperation UpdateManifestAsync(int updateResourceVersion, int timeout) { if (_playMode == EPlayMode.EditorPlayMode) { var operation = new EditorModeUpdateManifestOperation(); OperationUpdater.ProcessOperaiton(operation); return operation; } else if (_playMode == EPlayMode.OfflinePlayMode) { var operation = new OfflinePlayModeUpdateManifestOperation(); OperationUpdater.ProcessOperaiton(operation); return operation; } else if (_playMode == EPlayMode.HostPlayMode) { if (_hostPlayModeImpl == null) throw new Exception("YooAsset is not initialized."); return _hostPlayModeImpl.UpdatePatchManifestAsync(updateResourceVersion, timeout); } else { throw new NotImplementedException(); } } /// /// 获取资源版本号 /// public static int GetResourceVersion() { if (_playMode == EPlayMode.EditorPlayMode) { if (_editorPlayModeImpl == null) throw new Exception("YooAsset is not initialized."); return _editorPlayModeImpl.GetResourceVersion(); } else if (_playMode == EPlayMode.OfflinePlayMode) { if (_offlinePlayModeImpl == null) throw new Exception("YooAsset is not initialized."); return _offlinePlayModeImpl.GetResourceVersion(); } else if (_playMode == EPlayMode.HostPlayMode) { if (_hostPlayModeImpl == null) throw new Exception("YooAsset is not initialized."); return _hostPlayModeImpl.GetResourceVersion(); } else { throw new NotImplementedException(); } } /// /// 获取资源包信息 /// public static AssetBundleInfo GetAssetBundleInfo(string location) { string assetPath = ConvertLocationToAssetPath(location); string bundleName = _bundleServices.GetAssetBundleName(assetPath); return _bundleServices.GetAssetBundleInfo(bundleName); } /// /// 资源回收(卸载引用计数为零的资源) /// public static void UnloadUnusedAssets() { AssetSystem.Update(); AssetSystem.UnloadUnusedAssets(); } /// /// 强制回收所有资源 /// public static void ForceUnloadAllAssets() { AssetSystem.ForceUnloadAllAssets(); } /// /// 获取调试汇总信息 /// public static void GetDebugSummy(DebugSummy summy) { if (summy == null) Logger.Error($"{nameof(DebugSummy)} is null"); AssetSystem.GetDebugSummy(summy); } #region 资源加载接口 /// /// 同步加载资源对象 /// /// 资源对象相对路径 public static AssetOperationHandle LoadAssetSync(string location) where TObject : class { return LoadAssetInternal(location, typeof(TObject), true); } public static AssetOperationHandle LoadAssetSync(System.Type type, string location) { return LoadAssetInternal(location, type, true); } /// /// 同步加载子资源对象集合 /// /// 资源对象相对路径 public static AssetOperationHandle LoadSubAssetsSync(string location) { return LoadSubAssetsInternal(location, typeof(TObject), true); } public static AssetOperationHandle LoadSubAssetsSync(System.Type type, string location) { return LoadSubAssetsInternal(location, type, true); } /// /// 异步加载场景 /// public static AssetOperationHandle LoadSceneAsync(string location, SceneInstanceParam instanceParam) { string scenePath = ConvertLocationToAssetPath(location); var handle = AssetSystem.LoadSceneAsync(scenePath, instanceParam); return handle; } /// /// 异步加载资源对象 /// /// 资源对象相对路径 public static AssetOperationHandle LoadAssetAsync(string location) { return LoadAssetInternal(location, typeof(TObject), false); } public static AssetOperationHandle LoadAssetAsync(System.Type type, string location) { return LoadAssetInternal(location, type, false); } /// /// 异步加载子资源对象集合 /// /// 资源对象相对路径 public static AssetOperationHandle LoadSubAssetsAsync(string location) { return LoadSubAssetsInternal(location, typeof(TObject), false); } public static AssetOperationHandle LoadSubAssetsAsync(System.Type type, string location) { return LoadSubAssetsInternal(location, type, false); } private static AssetOperationHandle LoadAssetInternal(string location, System.Type assetType, bool waitForAsyncComplete) { string assetPath = ConvertLocationToAssetPath(location); var handle = AssetSystem.LoadAssetAsync(assetPath, assetType); if (waitForAsyncComplete) handle.WaitForAsyncComplete(); return handle; } private static AssetOperationHandle LoadSubAssetsInternal(string location, System.Type assetType, bool waitForAsyncComplete) { string assetPath = ConvertLocationToAssetPath(location); var handle = AssetSystem.LoadSubAssetsAsync(assetPath, assetType); if (waitForAsyncComplete) handle.WaitForAsyncComplete(); return handle; } #endregion #region 资源下载接口 /// /// 创建补丁下载器 /// /// 资源标签 /// 同时下载的最大文件数 /// 下载失败的重试次数 public static DownloaderOperation CreatePatchDownloader(string tag, int downloadingMaxNumber, int failedTryAgain) { return CreatePatchDownloader(new string[] { tag }, downloadingMaxNumber, failedTryAgain); } /// /// 创建补丁下载器 /// /// 资源标签列表 /// 同时下载的最大文件数 /// 下载失败的重试次数 public static DownloaderOperation CreatePatchDownloader(string[] tags, int downloadingMaxNumber, int failedTryAgain) { if (_playMode == EPlayMode.EditorPlayMode) { List downloadList = new List(); var operation = new DownloaderOperation(downloadList, downloadingMaxNumber, failedTryAgain); return operation; } else if (_playMode == EPlayMode.OfflinePlayMode) { List downloadList = new List(); var operation = new DownloaderOperation(downloadList, downloadingMaxNumber, failedTryAgain); return operation; } else if (_playMode == EPlayMode.HostPlayMode) { if (_hostPlayModeImpl == null) throw new Exception("YooAsset is not initialized."); return _hostPlayModeImpl.CreateDownloaderByTags(tags, downloadingMaxNumber, failedTryAgain); } else { throw new NotImplementedException(); } } /// /// 创建资源包下载器 /// /// 资源列表 /// 同时下载的最大文件数 /// 下载失败的重试次数 public static DownloaderOperation CreateBundleDownloader(string[] locations, int downloadingMaxNumber, int failedTryAgain) { if (_playMode == EPlayMode.EditorPlayMode) { List downloadList = new List(); var operation = new DownloaderOperation(downloadList, downloadingMaxNumber, failedTryAgain); return operation; } else if (_playMode == EPlayMode.OfflinePlayMode) { List downloadList = new List(); var operation = new DownloaderOperation(downloadList, downloadingMaxNumber, failedTryAgain); return operation; } else if (_playMode == EPlayMode.HostPlayMode) { if (_hostPlayModeImpl == null) throw new Exception("YooAsset is not initialized."); List assetPaths = new List(locations.Length); foreach (var location in locations) { string assetPath = ConvertLocationToAssetPath(location); assetPaths.Add(assetPath); } return _hostPlayModeImpl.CreateDownloaderByPaths(assetPaths, downloadingMaxNumber, failedTryAgain); } else { throw new NotImplementedException(); } } #endregion #region 资源解压接口 /// /// 创建补丁解压器 /// /// 资源标签 /// 同时解压的最大文件数 /// 解压失败的重试次数 public static DownloaderOperation CreatePatchUnpacker(string tag, int unpackingMaxNumber, int failedTryAgain) { return CreatePatchUnpacker(new string[] { tag }, unpackingMaxNumber, failedTryAgain); } /// /// 创建补丁解压器 /// /// 资源标签列表 /// 同时解压的最大文件数 /// 解压失败的重试次数 public static DownloaderOperation CreatePatchUnpacker(string[] tags, int unpackingMaxNumber, int failedTryAgain) { if (_playMode == EPlayMode.EditorPlayMode) { List downloadList = new List(); var operation = new DownloaderOperation(downloadList, unpackingMaxNumber, failedTryAgain); return operation; } else if (_playMode == EPlayMode.OfflinePlayMode) { List downloadList = new List(); var operation = new DownloaderOperation(downloadList, unpackingMaxNumber, failedTryAgain); return operation; } else if (_playMode == EPlayMode.HostPlayMode) { if (_hostPlayModeImpl == null) throw new Exception("YooAsset is not initialized."); return _hostPlayModeImpl.CreateUnpackerByTags(tags, unpackingMaxNumber, failedTryAgain); } else { throw new NotImplementedException(); } } #endregion #region 沙盒相关 /// /// 清空沙盒目录 /// 注意:可以使用该方法修复我们本地的客户端 /// public static void ClearSandbox() { Logger.Warning("Clear sandbox."); PatchHelper.ClearSandbox(); } /// /// 获取沙盒文件夹的路径 /// public static string GetSandboxRoot() { return AssetPathHelper.MakePersistentRootPath(); } #endregion #region 内部方法 /// /// 更新资源系统 /// internal static void InternalUpdate() { // 更新异步请求操作 OperationUpdater.Update(); // 更新下载管理系统 DownloadSystem.Update(); // 轮询更新资源系统 AssetSystem.Update(); // 自动释放零引用资源 if (_releaseCD > 0) { _releaseTimer += UnityEngine.Time.unscaledDeltaTime; if (_releaseTimer >= _releaseCD) { _releaseTimer = 0f; AssetSystem.UnloadUnusedAssets(); } } } /// /// 定位地址转换为资源路径 /// private static string ConvertLocationToAssetPath(string location) { if (_playMode == EPlayMode.EditorPlayMode) { string filePath = AssetPathHelper.CombineAssetPath(_locationRoot, location); return AssetPathHelper.FindDatabaseAssetPath(filePath); } else { return AssetPathHelper.CombineAssetPath(_locationRoot, location); } } #endregion } }