diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadBackend.meta similarity index 77% rename from Assets/YooAsset/Runtime/DownloadSystem/Operation.meta rename to Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadBackend.meta index 0587d2ca..1f9c4e73 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation.meta +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadBackend.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a8f060786f8775b4a82cc3f55d9135e2 +guid: bb70e2274ce5a5d419cfbd7212efdf4a folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadBackend/UnityWebRequestBackend.cs b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadBackend/UnityWebRequestBackend.cs new file mode 100644 index 00000000..6e874240 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadBackend/UnityWebRequestBackend.cs @@ -0,0 +1,110 @@ +using System; +using UnityEngine.Networking; + +namespace YooAsset +{ + /// + /// UnityWebRequest 下载后台 + /// + /// + /// 基于 Unity 内置 UnityWebRequest 实现的下载后台。 + /// 支持自定义 UnityWebRequest 创建方式,例如添加证书验证、代理设置等。 + /// + internal sealed class UnityWebRequestBackend : IDownloadBackend + { + private readonly UnityWebRequestDelegate _webRequestCreator; + + /// + /// 后端名称 + /// + public string Name + { + get { return nameof(UnityWebRequestBackend); } + } + + /// + /// 创建 UnityWebRequest 下载后端(使用默认创建方式) + /// + public UnityWebRequestBackend() : this(null) + { + } + + /// + /// 创建 UnityWebRequest 下载后端 + /// + /// + /// 自定义 UnityWebRequest 创建委托(可选)。 + /// 如果为 null,则使用默认的 UnityWebRequest 构造方式。 + /// + public UnityWebRequestBackend(UnityWebRequestDelegate webRequestCreator) + { + _webRequestCreator = webRequestCreator; + } + + /// + /// 驱动更新 + /// + /// + /// UnityWebRequest 由 Unity 引擎自动驱动,无需额外更新。 + /// + public void Update() + { + } + + /// + /// 释放资源 + /// + public void Dispose() + { + // 无需释放资源 + } + + /// + /// 创建 HEAD 请求 + /// + public IDownloadHeadRequest CreateHeadRequest(DownloadDataRequestArgs args) + { + return new UnityWebRequestHeadDownloader(args, _webRequestCreator); + } + + /// + /// 创建文件下载请求 + /// + public IDownloadFileRequest CreateFileRequest(DownloadFileRequestArgs args) + { + return new UnityWebRequestFileDownloader(args, _webRequestCreator); + } + + /// + /// 创建字节下载请求 + /// + public IDownloadBytesRequest CreateBytesRequest(DownloadDataRequestArgs args) + { + return new UnityWebRequestBytesDownloader(args, _webRequestCreator); + } + + /// + /// 创建文本下载请求 + /// + public IDownloadTextRequest CreateTextRequest(DownloadDataRequestArgs args) + { + return new UnityWebRequestTextDownloader(args, _webRequestCreator); + } + + /// + /// 创建 AssetBundle 下载请求 + /// + public IDownloadAssetBundleRequest CreateAssetBundleRequest(DownloadAssetBundleRequestArgs args) + { + return new UnityWebRequestAssetBundleDownloader(args, _webRequestCreator); + } + + /// + /// 创建模拟下载请求 + /// + public IDownloadFileRequest CreateSimulateRequest(DownloadSimulateRequestArgs args) + { + return new VirtualFileDownloader(args); + } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadBackend/UnityWebRequestBackend.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadBackend/UnityWebRequestBackend.cs.meta new file mode 100644 index 00000000..b7e9ef90 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadBackend/UnityWebRequestBackend.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 932e4c4574244dac8c27d9ddc156f8ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest.meta new file mode 100644 index 00000000..e611c40a --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d30af9086de4fb282c2cdd3d26244c0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestAssetBundleDownloader.cs b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestAssetBundleDownloader.cs new file mode 100644 index 00000000..15935313 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestAssetBundleDownloader.cs @@ -0,0 +1,92 @@ +using System; +using UnityEngine; +using UnityEngine.Networking; + +namespace YooAsset +{ + /// + /// UnityWebRequest AssetBundle 下载器 + /// + /// + /// 下载并加载 Unity AssetBundle 资源包。 + /// 支持 Unity 内置缓存机制和 CRC 校验。 + /// + internal sealed class UnityWebRequestAssetBundleDownloader : UnityWebRequestDownloaderBase, IDownloadAssetBundleRequest + { + private readonly DownloadAssetBundleRequestArgs _args; + private DownloadHandlerAssetBundle _downloadHandler; + + /// + /// 下载结果(AssetBundle 对象) + /// + public AssetBundle Result { get; private set; } + + /// + /// 构造 AssetBundle 下载器 + /// + /// AssetBundle 下载参数 + /// UnityWebRequest 创建器(可选) + public UnityWebRequestAssetBundleDownloader(DownloadAssetBundleRequestArgs args, UnityWebRequestDelegate webRequestCreator) + : base(args.URL, webRequestCreator) + { + _args = args; + } + + /// + /// 创建 UnityWebRequest + /// + protected override void CreateWebRequest() + { + _downloadHandler = CreateAssetBundleDownloadHandler(); + _webRequest = CreateUnityWebRequestGet(URL); + _webRequest.downloadHandler = _downloadHandler; + _webRequest.disposeDownloadHandlerOnDispose = true; + ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers); + } + + /// + /// 请求成功时的回调 + /// + protected override void OnRequestSucceed() + { + AssetBundle assetBundle = _downloadHandler.assetBundle; + if (assetBundle == null) + { + Status = EDownloadRequestStatus.Failed; + Error = $"[{GetType().Name}] URL: {URL} - AssetBundle object is null"; + } + else + { + Result = assetBundle; + } + } + + /// + /// 创建 AssetBundle 下载处理器 + /// + private DownloadHandlerAssetBundle CreateAssetBundleDownloadHandler() + { + DownloadHandlerAssetBundle handler; + + if (_args.DisableUnityWebCache) + { + // 禁用 Unity 缓存 + handler = new DownloadHandlerAssetBundle(URL, _args.UnityCRC); + } + else + { + // 使用 Unity 缓存(需要 FileHash) + // The file hash defining the version of the asset bundle. + Hash128 fileHash = Hash128.Parse(_args.FileHash); + handler = new DownloadHandlerAssetBundle(URL, fileHash, _args.UnityCRC); + } + +#if UNITY_2020_3_OR_NEWER + // 禁用自动加载,允许手动控制加载时机 + handler.autoLoadAssetBundle = false; +#endif + + return handler; + } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityAssetBundleRequestOperation.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestAssetBundleDownloader.cs.meta similarity index 83% rename from Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityAssetBundleRequestOperation.cs.meta rename to Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestAssetBundleDownloader.cs.meta index 2f3a8d5a..993bab95 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityAssetBundleRequestOperation.cs.meta +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestAssetBundleDownloader.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e01cc308d7179a34281087fafe455b42 +guid: 6f635344c08e2b04295a108c2bcc6a40 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestBytesDownloader.cs b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestBytesDownloader.cs new file mode 100644 index 00000000..001932ae --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestBytesDownloader.cs @@ -0,0 +1,61 @@ +using System; +using UnityEngine.Networking; + +namespace YooAsset +{ + /// + /// UnityWebRequest 字节下载器 + /// + /// + /// 将下载内容保存到内存中的字节数组。 + /// + internal sealed class UnityWebRequestBytesDownloader : UnityWebRequestDownloaderBase, IDownloadBytesRequest + { + private readonly DownloadDataRequestArgs _args; + + /// + /// 下载结果(字节数组) + /// + public byte[] Result { get; private set; } + + /// + /// 构造字节数组下载器 + /// + /// 数据下载参数 + /// UnityWebRequest 创建器(可选) + public UnityWebRequestBytesDownloader(DownloadDataRequestArgs args, UnityWebRequestDelegate webRequestCreator) + : base(args.URL, webRequestCreator) + { + _args = args; + } + + /// + /// 创建 UnityWebRequest + /// + protected override void CreateWebRequest() + { + var handler = new DownloadHandlerBuffer(); + _webRequest = CreateUnityWebRequestGet(URL); + _webRequest.downloadHandler = handler; + _webRequest.disposeDownloadHandlerOnDispose = true; + ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers); + } + + /// + /// 请求成功时的回调 + /// + protected override void OnRequestSucceed() + { + var fileData = _webRequest.downloadHandler.data; + if (fileData == null || fileData.Length == 0) + { + Status = EDownloadRequestStatus.Failed; + Error = $"[{GetType().Name}] URL: {URL} - Download bytes data is null or empty !"; + } + else + { + Result = fileData; + } + } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DownloadDefine.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestBytesDownloader.cs.meta similarity index 83% rename from Assets/YooAsset/Runtime/DownloadSystem/DownloadDefine.cs.meta rename to Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestBytesDownloader.cs.meta index 89c05103..a6c75721 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/DownloadDefine.cs.meta +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestBytesDownloader.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6602c4be2ef295546b7bbb328de8fb0c +guid: 38884a96e8c2df74082d4e059e2e73ed MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestDownloaderBase.cs b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestDownloaderBase.cs new file mode 100644 index 00000000..9824a5a6 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestDownloaderBase.cs @@ -0,0 +1,290 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Networking; + +namespace YooAsset +{ + /// + /// UnityWebRequest 下载器基类 + /// + /// + /// 封装 UnityWebRequest 的通用下载逻辑,包括状态管理、进度追踪等。 + /// 子类只需实现 CreateWebRequest 方法来创建特定类型的下载请求。 + /// + internal abstract class UnityWebRequestDownloaderBase : IDownloadRequest + { + private readonly UnityWebRequestDelegate _webRequestCreator; + protected UnityWebRequest _webRequest; + + // 看门狗相关 + private int _watchdogTime = 0; + private bool _watchdogAborted = false; + private long _lastDownloadBytes = -1; + private double _lastGetDataTime; + + #region 接口实现 + /// + /// 请求地址 + /// + public string URL { get; } + + /// + /// 是否完成 + /// + /// + /// 每次调用都会主动轮询请求 PollingRequest + /// + public bool IsDone + { + get + { + PollingRequest(); + return Status == EDownloadRequestStatus.Succeed + || Status == EDownloadRequestStatus.Failed + || Status == EDownloadRequestStatus.Aborted; + } + } + + /// + /// 请求状态 + /// + public EDownloadRequestStatus Status { get; protected set; } + + /// + /// 当前下载进度(0f - 1f) + /// + public float DownloadProgress { get; private set; } + + /// + /// 当前请求已接收的字节数 + /// + public long DownloadedBytes { get; private set; } + + /// + /// HTTP 返回码 + /// + public long HttpCode { get; private set; } + + /// + /// 错误信息 + /// + public string Error { get; protected set; } + #endregion + + /// + /// 构造下载器基类 + /// + /// 请求地址 + /// UnityWebRequest 创建器(可选) + protected UnityWebRequestDownloaderBase(string url, UnityWebRequestDelegate webRequestCreator) + { + URL = url; + _webRequestCreator = webRequestCreator; + Status = EDownloadRequestStatus.None; + } + + /// + /// 发起请求 + /// + public void SendRequest() + { + if (Status == EDownloadRequestStatus.None) + { + Status = EDownloadRequestStatus.Running; + + try + { + CreateWebRequest(); + + if (_webRequest == null) + { + Status = EDownloadRequestStatus.Failed; + Error = $"[{GetType().Name}] Created web request is null."; + } + else + { + _webRequest.SendWebRequest(); + } + } + catch (Exception ex) + { + Status = EDownloadRequestStatus.Failed; + Error = $"[{GetType().Name}] Failed to create web request : {ex.Message}"; + } + } + } + + /// + /// 轮询请求 + /// + public void PollingRequest() + { + if (Status != EDownloadRequestStatus.Running) + return; + + DownloadProgress = _webRequest.downloadProgress; + DownloadedBytes = (long)_webRequest.downloadedBytes; + + CheckWatchdog(); + if (_webRequest.isDone == false) + return; + + HttpCode = _webRequest.responseCode; +#if UNITY_2020_3_OR_NEWER + bool isSuccess = _webRequest.result == UnityWebRequest.Result.Success; +#else + bool isSuccess = !_webRequest.isNetworkError && !_webRequest.isHttpError; +#endif + + if (isSuccess) + { + Status = EDownloadRequestStatus.Succeed; + OnRequestSucceed(); + } + else + { + Status = EDownloadRequestStatus.Failed; + Error = $"[{GetType().Name}] URL: {URL} - 错误: {_webRequest.error}"; + OnRequestFailed(); + } + + // 完成后释放 + DisposeWebRequest(); + } + + /// + /// 中止请求 + /// + public void AbortRequest() + { + if (Status == EDownloadRequestStatus.None || Status == EDownloadRequestStatus.Running) + { + Status = EDownloadRequestStatus.Aborted; + if (_webRequest != null) + _webRequest.Abort(); + } + } + + /// + /// 释放资源 + /// + public void Dispose() + { + DisposeWebRequest(); + } + + + /// + /// 创建 UnityWebRequest(子类实现) + /// + protected abstract void CreateWebRequest(); + + /// + /// 请求成功时的回调(子类可重写) + /// + protected virtual void OnRequestSucceed() + { + } + + /// + /// 请求失败时的回调(子类可重写) + /// + protected virtual void OnRequestFailed() + { + } + + + /// + /// 创建 UnityWebRequest GET 请求 + /// + /// 请求地址 + /// UnityWebRequest 实例 + protected UnityWebRequest CreateUnityWebRequestGet(string requestUrl) + { + if (_webRequestCreator != null) + return _webRequestCreator.Invoke(requestUrl); + + return new UnityWebRequest(requestUrl, UnityWebRequest.kHttpVerbGET); + } + + /// + /// 创建 UnityWebRequest HEAD 请求 + /// + /// 请求地址 + /// UnityWebRequest 实例 + protected UnityWebRequest CreateUnityWebRequestHead(string requestUrl) + { + return new UnityWebRequest(requestUrl, UnityWebRequest.kHttpVerbHEAD); + } + + /// + /// 应用通用请求参数 + /// + protected void ApplyRequestOptions(int timeout, int watchdogTime, Dictionary headers) + { + if (_webRequest == null) + throw new YooInternalException("Web request is null !"); + + // 设置看门狗超时时间 + _watchdogTime = watchdogTime; + + // 设置响应的超时时间 + if (timeout > 0) + _webRequest.timeout = timeout; + + // 设置响应头 + if (headers != null) + { + foreach (var header in headers) + { + _webRequest.SetRequestHeader(header.Key, header.Value); + } + } + } + + /// + /// 检测看门狗 + /// + private void CheckWatchdog() + { + if (_watchdogTime == 0) + return; + if (_watchdogAborted) + return; + +#if UNITY_2020_3_OR_NEWER + double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartupAsDouble; +#else + double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartup; +#endif + + if (DownloadedBytes != _lastDownloadBytes) + { + _lastDownloadBytes = DownloadedBytes; + _lastGetDataTime = realtimeSinceStartup; + } + else + { + double deltaTime = realtimeSinceStartup - _lastGetDataTime; + if (deltaTime > _watchdogTime) + { + _watchdogAborted = true; + AbortRequest(); //看门狗终止网络请求 + } + } + } + + /// + /// 释放资源 + /// + private void DisposeWebRequest() + { + if (_webRequest != null) + { + //注意:引擎底层会自动调用Abort方法 + _webRequest.Dispose(); + _webRequest = null; + } + } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestDownloaderBase.cs.meta similarity index 83% rename from Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs.meta rename to Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestDownloaderBase.cs.meta index c59ceee4..eae4cb2b 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs.meta +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestDownloaderBase.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9e71e850eded0da43906cb4f7cb75629 +guid: 76b0712524ed69542914db8e44fa64fd MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestFileDownloader.cs b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestFileDownloader.cs new file mode 100644 index 00000000..11273e45 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestFileDownloader.cs @@ -0,0 +1,56 @@ +using System; +using UnityEngine.Networking; + +namespace YooAsset +{ + /// + /// UnityWebRequest 文件下载器 + /// + /// + /// 将下载内容保存到本地文件,支持断点续传和追加写入。 + /// + internal sealed class UnityWebRequestFileDownloader : UnityWebRequestDownloaderBase, IDownloadFileRequest + { + private readonly DownloadFileRequestArgs _args; + + /// + /// 文件保存路径 + /// + public string SavePath + { + get { return _args.SavePath; } + } + + /// + /// 构造文件下载器 + /// + /// 文件下载参数 + /// UnityWebRequest 创建器(可选) + public UnityWebRequestFileDownloader(DownloadFileRequestArgs args, UnityWebRequestDelegate webRequestCreator) + : base(args.URL, webRequestCreator) + { + _args = args; + } + + /// + /// 创建 UnityWebRequest + /// + protected override void CreateWebRequest() + { + var handler = new DownloadHandlerFile(_args.SavePath, _args.AppendToFile); + handler.removeFileOnAbort = _args.RemoveFileOnAbort; + + _webRequest = CreateUnityWebRequestGet(URL); + _webRequest.downloadHandler = handler; + _webRequest.disposeDownloadHandlerOnDispose = true; + + // 断点续传:设置 Range 请求头 + if (_args.ResumeFromBytes > 0) + { + _webRequest.SetRequestHeader("Range", $"bytes={_args.ResumeFromBytes}-"); + } + + ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers); + } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebCacheRequestOperation.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestFileDownloader.cs.meta similarity index 83% rename from Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebCacheRequestOperation.cs.meta rename to Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestFileDownloader.cs.meta index fba41120..60dc7be6 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebCacheRequestOperation.cs.meta +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestFileDownloader.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 375d88bcf5b9a6146adaf98ceb5369f8 +guid: 101a4be1bb0a85c4d84ecbf3e74f89e4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestHeadDownloader.cs b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestHeadDownloader.cs new file mode 100644 index 00000000..ef3e4ff3 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestHeadDownloader.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Networking; + +namespace YooAsset +{ + /// + /// UnityWebRequest HEAD 请求下载器 + /// + /// + /// 仅获取响应头信息,不下载实际内容。 + /// 用于检查资源是否存在、获取资源大小、检查缓存有效性等场景。 + /// + internal sealed class UnityWebRequestHeadDownloader : UnityWebRequestDownloaderBase, IDownloadHeadRequest + { + // 注意:缓存响应头(因为 WebRequest 释放后无法获取) + private Dictionary _cachedResponseHeaders; + private readonly DownloadDataRequestArgs _args; + + /// + /// 获取 ETag 响应头 + /// + public string ETag + { + get { return GetResponseHeader("ETag"); } + } + + /// + /// 获取 Last-Modified 响应头 + /// + public string LastModified + { + get { return GetResponseHeader("Last-Modified"); } + } + + /// + /// 获取 Content-Type 响应头 + /// + public string ContentType + { + get { return GetResponseHeader("Content-Type"); } + } + + /// + /// 获取 Content-Length 响应头 + /// 预期下载的总字节数 + /// + public long ContentLength + { + get + { + string contentLengthStr = GetResponseHeader("Content-Length"); + if (string.IsNullOrEmpty(contentLengthStr)) + return -1; + + if (long.TryParse(contentLengthStr, out long contentLength)) + { + return contentLength; + } + else + { + return -1; + } + } + } + + /// + /// 构造 HEAD 请求下载器 + /// + /// 数据下载参数 + /// UnityWebRequest 创建器(可选) + public UnityWebRequestHeadDownloader(DownloadDataRequestArgs args, UnityWebRequestDelegate webRequestCreator) + : base(args.URL, webRequestCreator) + { + _args = args; + } + + /// + /// 获取响应头信息 + /// + /// 响应头名称(不区分大小写) + /// 响应头的值,如果不存在或请求未完成则返回 null + public string GetResponseHeader(string name) + { + if (_cachedResponseHeaders == null) + return null; + + // 注意:UnityWebRequest 的响应头 key 是小写的 + string lowerName = name.ToLowerInvariant(); + if (_cachedResponseHeaders.TryGetValue(lowerName, out string value)) + return value; + + return null; + } + + /// + /// 创建 UnityWebRequest + /// + protected override void CreateWebRequest() + { + _webRequest = CreateUnityWebRequestHead(URL); + _webRequest.downloadHandler = null; // HEAD 请求不需要 DownloadHandler + ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers); + } + + /// + /// 请求成功时的回调 + /// + protected override void OnRequestSucceed() + { + var headers = _webRequest.GetResponseHeaders(); + if (headers != null) + { + _cachedResponseHeaders = new Dictionary(headers.Count, StringComparer.OrdinalIgnoreCase); + foreach (var kvp in headers) + { + string name = kvp.Key.ToLowerInvariant(); + string value = kvp.Value; + _cachedResponseHeaders[name] = value; + } + } + } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestHeadDownloader.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestHeadDownloader.cs.meta new file mode 100644 index 00000000..3e18504a --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestHeadDownloader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ed243d707130394aa85e20dee876d8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestTextDownloader.cs b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestTextDownloader.cs new file mode 100644 index 00000000..7c429afa --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestTextDownloader.cs @@ -0,0 +1,61 @@ +using System; +using UnityEngine.Networking; + +namespace YooAsset +{ + /// + /// UnityWebRequest 文本下载器 + /// + /// + /// 将下载内容解析为 UTF-8 文本字符串。 + /// + internal sealed class UnityWebRequestTextDownloader : UnityWebRequestDownloaderBase, IDownloadTextRequest + { + private readonly DownloadDataRequestArgs _args; + + /// + /// 下载结果(文本字符串) + /// + public string Result { get; private set; } + + /// + /// 构造文本下载器 + /// + /// 数据下载参数 + /// UnityWebRequest 创建器(可选) + public UnityWebRequestTextDownloader(DownloadDataRequestArgs args, UnityWebRequestDelegate webRequestCreator) + : base(args.URL, webRequestCreator) + { + _args = args; + } + + /// + /// 创建 UnityWebRequest + /// + protected override void CreateWebRequest() + { + var handler = new DownloadHandlerBuffer(); + _webRequest = CreateUnityWebRequestGet(URL); + _webRequest.downloadHandler = handler; + _webRequest.disposeDownloadHandlerOnDispose = true; + ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers); + } + + /// + /// 请求成功时的回调 + /// + protected override void OnRequestSucceed() + { + var fileText = _webRequest.downloadHandler.text; + if (string.IsNullOrEmpty(fileText)) + { + Status = EDownloadRequestStatus.Failed; + Error = $"[{GetType().Name}] URL: {URL} - Download text data is null or empty"; + } + else + { + Result = fileText; + } + } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestTextDownloader.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestTextDownloader.cs.meta new file mode 100644 index 00000000..cbf4bfe6 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/UnityWebRequestTextDownloader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b0bd3024ca5bae4dbdc05c7af7479df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/VirtualFileDownloader.cs b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/VirtualFileDownloader.cs new file mode 100644 index 00000000..6cf5ab9b --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/VirtualFileDownloader.cs @@ -0,0 +1,149 @@ +using System; + +namespace YooAsset +{ + /// + /// 模拟下载器 + /// + /// + /// 用于编辑器模式下模拟下载进度,不进行实际网络请求。 + /// 根据配置的下载速度模拟进度变化。 + /// + internal sealed class VirtualFileDownloader : IDownloadFileRequest + { + private readonly DownloadSimulateRequestArgs _args; + private double _lastUpdateTime; + + /// + /// 文件保存路径(模拟下载不需要) + /// + public string SavePath + { + get { return null; } + } + + #region 接口实现 + /// + /// 请求地址 + /// + public string URL { get; } + + /// + /// 是否完成 + /// + public bool IsDone + { + get + { + PollingRequest(); + return Status == EDownloadRequestStatus.Succeed + || Status == EDownloadRequestStatus.Failed + || Status == EDownloadRequestStatus.Aborted; + } + } + + /// + /// 请求状态 + /// + public EDownloadRequestStatus Status { get; private set; } + + /// + /// 当前下载进度(0f - 1f) + /// + public float DownloadProgress { get; private set; } + + /// + /// 当前请求已接收的字节数 + /// + public long DownloadedBytes { get; private set; } + + /// + /// HTTP 返回码(模拟固定返回 200) + /// + public long HttpCode { get; private set; } + + /// + /// 错误信息 + /// + public string Error { get; private set; } + #endregion + + /// + /// 构造模拟下载器 + /// + /// 模拟下载参数 + public VirtualFileDownloader(DownloadSimulateRequestArgs args) + { + _args = args; + Status = EDownloadRequestStatus.None; + } + + /// + /// 发起请求 + /// + public void SendRequest() + { + if (Status == EDownloadRequestStatus.None) + { + Status = EDownloadRequestStatus.Running; + _lastUpdateTime = GetUnityEngineRealtime(); + } + } + + /// + /// 轮询请求 + /// + public void PollingRequest() + { + if (Status != EDownloadRequestStatus.Running) + return; + + double currentTime = GetUnityEngineRealtime(); + double deltaTime = currentTime - _lastUpdateTime; + _lastUpdateTime = currentTime; + + // 计算本帧下载的字节数 + long downloadBytes = (long)(_args.DownloadSpeed * deltaTime); + DownloadedBytes += downloadBytes; + + if (_args.FileSize > 0) + DownloadProgress = (float)DownloadedBytes / _args.FileSize; + + // 检查是否完成 + if (DownloadedBytes >= _args.FileSize) + { + HttpCode = 200; + DownloadProgress = 1f; + DownloadedBytes = _args.FileSize; + Status = EDownloadRequestStatus.Succeed; + } + } + + /// + /// 中止请求 + /// + public void AbortRequest() + { + if (Status == EDownloadRequestStatus.None || Status == EDownloadRequestStatus.Running) + { + Status = EDownloadRequestStatus.Aborted; + } + } + + /// + /// 释放资源 + /// + public void Dispose() + { + } + + private double GetUnityEngineRealtime() + { +#if UNITY_2020_3_OR_NEWER + return UnityEngine.Time.realtimeSinceStartupAsDouble; +#else + return = UnityEngine.Time.realtimeSinceStartup; +#endif + } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/VirtualFileDownloader.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/VirtualFileDownloader.cs.meta new file mode 100644 index 00000000..d38ea991 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DefaultDownloadRequest/VirtualFileDownloader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 84daeb1559aadff40b5b5aa5c81d7d64 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DownloadDefine.cs b/Assets/YooAsset/Runtime/DownloadSystem/DownloadDefine.cs deleted file mode 100644 index bacaae33..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/DownloadDefine.cs +++ /dev/null @@ -1,118 +0,0 @@ - -namespace YooAsset -{ - /// - /// 下载器结束 - /// - public struct DownloaderFinishData - { - /// - /// 所属包裹名称 - /// - public string PackageName; - - /// - /// 是否成功 - /// - public bool Succeed; - } - - /// - /// 下载器相关的更新数据 - /// - public struct DownloadUpdateData - { - /// - /// 所属包裹名称 - /// - public string PackageName; - - /// - /// 下载进度 (0-1f) - /// - public float Progress; - - /// - /// 下载文件总数 - /// - public int TotalDownloadCount; - - /// - /// 当前完成的下载文件数量 - /// - public int CurrentDownloadCount; - - /// - /// 下载数据总大小(单位:字节) - /// - public long TotalDownloadBytes; - - /// - /// 当前完成的下载数据大小(单位:字节) - /// - public long CurrentDownloadBytes; - } - - /// - /// 下载器相关的错误数据 - /// - public struct DownloadErrorData - { - /// - /// 所属包裹名称 - /// - public string PackageName; - - /// - /// 下载失败的文件名称 - /// - public string FileName; - - /// - /// 错误信息 - /// - public string ErrorInfo; - } - - /// - /// 下载器相关的文件数据 - /// - public struct DownloadFileData - { - /// - /// 所属包裹名称 - /// - public string PackageName; - - /// - /// 下载的文件名称 - /// - public string FileName; - - /// - /// 下载的文件大小 - /// - public long FileSize; - } - - /// - /// 导入文件的信息 - /// - public struct ImportFileInfo - { - /// - /// 本地文件路径 - /// - public string FilePath; - - /// - /// 资源包名称 - /// - public string BundleName; - - /// - /// 资源包GUID - /// - public string BundleGUID; - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs new file mode 100644 index 00000000..1fe19898 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs @@ -0,0 +1,443 @@ +using System.Collections.Generic; + +namespace YooAsset +{ + /// + /// 下载器结束 + /// + public struct DownloaderFinishData + { + /// + /// 所属包裹名称 + /// + public string PackageName; + + /// + /// 是否成功 + /// + public bool Succeed; + } + + /// + /// 下载器相关的更新数据 + /// + public struct DownloadUpdateData + { + /// + /// 所属包裹名称 + /// + public string PackageName; + + /// + /// 下载进度 (0-1f) + /// + public float Progress; + + /// + /// 下载文件总数 + /// + public int TotalDownloadCount; + + /// + /// 当前完成的下载文件数量 + /// + public int CurrentDownloadCount; + + /// + /// 下载数据总大小(单位:字节) + /// + public long TotalDownloadBytes; + + /// + /// 当前完成的下载数据大小(单位:字节) + /// + public long CurrentDownloadBytes; + } + + /// + /// 下载器相关的错误数据 + /// + public struct DownloadErrorData + { + /// + /// 所属包裹名称 + /// + public string PackageName; + + /// + /// 下载失败的文件名称 + /// + public string FileName; + + /// + /// 错误信息 + /// + public string ErrorInfo; + } + + /// + /// 下载器相关的文件数据 + /// + public struct DownloadFileData + { + /// + /// 所属包裹名称 + /// + public string PackageName; + + /// + /// 下载的文件名称 + /// + public string FileName; + + /// + /// 下载的文件大小 + /// + public long FileSize; + } + + /// + /// 导入文件的信息 + /// + public struct ImportFileInfo + { + /// + /// 本地文件路径 + /// + public string FilePath; + + /// + /// 资源包名称 + /// + public string BundleName; + + /// + /// 资源包GUID + /// + public string BundleGUID; + } + + + /// + /// 下载请求状态 + /// + internal enum EDownloadRequestStatus + { + /// + /// 未开始 + /// + None, + + /// + /// 进行中 + /// + Running, + + /// + /// 已成功 + /// + Succeed, + + /// + /// 已失败 + /// + Failed, + + /// + /// 已中止 + /// + Aborted, + } + + /// + /// 文件下载请求参数 + /// + /// + /// 用于将下载内容保存到本地文件的请求配置。 + /// 支持断点续传和追加写入模式。 + /// + internal struct DownloadFileRequestArgs + { + /// + /// 请求地址 + /// + public readonly string URL; + + /// + /// 响应的超时时间(单位:秒) + /// + /// + /// 当 Timeout 设置为 0 时,不应用超时。 + /// 设置的超时值可能应用于Android上的每个URL重定向,这可能会导致响应时间增加。 + /// + public readonly int Timeout; + + /// + /// 看门狗超时时间(单位:秒) + /// + /// + /// 用于监控下载任务的数据接收情况。 + /// 规则说明: + /// 1. 当设置值为 0 时,表示禁用看门狗监控。 + /// 2. 每次接收到下载数据时,看门狗计时器会重置。 + /// 3. 若在设定的时间范围内未收到任何数据,任务将被自动终止。 + /// + public readonly int WatchdogTime; + + /// + /// 文件保存路径 + /// + public readonly string SavePath; + + /// + /// 是否追加写入文件 + /// + /// + /// 配合 ResumeFromBytes 使用,用于断点续传场景。 + /// + public readonly bool AppendToFile; + + /// + /// 中止请求时是否删除目标文件 + /// + public readonly bool RemoveFileOnAbort; + + /// + /// 断点续传的起始字节(小于等于 0 表示不启用) + /// + /// + /// 推荐由后端自动设置 Range 请求头:"bytes={ResumeFromBytes}-"。 + /// + public readonly long ResumeFromBytes; + + /// + /// 自定义请求头(可选) + /// + public Dictionary Headers; + + /// + /// 构造文件下载请求参数 + /// + public DownloadFileRequestArgs( + string url, + string savePath, + int timeout, + int watchdogTime, + bool appendToFile = false, + bool removeFileOnAbort = true, + long resumeFromBytes = 0) + { + URL = url; + SavePath = savePath; + Timeout = timeout; + WatchdogTime = watchdogTime; + AppendToFile = appendToFile; + RemoveFileOnAbort = removeFileOnAbort; + ResumeFromBytes = resumeFromBytes; + Headers = null; + } + + /// + /// 添加请求头数据 + /// + public void AddRequestHeader(string name, string value) + { + if (Headers == null) + Headers = new Dictionary(10); + Headers.Add(name, value); + } + } + + /// + /// 数据下载请求参数(通用) + /// + /// + /// 用于下载到内存的请求配置。 + /// 可用于字节数组(bytes)或文本(text)下载。 + /// + internal struct DownloadDataRequestArgs + { + /// + /// 请求地址 + /// + public readonly string URL; + + /// + /// 响应的超时时间(单位:秒) + /// + /// + /// 当 Timeout 设置为 0 时,不应用超时。 + /// 设置的超时值可能应用于Android上的每个URL重定向,这可能会导致响应时间增加。 + /// + public readonly int Timeout; + + /// + /// 看门狗超时时间(单位:秒) + /// + /// + /// 用于监控下载任务的数据接收情况。 + /// 规则说明: + /// 1. 当设置值为 0 时,表示禁用看门狗监控。 + /// 2. 每次接收到下载数据时,看门狗计时器会重置。 + /// 3. 若在设定的时间范围内未收到任何数据,任务将被自动终止。 + /// + public readonly int WatchdogTime; + + /// + /// 自定义请求头(可选) + /// + public Dictionary Headers; + + /// + /// 构造数据下载请求参数 + /// + /// 请求地址 + /// 通用请求参数 + public DownloadDataRequestArgs(string url, int timeout, int watchdogTime) + { + URL = url; + Timeout = timeout; + WatchdogTime = watchdogTime; + Headers = null; + } + + /// + /// 添加请求头数据 + /// + public void AddRequestHeader(string name, string value) + { + if (Headers == null) + Headers = new Dictionary(10); + Headers.Add(name, value); + } + } + + /// + /// AssetBundle 下载请求参数 + /// + /// + /// 用于下载并加载 Unity AssetBundle 的请求配置。 + /// 支持 Unity 内置缓存机制和 CRC 校验。 + /// + internal struct DownloadAssetBundleRequestArgs + { + /// + /// 请求地址 + /// + public readonly string URL; + + /// + /// 响应的超时时间(单位:秒) + /// + /// + /// 当 Timeout 设置为 0 时,不应用超时。 + /// 设置的超时值可能应用于Android上的每个URL重定向,这可能会导致响应时间增加。 + /// + public readonly int Timeout; + + /// + /// 看门狗超时时间(单位:秒) + /// + /// + /// 用于监控下载任务的数据接收情况。 + /// 规则说明: + /// 1. 当设置值为 0 时,表示禁用看门狗监控。 + /// 2. 每次接收到下载数据时,看门狗计时器会重置。 + /// 3. 若在设定的时间范围内未收到任何数据,任务将被自动终止。 + /// + public readonly int WatchdogTime; + + /// + /// 禁用 Unity 的网络缓存 + /// + public readonly bool DisableUnityWebCache; + + /// + /// AssetBundle 文件哈希(用于 UnityWebRequest 的缓存) + /// + /// + /// 仅当 DisableUnityWebCache 为 false 时需要。 + /// + public readonly string FileHash; + + /// + /// Unity CRC 校验值 + /// + public readonly uint UnityCRC; + + /// + /// 自定义请求头(可选) + /// + public Dictionary Headers; + + /// + /// 构造 AssetBundle 下载请求参数 + /// + public DownloadAssetBundleRequestArgs( + string url, + int timeout, + int watchdogTime, + bool disableUnityWebCache = true, + string fileHash = null, + uint unityCrc = 0) + { + URL = url; + Timeout = timeout; + WatchdogTime = watchdogTime; + DisableUnityWebCache = disableUnityWebCache; + FileHash = fileHash; + UnityCRC = unityCrc; + Headers = null; + } + + /// + /// 添加请求头数据 + /// + public void AddRequestHeader(string name, string value) + { + if (Headers == null) + Headers = new Dictionary(10); + Headers.Add(name, value); + } + } + + /// + /// 模拟下载请求参数 + /// + /// + /// 用于编辑器模式下模拟下载进度,不进行实际网络请求。 + /// + internal struct DownloadSimulateRequestArgs + { + /// + /// 请求地址(仅用于标识) + /// + public readonly string URL; + + /// + /// 模拟的文件大小(字节) + /// + public readonly long FileSize; + + /// + /// 模拟的下载速度(字节/秒) + /// + /// + /// 用于计算模拟的下载进度。 + /// + public readonly long DownloadSpeed; + + /// + /// 构造模拟下载请求参数 + /// + /// 请求地址(仅用于标识) + /// 模拟的文件大小(字节) + /// 模拟的下载速度(字节/秒),默认 1MB/s + public DownloadSimulateRequestArgs(string url, long fileSize, long downloadSpeed = 1024 * 1024) + { + URL = url; + FileSize = fileSize; + DownloadSpeed = downloadSpeed > 0 ? downloadSpeed : 1024 * 1024; + } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs.meta new file mode 100644 index 00000000..ca5adcde --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemDefine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb0480e877454f7c944f66a01646b6d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemHelper.cs b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemHelper.cs index 09ccd358..c0f8fb54 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemHelper.cs +++ b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystemHelper.cs @@ -94,8 +94,12 @@ namespace YooAsset public static bool IsRequestLocalFile(string url) { //TODO UNITY_STANDALONE_OSX平台目前无法确定 + + // 本地文件传输协议 if (url.StartsWith("file:")) return true; + + // JAR文件协议 if (url.StartsWith("jar:file:")) return true; diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal.meta b/Assets/YooAsset/Runtime/DownloadSystem/Interface.meta similarity index 77% rename from Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal.meta rename to Assets/YooAsset/Runtime/DownloadSystem/Interface.meta index 159e6467..22a2e083 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal.meta +++ b/Assets/YooAsset/Runtime/DownloadSystem/Interface.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4630dac2050606043bb146325fdce6ad +guid: d724672f4d6f24b4db435d10eef6c40d folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadBackend.cs b/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadBackend.cs new file mode 100644 index 00000000..09bd7138 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadBackend.cs @@ -0,0 +1,78 @@ +using System; + +namespace YooAsset +{ + /// + /// 下载后台接口 + /// + /// + /// 不同网络库(UnityWebRequest / BestHTTP / 自研)实现该接口,用于创建具体下载请求。 + /// 每个后台实例是独立的,不共享全局状态。 + /// + internal interface IDownloadBackend : IDisposable + { + /// + /// 后台名称(用于日志与调试) + /// + string Name { get; } + + /// + /// 驱动更新 + /// + /// + /// 部分第三方网络库需要在 Unity 主线程中周期性调用 Update 进行驱动。 + /// 不需要驱动的后台可实现为空方法。 + /// + void Update(); + + /// + /// 创建 HEAD 请求 + /// + /// + /// 仅获取响应头信息,不下载实际内容。 + /// 用于检查资源是否存在、获取资源大小、检查缓存有效性等场景。 + /// + /// 数据请求参数 + /// HEAD 请求实例 + IDownloadHeadRequest CreateHeadRequest(DownloadDataRequestArgs args); + + /// + /// 创建文件下载请求 + /// + /// 文件下载参数 + /// 文件下载请求实例 + IDownloadFileRequest CreateFileRequest(DownloadFileRequestArgs args); + + /// + /// 创建内存下载请求(字节数组) + /// + /// 数据下载参数 + /// 字节下载请求实例 + IDownloadBytesRequest CreateBytesRequest(DownloadDataRequestArgs args); + + /// + /// 创建文本下载请求 + /// + /// 数据下载参数 + /// 文本下载请求实例 + IDownloadTextRequest CreateTextRequest(DownloadDataRequestArgs args); + + /// + /// 创建 AssetBundle 下载请求 + /// + /// AssetBundle 下载参数 + /// AssetBundle 下载请求实例 + IDownloadAssetBundleRequest CreateAssetBundleRequest(DownloadAssetBundleRequestArgs args); + + /// + /// 创建模拟下载请求 + /// + /// + /// 用于编辑器模式下模拟下载进度,不进行实际网络请求。 + /// 可用于测试下载流程和 UI 展示。 + /// + /// 模拟下载参数 + /// 模拟下载请求实例 + IDownloadFileRequest CreateSimulateRequest(DownloadSimulateRequestArgs args); + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadBackend.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadBackend.cs.meta new file mode 100644 index 00000000..a24994da --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadBackend.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e88c026ebbfb40258aad52ad1c2feb70 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadRequest.cs b/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadRequest.cs new file mode 100644 index 00000000..4feac65b --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadRequest.cs @@ -0,0 +1,194 @@ +using System; + +namespace YooAsset +{ + /// + /// 可轮询的下载请求接口 + /// + /// + /// 上层通常会在每帧轮询 Status IsDone,并在完成后读取结果。 + /// + internal interface IDownloadRequest : IDisposable + { + /// + /// 请求地址 + /// + string URL { get; } + + /// + /// 是否完成(成功/失败/中止) + /// + bool IsDone { get; } + + /// + /// 请求状态 + /// + EDownloadRequestStatus Status { get; } + + /// + /// 当前下载进度(0f - 1f) + /// + /// + /// 部分情况下无法准确获取总长度,可返回 0。 + /// + float DownloadProgress { get; } + + /// + /// 当前请求已接收的字节数 + /// + /// + /// 断点续传场景下,该值仅表示"本次请求新增下载的字节数",不包含已存在的本地文件长度。 + /// + long DownloadedBytes { get; } + + /// + /// HTTP 返回码 + /// + /// + /// 非 HTTP 协议可返回 0。使用 long 类型以兼容各种协议的返回码。 + /// + long HttpCode { get; } + + /// + /// 错误信息 + /// + /// + /// 失败时不为空。 + /// + string Error { get; } + + /// + /// 发起请求 + /// + void SendRequest(); + + /// + /// 轮询请求 + /// + void PollingRequest(); + + /// + /// 中止请求 + /// + void AbortRequest(); + } + + /// + /// HEAD 请求接口(仅获取响应头) + /// + /// + /// 用于检查资源是否存在、获取资源大小、检查缓存有效性等场景。 + /// 不下载实际内容,仅获取响应头信息。 + /// + internal interface IDownloadHeadRequest : IDownloadRequest + { + /// + /// 获取 ETag 响应头 + /// + /// + /// 用于缓存验证,如果服务器未返回则为 null。 + /// + string ETag { get; } + + /// + /// 获取 Last-Modified 响应头 + /// + /// + /// 资源最后修改时间,如果服务器未返回则为 null。 + /// + string LastModified { get; } + + /// + /// 获取 Content-Type 响应头 + /// + /// + /// 资源的 MIME 类型,如果服务器未返回则为 null。 + /// + string ContentType { get; } + + /// + /// 预期下载的总字节数(Content-Length) + /// + /// + /// 从响应头 Content-Length 获取。 + /// 如果服务器未返回或请求未完成,返回 -1。 + /// 用于更准确的进度计算。 + /// + long ContentLength { get; } + + /// + /// 获取响应头信息 + /// + /// 响应头名称(不区分大小写) + /// 响应头的值,如果不存在或请求未完成则返回 null + /// + /// 常用响应头:Content-Length、Content-Type、ETag、Last-Modified 等。 + /// + string GetResponseHeader(string name); + } + + /// + /// 文件下载请求接口 + /// + /// + /// 将下载内容保存到指定的本地文件路径。 + /// + internal interface IDownloadFileRequest : IDownloadRequest + { + /// + /// 文件保存路径 + /// + string SavePath { get; } + } + + /// + /// 内存下载请求接口(字节数组) + /// + /// + /// 将下载内容保存到内存中的字节数组。 + /// + internal interface IDownloadBytesRequest : IDownloadRequest + { + /// + /// 下载结果(字节数组) + /// + /// + /// 仅在请求成功时可用,失败时为 null。 + /// + byte[] Result { get; } + } + + /// + /// 文本下载请求接口 + /// + /// + /// 将下载内容解析为 UTF-8 文本字符串。 + /// + internal interface IDownloadTextRequest : IDownloadRequest + { + /// + /// 下载结果(文本字符串) + /// + /// + /// 仅在请求成功时可用,失败时为 null。 + /// + string Result { get; } + } + + /// + /// AssetBundle 下载请求接口 + /// + /// + /// 下载并加载 Unity AssetBundle 资源包。 + /// + internal interface IDownloadAssetBundleRequest : IDownloadRequest + { + /// + /// 下载结果(AssetBundle 对象) + /// + /// + /// 仅在请求成功时可用,失败时为 null。 + /// + UnityEngine.AssetBundle Result { get; } + } +} diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadRequest.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadRequest.cs.meta new file mode 100644 index 00000000..ea1e9d3e --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/Interface/IDownloadRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a2aafeb309243f4959394a97d66b19f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityAssetBundleRequestOperation.cs b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityAssetBundleRequestOperation.cs deleted file mode 100644 index 3ffcd966..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityAssetBundleRequestOperation.cs +++ /dev/null @@ -1,113 +0,0 @@ -using UnityEngine.Networking; -using UnityEngine; - -namespace YooAsset -{ - internal class UnityAssetBundleRequestOperation : UnityWebRequestOperation - { - protected enum ESteps - { - None, - CreateRequest, - Download, - Done, - } - - private UnityWebRequestAsyncOperation _requestOperation; - private DownloadHandlerAssetBundle _downloadhandler; - private readonly PackageBundle _packageBundle; - private readonly bool _disableUnityWebCache; - private ESteps _steps = ESteps.None; - - /// - /// 请求结果 - /// - public AssetBundle Result { private set; get; } - - internal UnityAssetBundleRequestOperation(PackageBundle packageBundle, bool disableUnityWebCache, string url) : base(url) - { - _packageBundle = packageBundle; - _disableUnityWebCache = disableUnityWebCache; - } - internal override void InternalStart() - { - _steps = ESteps.CreateRequest; - } - internal override void InternalUpdate() - { - if (_steps == ESteps.None || _steps == ESteps.Done) - return; - - if (_steps == ESteps.CreateRequest) - { - CreateWebRequest(); - _steps = ESteps.Download; - } - - if (_steps == ESteps.Download) - { - DownloadProgress = _webRequest.downloadProgress; - DownloadedBytes = (long)_webRequest.downloadedBytes; - Progress = _requestOperation.progress; - if (_requestOperation.isDone == false) - return; - - if (CheckRequestResult()) - { - AssetBundle assetBundle = _downloadhandler.assetBundle; - if (assetBundle == null) - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = $"URL : {_requestURL} Download handler asset bundle object is null !"; - } - else - { - _steps = ESteps.Done; - Result = assetBundle; - Status = EOperationStatus.Succeed; - } - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - } - - // 注意:最终释放请求器 - DisposeRequest(); - } - } - - private void CreateWebRequest() - { - _downloadhandler = CreateWebDownloadHandler(); - _webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL); - _webRequest.downloadHandler = _downloadhandler; - _webRequest.disposeDownloadHandlerOnDispose = true; - _requestOperation = _webRequest.SendWebRequest(); - } - private DownloadHandlerAssetBundle CreateWebDownloadHandler() - { - if (_disableUnityWebCache) - { - var downloadhandler = new DownloadHandlerAssetBundle(_requestURL, _packageBundle.UnityCRC); -#if UNITY_2020_3_OR_NEWER - downloadhandler.autoLoadAssetBundle = false; -#endif - return downloadhandler; - } - else - { - // 注意:优先从浏览器缓存里获取文件 - // The file hash defining the version of the asset bundle. - Hash128 fileHash = Hash128.Parse(_packageBundle.FileHash); - var downloadhandler = new DownloadHandlerAssetBundle(_requestURL, fileHash, _packageBundle.UnityCRC); -#if UNITY_2020_3_OR_NEWER - downloadhandler.autoLoadAssetBundle = false; -#endif - return downloadhandler; - } - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs deleted file mode 100644 index 1923bfd8..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs +++ /dev/null @@ -1,65 +0,0 @@ -using UnityEngine.Networking; -using UnityEngine; - -namespace YooAsset -{ - internal class UnityVirtualBundleRequestOperation : UnityWebRequestOperation - { - protected enum ESteps - { - None, - Download, - Done, - } - - private readonly PackageBundle _bundle; - private readonly int _downloadSpeed; - private ESteps _steps = ESteps.None; - - internal UnityVirtualBundleRequestOperation(PackageBundle packageBundle, int downloadSpeed, string url) : base(url) - { - _bundle = packageBundle; - _downloadSpeed = downloadSpeed; - } - internal override void InternalStart() - { - _steps = ESteps.Download; - } - internal override void InternalUpdate() - { - if (_steps == ESteps.None || _steps == ESteps.Done) - return; - - if (_steps == ESteps.Download) - { - // 模拟下载进度 - float progress = 0; - if (DownloadedBytes > 0) - progress = DownloadedBytes / _bundle.FileSize; - long downloadBytes = (long)((double)_downloadSpeed * Time.deltaTime); - - Progress = progress; - DownloadProgress = progress; - DownloadedBytes += downloadBytes; - if (DownloadedBytes < _bundle.FileSize) - return; - - Progress = 1f; - DownloadProgress = 1f; - DownloadedBytes = _bundle.FileSize; - - _steps = ESteps.Done; - Status = EOperationStatus.Succeed; - } - } - internal override void InternalWaitForAsyncComplete() - { - if (_steps != ESteps.Done) - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = $"Try load bundle {_bundle.BundleName} from remote !"; - } - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebCacheRequestOperation.cs b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebCacheRequestOperation.cs deleted file mode 100644 index a5b8a72b..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebCacheRequestOperation.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine.Networking; -using UnityEngine; - -namespace YooAsset -{ - internal class UnityWebCacheRequestOperation : UnityWebRequestOperation - { - protected enum ESteps - { - None, - CreateRequest, - Download, - Done, - } - - private UnityWebRequestAsyncOperation _requestOperation; - private readonly Dictionary _headers = new Dictionary(); - private ESteps _steps = ESteps.None; - - - internal UnityWebCacheRequestOperation(string url) : base(url) - { - } - internal override void InternalStart() - { - _steps = ESteps.CreateRequest; - } - internal override void InternalUpdate() - { - if (_steps == ESteps.None || _steps == ESteps.Done) - return; - - if (_steps == ESteps.CreateRequest) - { - CreateWebRequest(); - _steps = ESteps.Download; - } - - if (_steps == ESteps.Download) - { - DownloadProgress = _webRequest.downloadProgress; - DownloadedBytes = (long)_webRequest.downloadedBytes; - Progress = _requestOperation.progress; - if (_requestOperation.isDone == false) - return; - - if (CheckRequestResult()) - { - _steps = ESteps.Done; - Status = EOperationStatus.Succeed; - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - } - - // 注意:最终释放请求器 - DisposeRequest(); - } - } - - /// - /// 设置请求头信息 - /// - public void SetRequestHeader(string name, string value) - { - _headers.Add(name, value); - } - - private void CreateWebRequest() - { - _webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL); - _webRequest.disposeDownloadHandlerOnDispose = true; - - // 设置消息头 - foreach (var keyValuePair in _headers) - { - string name = keyValuePair.Key; - string value = keyValuePair.Value; - _webRequest.SetRequestHeader(name, value); - } - - _requestOperation = _webRequest.SendWebRequest(); - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebDataRequestOperation.cs b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebDataRequestOperation.cs deleted file mode 100644 index 1ffbad24..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebDataRequestOperation.cs +++ /dev/null @@ -1,96 +0,0 @@ -using UnityEngine.Networking; -using UnityEngine; - -namespace YooAsset -{ - internal class UnityWebDataRequestOperation : UnityWebRequestOperation - { - protected enum ESteps - { - None, - CreateRequest, - Download, - Done, - } - - private UnityWebRequestAsyncOperation _requestOperation; - private ESteps _steps = ESteps.None; - - /// - /// 响应的超时时间(单位:秒),在经过Timeout的秒数后尝试中止。 - /// 注意:当Timeout设置为0时,不会应用超时。 - /// 注意:设置的超时值可能应用于Android上的每个URL重定向,这可能会导致响应时间增加。 - /// - private readonly int _timeout; - - /// - /// 请求结果 - /// - public byte[] Result { private set; get; } - - - internal UnityWebDataRequestOperation(string url, int timeout) : base(url) - { - _timeout = timeout; - } - internal override void InternalStart() - { - _steps = ESteps.CreateRequest; - } - internal override void InternalUpdate() - { - if (_steps == ESteps.None || _steps == ESteps.Done) - return; - - if (_steps == ESteps.CreateRequest) - { - CreateWebRequest(); - _steps = ESteps.Download; - } - - if (_steps == ESteps.Download) - { - DownloadProgress = _webRequest.downloadProgress; - DownloadedBytes = (long)_webRequest.downloadedBytes; - Progress = _requestOperation.progress; - if (_requestOperation.isDone == false) - return; - - if (CheckRequestResult()) - { - var fileData = _webRequest.downloadHandler.data; - if (fileData == null || fileData.Length == 0) - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = $"URL : {_requestURL} Download handler data is null or empty !"; - } - else - { - _steps = ESteps.Done; - Result = fileData; - Status = EOperationStatus.Succeed; - } - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - } - - // 注意:最终释放请求器 - DisposeRequest(); - } - } - - private void CreateWebRequest() - { - DownloadHandlerBuffer handler = new DownloadHandlerBuffer(); - _webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL); - _webRequest.timeout = _timeout; - _webRequest.downloadHandler = handler; - _webRequest.disposeDownloadHandlerOnDispose = true; - _requestOperation = _webRequest.SendWebRequest(); - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebDataRequestOperation.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebDataRequestOperation.cs.meta deleted file mode 100644 index 1e4cc2d3..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebDataRequestOperation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b7557eb146572de49a1ec9b3f3c0b706 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebFileRequestOperation.cs b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebFileRequestOperation.cs deleted file mode 100644 index 20077fdf..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebFileRequestOperation.cs +++ /dev/null @@ -1,83 +0,0 @@ -using UnityEngine.Networking; -using UnityEngine; - -namespace YooAsset -{ - internal class UnityWebFileRequestOperation : UnityWebRequestOperation - { - protected enum ESteps - { - None, - CreateRequest, - Download, - Done, - } - - private UnityWebRequestAsyncOperation _requestOperation; - private readonly string _fileSavePath; - private ESteps _steps = ESteps.None; - - /// - /// 响应的超时时间(单位:秒),在经过Timeout的秒数后尝试中止。 - /// 注意:当Timeout设置为0时,不会应用超时。 - /// 注意:设置的超时值可能应用于Android上的每个URL重定向,这可能会导致响应时间增加。 - /// - private readonly int _timeout; - - - internal UnityWebFileRequestOperation(string url, string fileSavePath, int timeout) : base(url) - { - _fileSavePath = fileSavePath; - _timeout = timeout; - } - internal override void InternalStart() - { - _steps = ESteps.CreateRequest; - } - internal override void InternalUpdate() - { - if (_steps == ESteps.None || _steps == ESteps.Done) - return; - - if (_steps == ESteps.CreateRequest) - { - CreateWebRequest(); - _steps = ESteps.Download; - } - - if (_steps == ESteps.Download) - { - DownloadProgress = _webRequest.downloadProgress; - DownloadedBytes = (long)_webRequest.downloadedBytes; - Progress = _requestOperation.progress; - if (_requestOperation.isDone == false) - return; - - if (CheckRequestResult()) - { - _steps = ESteps.Done; - Status = EOperationStatus.Succeed; - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - } - - // 注意:最终释放请求器 - DisposeRequest(); - } - } - - private void CreateWebRequest() - { - DownloadHandlerFile handler = new DownloadHandlerFile(_fileSavePath); - handler.removeFileOnAbort = true; - _webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL); - _webRequest.timeout = _timeout; - _webRequest.downloadHandler = handler; - _webRequest.disposeDownloadHandlerOnDispose = true; - _requestOperation = _webRequest.SendWebRequest(); - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebFileRequestOperation.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebFileRequestOperation.cs.meta deleted file mode 100644 index 7e74c680..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebFileRequestOperation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2ab5f2486d06e2642ba7aa9c9623430e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebRequestOperation.cs b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebRequestOperation.cs deleted file mode 100644 index c8229ae1..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebRequestOperation.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using UnityEngine.Networking; -using UnityEngine; - -namespace YooAsset -{ - internal abstract class UnityWebRequestOperation : AsyncOperationBase - { - protected UnityWebRequest _webRequest; - protected readonly string _requestURL; - private bool _isAbort = false; - - /// - /// HTTP返回码 - /// - public long HttpCode { private set; get; } - - /// - /// 当前下载的字节数 - /// - public long DownloadedBytes { protected set; get; } - - /// - /// 当前下载进度(0f - 1f) - /// - public float DownloadProgress { protected set; get; } - - /// - /// 请求的URL地址 - /// - public string URL - { - get { return _requestURL; } - } - - internal UnityWebRequestOperation(string url) - { - _requestURL = url; - } - internal override void InternalAbort() - { - //TODO - // 1. 编辑器下停止运行游戏的时候主动终止下载任务 - // 2. 真机上销毁包裹的时候主动终止下载任务 - if (_isAbort == false) - { - if (_webRequest != null) - { - _webRequest.Abort(); - _isAbort = true; - } - } - } - - /// - /// 释放下载器 - /// - protected void DisposeRequest() - { - if (_webRequest != null) - { - //注意:引擎底层会自动调用Abort方法 - _webRequest.Dispose(); - _webRequest = null; - } - } - - /// - /// 检测请求结果 - /// - protected bool CheckRequestResult() - { - HttpCode = _webRequest.responseCode; - -#if UNITY_2020_3_OR_NEWER - if (_webRequest.result != UnityWebRequest.Result.Success) - { - Error = $"URL : {_requestURL} Error : {_webRequest.error}"; - return false; - } - else - { - return true; - } -#else - if (_webRequest.isNetworkError || _webRequest.isHttpError) - { - Error = $"URL : {_requestURL} Error : {_webRequest.error}"; - return false; - } - else - { - return true; - } -#endif - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebRequestOperation.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebRequestOperation.cs.meta deleted file mode 100644 index c7401fed..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebRequestOperation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4e5c3c1a1655a8b41b585c6811201583 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebTextRequestOperation.cs b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebTextRequestOperation.cs deleted file mode 100644 index 609cd1cf..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebTextRequestOperation.cs +++ /dev/null @@ -1,96 +0,0 @@ -using UnityEngine.Networking; -using UnityEngine; - -namespace YooAsset -{ - internal class UnityWebTextRequestOperation : UnityWebRequestOperation - { - protected enum ESteps - { - None, - CreateRequest, - Download, - Done, - } - - private UnityWebRequestAsyncOperation _requestOperation; - private ESteps _steps = ESteps.None; - - /// - /// 响应的超时时间(单位:秒),在经过Timeout的秒数后尝试中止。 - /// 注意:当Timeout设置为0时,不会应用超时。 - /// 注意:设置的超时值可能应用于Android上的每个URL重定向,这可能会导致响应时间增加。 - /// - private readonly int _timeout; - - /// - /// 请求结果 - /// - public string Result { private set; get; } - - - internal UnityWebTextRequestOperation(string url, int timeout) : base(url) - { - _timeout = timeout; - } - internal override void InternalStart() - { - _steps = ESteps.CreateRequest; - } - internal override void InternalUpdate() - { - if (_steps == ESteps.None || _steps == ESteps.Done) - return; - - if (_steps == ESteps.CreateRequest) - { - CreateWebRequest(); - _steps = ESteps.Download; - } - - if (_steps == ESteps.Download) - { - DownloadProgress = _webRequest.downloadProgress; - DownloadedBytes = (long)_webRequest.downloadedBytes; - Progress = _requestOperation.progress; - if (_requestOperation.isDone == false) - return; - - if (CheckRequestResult()) - { - var fileText = _webRequest.downloadHandler.text; - if (string.IsNullOrEmpty(fileText)) - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = $"URL : {_requestURL} Download handler text is null or empty !"; - } - else - { - _steps = ESteps.Done; - Result = fileText; - Status = EOperationStatus.Succeed; - } - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - } - - // 注意:最终释放请求器 - DisposeRequest(); - } - } - - private void CreateWebRequest() - { - DownloadHandlerBuffer handler = new DownloadHandlerBuffer(); - _webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL); - _webRequest.timeout = _timeout; - _webRequest.downloadHandler = handler; - _webRequest.disposeDownloadHandlerOnDispose = true; - _requestOperation = _webRequest.SendWebRequest(); - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebTextRequestOperation.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebTextRequestOperation.cs.meta deleted file mode 100644 index 14653aeb..00000000 --- a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityWebTextRequestOperation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a488de5dcd6f4c448a47c4b574d5c9bc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/DefaultBuildinFileSystem.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/DefaultBuildinFileSystem.cs index c6ea39aa..90ec6c8e 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/DefaultBuildinFileSystem.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/DefaultBuildinFileSystem.cs @@ -25,6 +25,11 @@ namespace YooAsset protected IFileSystem _unpackFileSystem; protected string _packageRoot; + /// + /// 下载后台接口 + /// + public IDownloadBackend DownloadBackend { private set; get; } + /// /// 包裹名称 /// @@ -66,7 +71,7 @@ namespace YooAsset /// /// 自定义参数:初始化的时候缓存文件校验最大并发数 /// - public int FileVerifyMaxConcurrency { private set; get; } = int.MaxValue; + public int FileVerifyMaxConcurrency { private set; get; } = 32; /// /// 自定义参数:数据文件追加文件格式 @@ -156,6 +161,13 @@ namespace YooAsset var operation = new DBFSLoadRawBundleOperation(this, bundle); return operation; } +#if TUANJIE_1_7_OR_NEWER + else if (bundle.BundleType == (int)EBuildBundleType.InstantBundle) + { + var operation = new DBFSLoadInstantBundleOperation(this, bundle); + return operation; + } +#endif else { string error = $"{nameof(DefaultBuildinFileSystem)} not support load bundle type : {bundle.BundleType}"; @@ -225,6 +237,10 @@ namespace YooAsset else _packageRoot = packageRoot; + // 创建默认的下载后台接口 + if (DownloadBackend == null) + DownloadBackend = new UnityWebRequestBackend(DownloadSystemHelper.UnityWebRequestCreater); + // 创建解压文件系统 var remoteServices = new DefaultUnpackRemoteServices(_packageRoot); _unpackFileSystem = new DefaultUnpackFileSystem(); diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/DBFSInitializeOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/DBFSInitializeOperation.cs index 657b7b6d..efbedff9 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/DBFSInitializeOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/DBFSInitializeOperation.cs @@ -78,7 +78,7 @@ namespace YooAsset string packageVersion = _requestBuildinPackageVersionOp.PackageVersion; string destFilePath = GetCopyPackageHashDestPath(packageVersion); string sourceFilePath = _fileSystem.GetBuildinPackageHashFilePath(packageVersion); - _copyBuildinHashFileOp = new CopyBuildinFileOperation(sourceFilePath, destFilePath); + _copyBuildinHashFileOp = new CopyBuildinFileOperation(_fileSystem, sourceFilePath, destFilePath); _copyBuildinHashFileOp.StartOperation(); AddChildOperation(_copyBuildinHashFileOp); } @@ -106,7 +106,7 @@ namespace YooAsset string packageVersion = _requestBuildinPackageVersionOp.PackageVersion; string destFilePath = GetCopyPackageManifestDestPath(packageVersion); string sourceFilePath = _fileSystem.GetBuildinPackageManifestFilePath(packageVersion); - _copyBuildinManifestFileOp = new CopyBuildinFileOperation(sourceFilePath, destFilePath); + _copyBuildinManifestFileOp = new CopyBuildinFileOperation(_fileSystem, sourceFilePath, destFilePath); _copyBuildinManifestFileOp.StartOperation(); AddChildOperation(_copyBuildinManifestFileOp); } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/CopyBuildinFileOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/CopyBuildinFileOperation.cs index 462aec69..7f0b8c9a 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/CopyBuildinFileOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/CopyBuildinFileOperation.cs @@ -14,13 +14,15 @@ namespace YooAsset Done, } - private UnityWebFileRequestOperation _webFileRequestOp; + private readonly DefaultBuildinFileSystem _fileSystem; private readonly string _sourceFilePath; private readonly string _destFilePath; + private IDownloadFileRequest _webFileRequestOp; private ESteps _steps = ESteps.None; - public CopyBuildinFileOperation(string sourceFilePath, string destFilePath) + public CopyBuildinFileOperation(DefaultBuildinFileSystem fileSystem, string sourceFilePath, string destFilePath) { + _fileSystem = fileSystem; _sourceFilePath = sourceFilePath; _destFilePath = destFilePath; } @@ -76,16 +78,15 @@ namespace YooAsset if (_webFileRequestOp == null) { string url = DownloadSystemHelper.ConvertToWWWPath(_sourceFilePath); - _webFileRequestOp = new UnityWebFileRequestOperation(url, _destFilePath, 60); - _webFileRequestOp.StartOperation(); - AddChildOperation(_webFileRequestOp); + var args = new DownloadFileRequestArgs(url, _destFilePath, 60, 0); + _webFileRequestOp = _fileSystem.DownloadBackend.CreateFileRequest(args); + _webFileRequestOp.SendRequest(); } - _webFileRequestOp.UpdateOperation(); if (_webFileRequestOp.IsDone == false) return; - if (_webFileRequestOp.Status == EOperationStatus.Succeed) + if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/LoadBuildinCatalogFileOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/LoadBuildinCatalogFileOperation.cs index 408ab143..22702aa4 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/LoadBuildinCatalogFileOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/LoadBuildinCatalogFileOperation.cs @@ -15,7 +15,7 @@ namespace YooAsset } private readonly DefaultBuildinFileSystem _fileSystem; - private UnityWebDataRequestOperation _webDataRequestOp; + private IDownloadBytesRequest _webDataRequestOp; private byte[] _fileData; private ESteps _steps = ESteps.None; @@ -57,16 +57,15 @@ namespace YooAsset { string filePath = _fileSystem.GetCatalogBinaryFileLoadPath(); string url = DownloadSystemHelper.ConvertToWWWPath(filePath); - _webDataRequestOp = new UnityWebDataRequestOperation(url, 60); - _webDataRequestOp.StartOperation(); - AddChildOperation(_webDataRequestOp); + var args = new DownloadDataRequestArgs(url, 60, 0); + _webDataRequestOp = _fileSystem.DownloadBackend.CreateBytesRequest(args); + _webDataRequestOp.SendRequest(); } - _webDataRequestOp.UpdateOperation(); if (_webDataRequestOp.IsDone == false) return; - if (_webDataRequestOp.Status == EOperationStatus.Succeed) + if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed) { _fileData = _webDataRequestOp.Result; _steps = ESteps.LoadCatalog; diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/LoadBuildinPackageManifestOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/LoadBuildinPackageManifestOperation.cs index 76b912bb..2e28c6e5 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/LoadBuildinPackageManifestOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/LoadBuildinPackageManifestOperation.cs @@ -17,7 +17,7 @@ namespace YooAsset private readonly DefaultBuildinFileSystem _fileSystem; private readonly string _packageVersion; private readonly string _packageHash; - private UnityWebDataRequestOperation _webDataRequestOp; + private IDownloadBytesRequest _webDataRequestOp; private DeserializeManifestOperation _deserializer; private byte[] _fileData; private ESteps _steps = ESteps.None; @@ -63,16 +63,15 @@ namespace YooAsset { string filePath = _fileSystem.GetBuildinPackageManifestFilePath(_packageVersion); string url = DownloadSystemHelper.ConvertToWWWPath(filePath); - _webDataRequestOp = new UnityWebDataRequestOperation(url, 60); - _webDataRequestOp.StartOperation(); - AddChildOperation(_webDataRequestOp); + var args = new DownloadDataRequestArgs(url, 60, 0); + _webDataRequestOp = _fileSystem.DownloadBackend.CreateBytesRequest(args); + _webDataRequestOp.SendRequest(); } - _webDataRequestOp.UpdateOperation(); if (_webDataRequestOp.IsDone == false) return; - if (_webDataRequestOp.Status == EOperationStatus.Succeed) + if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed) { _fileData = _webDataRequestOp.Result; _steps = ESteps.VerifyFileData; diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/RequestBuildinPackageHashOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/RequestBuildinPackageHashOperation.cs index df4a156a..f4ec7f0a 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/RequestBuildinPackageHashOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/RequestBuildinPackageHashOperation.cs @@ -15,7 +15,7 @@ namespace YooAsset private readonly DefaultBuildinFileSystem _fileSystem; private readonly string _packageVersion; - private UnityWebTextRequestOperation _webTextRequestOp; + private IDownloadTextRequest _webTextRequestOp; private ESteps _steps = ESteps.None; /// @@ -58,16 +58,15 @@ namespace YooAsset { string filePath = _fileSystem.GetBuildinPackageHashFilePath(_packageVersion); string url = DownloadSystemHelper.ConvertToWWWPath(filePath); - _webTextRequestOp = new UnityWebTextRequestOperation(url, 60); - _webTextRequestOp.StartOperation(); - AddChildOperation(_webTextRequestOp); + var args = new DownloadDataRequestArgs(url, 60, 0); + _webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args); + _webTextRequestOp.SendRequest(); } - _webTextRequestOp.UpdateOperation(); if (_webTextRequestOp.IsDone == false) return; - if (_webTextRequestOp.Status == EOperationStatus.Succeed) + if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed) { PackageHash = _webTextRequestOp.Result; _steps = ESteps.CheckResult; diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/RequestBuildinPackageVersionOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/RequestBuildinPackageVersionOperation.cs index d93e2ea2..6e07d9ab 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/RequestBuildinPackageVersionOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultBuildinFileSystem/Operation/internal/RequestBuildinPackageVersionOperation.cs @@ -14,7 +14,7 @@ namespace YooAsset } private readonly DefaultBuildinFileSystem _fileSystem; - private UnityWebTextRequestOperation _webTextRequestOp; + private IDownloadTextRequest _webTextRequestOp; private ESteps _steps = ESteps.None; /// @@ -56,16 +56,15 @@ namespace YooAsset { string filePath = _fileSystem.GetBuildinPackageVersionFilePath(); string url = DownloadSystemHelper.ConvertToWWWPath(filePath); - _webTextRequestOp = new UnityWebTextRequestOperation(url, 60); - _webTextRequestOp.StartOperation(); - AddChildOperation(_webTextRequestOp); + var args = new DownloadDataRequestArgs(url, 60, 0); + _webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args); + _webTextRequestOp.SendRequest(); } - _webTextRequestOp.UpdateOperation(); if (_webTextRequestOp.IsDone == false) return; - if (_webTextRequestOp.Status == EOperationStatus.Succeed) + if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed) { PackageVersion = _webTextRequestOp.Result; _steps = ESteps.CheckResult; diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/DefaultCacheFileSystem.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/DefaultCacheFileSystem.cs index 5bd2c6a7..98f976aa 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/DefaultCacheFileSystem.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/DefaultCacheFileSystem.cs @@ -23,10 +23,14 @@ namespace YooAsset protected string _cacheManifestFilesRoot; /// - /// 下载中心 - /// 说明:当异步操作任务终止的时候,所有下载子任务都会一同被终止! + /// 下载调度器 /// - public DownloadCenterOperation DownloadCenter { set; get; } + public DownloadSchedulerOperation DownloadScheduler { set; get; } + + /// + /// 下载后台接口 + /// + public IDownloadBackend DownloadBackend { private set; get; } /// /// 包裹名称 @@ -105,7 +109,7 @@ namespace YooAsset /// /// 自定义参数:下载任务的看门狗机制监控时间 /// - public int DownloadWatchDogTime { private set; get; } = int.MaxValue; + public int DownloadWatchDogTime { private set; get; } = 0; /// /// 自定义参数:启用断点续传的最小尺寸 @@ -288,7 +292,7 @@ namespace YooAsset else if (name == FileSystemParametersDefine.DOWNLOAD_WATCH_DOG_TIME) { int convertValue = Convert.ToInt32(value); - DownloadWatchDogTime = Mathf.Clamp(convertValue, 1, int.MaxValue); + DownloadWatchDogTime = Mathf.Clamp(convertValue, 0, int.MaxValue); } else if (name == FileSystemParametersDefine.RESUME_DOWNLOAD_MINMUM_SIZE) { @@ -327,13 +331,17 @@ namespace YooAsset _cacheBundleFilesRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.BundleFilesFolderName); _cacheManifestFilesRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.ManifestFilesFolderName); _tempFilesRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.TempFilesFolderName); + + // 创建默认的下载后台接口 + if (DownloadBackend == null) + DownloadBackend = new UnityWebRequestBackend(DownloadSystemHelper.UnityWebRequestCreater); } public virtual void OnDestroy() { - if (DownloadCenter != null) + if (DownloadScheduler != null) { - DownloadCenter.AbortOperation(); - DownloadCenter = null; + DownloadScheduler.Dispose(); + DownloadScheduler = null; } } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/DCFSInitializeOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/DCFSInitializeOperation.cs index 1d1fbc0a..7ec366b7 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/DCFSInitializeOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/DCFSInitializeOperation.cs @@ -9,7 +9,7 @@ namespace YooAsset CheckAppFootPrint, SearchCacheFiles, VerifyCacheFiles, - CreateDownloadCenter, + CreateDownloadScheduler, Done, } @@ -110,7 +110,7 @@ namespace YooAsset if (_verifyCacheFilesOp.Status == EOperationStatus.Succeed) { - _steps = ESteps.CreateDownloadCenter; + _steps = ESteps.CreateDownloadScheduler; YooLogger.Log($"Package '{_fileSystem.PackageName}' '{_fileSystem.GetType().Name}' cached files count : {_fileSystem.FileCount}"); } else @@ -121,13 +121,13 @@ namespace YooAsset } } - if (_steps == ESteps.CreateDownloadCenter) + if (_steps == ESteps.CreateDownloadScheduler) { // 注意:下载中心作为独立任务运行! - if (_fileSystem.DownloadCenter == null) + if (_fileSystem.DownloadScheduler == null) { - _fileSystem.DownloadCenter = new DownloadCenterOperation(_fileSystem); - OperationSystem.StartOperation(_fileSystem.PackageName, _fileSystem.DownloadCenter); + _fileSystem.DownloadScheduler = new DownloadSchedulerOperation(_fileSystem); + OperationSystem.StartOperation(_fileSystem.PackageName, _fileSystem.DownloadScheduler); } _steps = ESteps.Done; diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadCenterOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadCenterOperation.cs deleted file mode 100644 index d453901f..00000000 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadCenterOperation.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace YooAsset -{ - internal class DownloadCenterOperation : AsyncOperationBase - { - private readonly DefaultCacheFileSystem _fileSystem; - protected readonly Dictionary _downloaders = new Dictionary(1000); - protected readonly List _removeList = new List(1000); - - public DownloadCenterOperation(DefaultCacheFileSystem fileSystem) - { - _fileSystem = fileSystem; - } - internal override void InternalStart() - { - } - internal override void InternalUpdate() - { - // 获取可移除的下载器集合 - _removeList.Clear(); - foreach (var valuePair in _downloaders) - { - var downloader = valuePair.Value; - downloader.UpdateOperation(); - if (downloader.IsDone) - { - _removeList.Add(valuePair.Key); - continue; - } - - // 注意:主动终止引用计数为零的下载任务 - if (downloader.RefCount <= 0) - { - _removeList.Add(valuePair.Key); - downloader.AbortOperation(); - continue; - } - } - - // 移除下载器 - foreach (var key in _removeList) - { - if (_downloaders.TryGetValue(key, out var downloader)) - { - Childs.Remove(downloader); - _downloaders.Remove(key); - } - } - - // 最大并发数检测 - int processCount = GetProcessingOperationCount(); - if (processCount != _downloaders.Count) - { - if (processCount < _fileSystem.DownloadMaxConcurrency) - { - int startCount = _fileSystem.DownloadMaxConcurrency - processCount; - if (startCount > _fileSystem.DownloadMaxRequestPerFrame) - startCount = _fileSystem.DownloadMaxRequestPerFrame; - - foreach (var operationPair in _downloaders) - { - var operation = operationPair.Value; - if (operation.Status == EOperationStatus.None) - { - operation.StartOperation(); - startCount--; - if (startCount <= 0) - break; - } - } - } - } - } - - /// - /// 创建下载任务 - /// - public UnityDownloadFileOperation DownloadFileAsync(PackageBundle bundle, string url) - { - // 查询旧的下载器 - if (_downloaders.TryGetValue(bundle.BundleGUID, out var oldDownloader)) - { - oldDownloader.Reference(); - return oldDownloader; - } - - // 创建新的下载器 - UnityDownloadFileOperation newDownloader; - bool isRequestLocalFile = DownloadSystemHelper.IsRequestLocalFile(url); - if (isRequestLocalFile) - { - newDownloader = new UnityDownloadLocalFileOperation(_fileSystem, bundle, url); - AddChildOperation(newDownloader); - _downloaders.Add(bundle.BundleGUID, newDownloader); - } - else - { - if (bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize) - { - newDownloader = new UnityDownloadResumeFileOperation(_fileSystem, bundle, url); - AddChildOperation(newDownloader); - _downloaders.Add(bundle.BundleGUID, newDownloader); - } - else - { - newDownloader = new UnityDownloadNormalFileOperation(_fileSystem, bundle, url); - AddChildOperation(newDownloader); - _downloaders.Add(bundle.BundleGUID, newDownloader); - } - } - - newDownloader.Reference(); - return newDownloader; - } - - /// - /// 获取正在进行中的下载器总数 - /// - private int GetProcessingOperationCount() - { - int count = 0; - foreach (var operationPair in _downloaders) - { - var operation = operationPair.Value; - if (operation.Status != EOperationStatus.None) - count++; - } - return count; - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadCenterOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadCenterOperation.cs.meta deleted file mode 100644 index a7e85c28..00000000 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadCenterOperation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 768ef2df3433df245a26fec28d022e45 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageBundleOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageBundleOperation.cs index bacb2bb6..3f47bc22 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageBundleOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageBundleOperation.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using System.IO; +using UnityEngine; namespace YooAsset { @@ -17,7 +18,7 @@ namespace YooAsset // 下载参数 protected readonly DefaultCacheFileSystem _fileSystem; protected readonly DownloadFileOptions _options; - private UnityDownloadFileOperation _unityDownloadFileOp; + private DownloadAndCacheFileOperation _downloadFileOp; protected int _requestCount = 0; protected float _tryAgainTimer = 0; @@ -67,7 +68,7 @@ namespace YooAsset } string url = GetRequestURL(); - _unityDownloadFileOp = _fileSystem.DownloadCenter.DownloadFileAsync(Bundle, url); + _downloadFileOp = _fileSystem.DownloadScheduler.DownloadAndCacheFileAsync(Bundle, url); _steps = ESteps.CheckRequest; } @@ -75,20 +76,16 @@ namespace YooAsset if (_steps == ESteps.CheckRequest) { if (IsWaitForAsyncComplete) - _unityDownloadFileOp.WaitForAsyncComplete(); + _downloadFileOp.WaitForAsyncComplete(); - // 因为并发数量限制,下载器可能被挂起! - if (_unityDownloadFileOp.Status == EOperationStatus.None) + _downloadFileOp.UpdateOperation(); + Progress = _downloadFileOp.Progress; + DownloadedBytes = _downloadFileOp.DownloadedBytes; + DownloadProgress = _downloadFileOp.DownloadProgress; + if (_downloadFileOp.IsDone == false) return; - _unityDownloadFileOp.UpdateOperation(); - Progress = _unityDownloadFileOp.Progress; - DownloadedBytes = _unityDownloadFileOp.DownloadedBytes; - DownloadProgress = _unityDownloadFileOp.DownloadProgress; - if (_unityDownloadFileOp.IsDone == false) - return; - - if (_unityDownloadFileOp.Status == EOperationStatus.Succeed) + if (_downloadFileOp.Status == EOperationStatus.Succeed) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; @@ -98,13 +95,13 @@ namespace YooAsset if (IsWaitForAsyncComplete == false && _failedTryAgain > 0) { _steps = ESteps.TryAgain; - YooLogger.Warning($"Failed download : {_unityDownloadFileOp.URL} Try again !"); + YooLogger.Warning($"Failed download : {_downloadFileOp.URL} Try again !"); } else { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = _unityDownloadFileOp.Error; + Error = _downloadFileOp.Error; YooLogger.Error(Error); } } @@ -141,9 +138,9 @@ namespace YooAsset // 注意:取消下载任务的时候引用计数减一 if (_steps != ESteps.Done) { - if (_unityDownloadFileOp != null) + if (_downloadFileOp != null) { - _unityDownloadFileOp.Release(); + _downloadFileOp.Release(); } } } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageHashOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageHashOperation.cs index 0189e95a..0f860796 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageHashOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageHashOperation.cs @@ -15,7 +15,7 @@ namespace YooAsset private readonly DefaultCacheFileSystem _fileSystem; private readonly string _packageVersion; private readonly int _timeout; - private UnityWebFileRequestOperation _webFileRequestOp; + private IDownloadFileRequest _webFileRequestOp; private int _requestCount = 0; private ESteps _steps = ESteps.None; @@ -57,16 +57,16 @@ namespace YooAsset string savePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion); string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, _packageVersion); string webURL = GetWebRequestURL(fileName); - _webFileRequestOp = new UnityWebFileRequestOperation(webURL, savePath, _timeout); - _webFileRequestOp.StartOperation(); - AddChildOperation(_webFileRequestOp); + int watchdogTime = _fileSystem.DownloadWatchDogTime; + var args = new DownloadFileRequestArgs(webURL, savePath, _timeout, watchdogTime); + _webFileRequestOp = _fileSystem.DownloadBackend.CreateFileRequest(args); + _webFileRequestOp.SendRequest(); } - _webFileRequestOp.UpdateOperation(); if (_webFileRequestOp.IsDone == false) return; - if (_webFileRequestOp.Status == EOperationStatus.Succeed) + if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageManifestOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageManifestOperation.cs index f4805f97..8ee423ec 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageManifestOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/DownloadPackageManifestOperation.cs @@ -15,7 +15,7 @@ namespace YooAsset private readonly DefaultCacheFileSystem _fileSystem; private readonly string _packageVersion; private readonly int _timeout; - private UnityWebFileRequestOperation _webFileRequestOp; + private IDownloadFileRequest _webFileRequestOp; private int _requestCount = 0; private ESteps _steps = ESteps.None; @@ -57,16 +57,16 @@ namespace YooAsset string savePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion); string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, _packageVersion); string webURL = GetDownloadRequestURL(fileName); - _webFileRequestOp = new UnityWebFileRequestOperation(webURL, savePath, _timeout); - _webFileRequestOp.StartOperation(); - AddChildOperation(_webFileRequestOp); + int watchdogTime = _fileSystem.DownloadWatchDogTime; + var args = new DownloadFileRequestArgs(webURL, savePath, _timeout, watchdogTime); + _webFileRequestOp = _fileSystem.DownloadBackend.CreateFileRequest(args); + _webFileRequestOp.SendRequest(); } - _webFileRequestOp.UpdateOperation(); if (_webFileRequestOp.IsDone == false) return; - if (_webFileRequestOp.Status == EOperationStatus.Succeed) + if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/RequestRemotePackageVersionOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/RequestRemotePackageVersionOperation.cs index 1c8e4df7..2dd49826 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/RequestRemotePackageVersionOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/RequestRemotePackageVersionOperation.cs @@ -13,7 +13,7 @@ namespace YooAsset private readonly DefaultCacheFileSystem _fileSystem; private readonly bool _appendTimeTicks; private readonly int _timeout; - private UnityWebTextRequestOperation _webTextRequestOp; + private IDownloadTextRequest _webTextRequestOp; private int _requestCount = 0; private ESteps _steps = ESteps.None; @@ -45,17 +45,17 @@ namespace YooAsset { string fileName = YooAssetSettingsData.GetPackageVersionFileName(_fileSystem.PackageName); string url = GetWebRequestURL(fileName); - _webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout); - _webTextRequestOp.StartOperation(); - AddChildOperation(_webTextRequestOp); + int watchDogTime = _fileSystem.DownloadWatchDogTime; + var args = new DownloadDataRequestArgs(url, _timeout, watchDogTime); + _webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args); + _webTextRequestOp.SendRequest(); } - _webTextRequestOp.UpdateOperation(); - Progress = _webTextRequestOp.Progress; + Progress = _webTextRequestOp.DownloadProgress; if (_webTextRequestOp.IsDone == false) return; - if (_webTextRequestOp.Status == EOperationStatus.Succeed) + if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed) { PackageVersion = _webTextRequestOp.Result; if (string.IsNullOrEmpty(PackageVersion)) diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler.meta new file mode 100644 index 00000000..82ba251e --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf9991076b60f0f459846f54b0ca6698 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheFileOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheFileOperation.cs new file mode 100644 index 00000000..830915ca --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheFileOperation.cs @@ -0,0 +1,51 @@ + +namespace YooAsset +{ + internal abstract class DownloadAndCacheFileOperation : AsyncOperationBase + { + /// + /// 引用计数 + /// + public int RefCount { private set; get; } + + /// + /// 下载地址 + /// + public readonly string URL; + + /// + /// 下载进度 + /// + public float DownloadProgress { get; protected set; } + + /// + /// 下载字节 + /// + public long DownloadedBytes { get; protected set; } + + public DownloadAndCacheFileOperation(string url) + { + URL = url; + } + internal override string InternalGetDesc() + { + return $"RefCount : {RefCount}"; + } + + /// + /// 减少引用计数 + /// + public void Release() + { + RefCount--; + } + + /// + /// 增加引用计数 + /// + public void Reference() + { + RefCount++; + } + } +} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheFileOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheFileOperation.cs.meta new file mode 100644 index 00000000..4a7f4826 --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheFileOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2954a64fd419d5a4b9d0a102260d193c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadLocalFileOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheLocalFileOperation.cs similarity index 52% rename from Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadLocalFileOperation.cs rename to Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheLocalFileOperation.cs index b3961ec7..42555066 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadLocalFileOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheLocalFileOperation.cs @@ -1,94 +1,79 @@ using System.IO; -using UnityEngine; -using UnityEngine.Networking; namespace YooAsset { - internal sealed class UnityDownloadLocalFileOperation : UnityDownloadFileOperation + internal sealed class DownloadAndCacheLocalFileOperation : DownloadAndCacheFileOperation { + private enum ESteps + { + None, + CheckCopy, + CopyLocalFile, + CreateRequest, + CheckRequest, + VerifyBundleFile, + CacheBundleFile, + Done, + } + + private readonly DefaultCacheFileSystem _fileSystem; + private readonly PackageBundle _bundle; + private readonly string _tempFilePath; + private IDownloadRequest _request; private VerifyTempFileOperation _verifyOperation; private ESteps _steps = ESteps.None; - internal UnityDownloadLocalFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url) - : base(fileSystem, bundle, url) + internal DownloadAndCacheLocalFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url) : base(url) { + _fileSystem = fileSystem; + _bundle = bundle; + _tempFilePath = _fileSystem.GetTempFilePath(_bundle); } internal override void InternalStart() { - if (_fileSystem.CopyLocalFileServices != null) - _steps = ESteps.CopyLocalFile; - else - _steps = ESteps.CreateRequest; + _steps = ESteps.CheckCopy; } internal override void InternalUpdate() { if (_steps == ESteps.None || _steps == ESteps.Done) return; - // 创建下载器 - if (_steps == ESteps.CreateRequest) + // 检测文件拷贝 + if (_steps == ESteps.CheckCopy) { + // 删除历史缓存文件 FileUtility.CreateFileDirectory(_tempFilePath); if (File.Exists(_tempFilePath)) File.Delete(_tempFilePath); - CreateWebRequest(); - _steps = ESteps.Download; - } - - // 检测下载结果 - if (_steps == ESteps.Download) - { - DownloadProgress = _webRequest.downloadProgress; - DownloadedBytes = (long)_webRequest.downloadedBytes; - Progress = DownloadProgress; - - UpdateWatchDog(); - if (_webRequest.isDone == false) - return; - - // 检查网络错误 - if (CheckRequestResult()) - { - _steps = ESteps.VerifyFile; - } + if (_fileSystem.CopyLocalFileServices != null) + _steps = ESteps.CopyLocalFile; else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - } - - // 注意:最终释放请求器 - DisposeRequest(); + _steps = ESteps.CreateRequest; } - // 拷贝内置文件 + // 拷贝本地文件 if (_steps == ESteps.CopyLocalFile) { - FileUtility.CreateFileDirectory(_tempFilePath); - if (File.Exists(_tempFilePath)) - File.Delete(_tempFilePath); - try { //TODO 团结引擎,在某些机型(红米),拷贝包内文件会小概率失败!需要借助其它方式来拷贝包内文件。 var localFileInfo = new LocalFileInfo(); localFileInfo.PackageName = _fileSystem.PackageName; localFileInfo.BundleName = _bundle.BundleName; - localFileInfo.SourceFileURL = _requestURL; + localFileInfo.SourceFileURL = URL; _fileSystem.CopyLocalFileServices.CopyFile(localFileInfo, _tempFilePath); if (File.Exists(_tempFilePath)) { DownloadProgress = 1f; DownloadedBytes = _bundle.FileSize; - Progress = DownloadProgress; - _steps = ESteps.VerifyFile; + _steps = ESteps.VerifyBundleFile; } else { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = $"Failed copy local file : {_requestURL}"; + Error = $"Failed copy local file : {URL}"; } } catch (System.Exception ex) @@ -99,8 +84,44 @@ namespace YooAsset } } - // 验证下载文件 - if (_steps == ESteps.VerifyFile) + // 创建下载请求 + if (_steps == ESteps.CreateRequest) + { + int watchdogTime = _fileSystem.DownloadWatchDogTime; + int timeout = 0; //注意:文件下载不做超时检测 + var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime); + _request = _fileSystem.DownloadBackend.CreateFileRequest(args); + _request.SendRequest(); + _steps = ESteps.CheckRequest; + } + + // 检测下载结果 + if (_steps == ESteps.CheckRequest) + { + DownloadProgress = _request.DownloadProgress; + DownloadedBytes = _request.DownloadedBytes; + Progress = DownloadProgress; + if (_request.IsDone == false) + return; + + // 检查网络错误 + if (_request.Status == EDownloadRequestStatus.Succeed) + { + _steps = ESteps.VerifyBundleFile; + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = _request.Error; + } + + // 最终释放请求器 + _request.Dispose(); + } + + // 验证下载结果 + if (_steps == ESteps.VerifyBundleFile) { if (_verifyOperation == null) { @@ -119,35 +140,51 @@ namespace YooAsset if (_verifyOperation.Status == EOperationStatus.Succeed) { - if (_fileSystem.WriteCacheBundleFile(_bundle, _tempFilePath)) - { - _steps = ESteps.Done; - Status = EOperationStatus.Succeed; - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = $"{_fileSystem.GetType().FullName} failed to write file !"; - } + _steps = ESteps.CacheBundleFile; } else { _steps = ESteps.Done; Status = EOperationStatus.Failed; Error = _verifyOperation.Error; + + // 注意:验证失败后直接删除文件 + if (File.Exists(_tempFilePath)) + File.Delete(_tempFilePath); + } + } + + // 缓存文件 + if (_steps == ESteps.CacheBundleFile) + { + if (_fileSystem.WriteCacheBundleFile(_bundle, _tempFilePath)) + { + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = $"{_fileSystem.GetType().FullName} failed to write file !"; } - // 注意:验证完成后直接删除文件 + // 注意:缓存完成后直接删除临时文件 if (File.Exists(_tempFilePath)) File.Delete(_tempFilePath); } } + internal override void InternalAbort() + { + if (_request != null) + _request.AbortRequest(); + } internal override void InternalWaitForAsyncComplete() { while (true) { //TODO 等待导入或解压本地文件完毕,该操作会挂起主线程! + _fileSystem.DownloadBackend.Update(); InternalUpdate(); if (IsDone) break; @@ -156,15 +193,5 @@ namespace YooAsset System.Threading.Thread.Sleep(1); } } - - private void CreateWebRequest() - { - DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath); - handler.removeFileOnAbort = true; - _webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL); - _webRequest.downloadHandler = handler; - _webRequest.disposeDownloadHandlerOnDispose = true; - _webRequest.SendWebRequest(); - } } } \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheLocalFileOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheLocalFileOperation.cs.meta new file mode 100644 index 00000000..0ed77cb1 --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheLocalFileOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 47700ac672942834f8d5a7c59783d88e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheRemoteFileOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheRemoteFileOperation.cs new file mode 100644 index 00000000..563c0578 --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheRemoteFileOperation.cs @@ -0,0 +1,206 @@ +using System.IO; + +namespace YooAsset +{ + internal sealed class DownloadAndCacheRemoteFileOperation : DownloadAndCacheFileOperation + { + private enum ESteps + { + None, + CreateRequest, + CheckRequest, + VerifyBundleFile, + CacheBundleFile, + Done, + } + + private readonly DefaultCacheFileSystem _fileSystem; + private readonly PackageBundle _bundle; + private readonly string _tempFilePath; + private bool _enableResume = false; + private long _fileOriginLength = 0; + private IDownloadRequest _request; + private VerifyTempFileOperation _verifyOperation; + private ESteps _steps = ESteps.None; + + internal DownloadAndCacheRemoteFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url) : base(url) + { + _fileSystem = fileSystem; + _bundle = bundle; + _tempFilePath = _fileSystem.GetTempFilePath(_bundle); + } + internal override void InternalStart() + { + _steps = ESteps.CreateRequest; + } + internal override void InternalUpdate() + { + if (_steps == ESteps.None || _steps == ESteps.Done) + return; + + // 创建下载请求 + if (_steps == ESteps.CreateRequest) + { + FileUtility.CreateFileDirectory(_tempFilePath); + + _enableResume = _bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize; + if (_enableResume) + { + _request = CreateResumeRequest(); + _request.SendRequest(); + _steps = ESteps.CheckRequest; + } + else + { + _request = CreateNormalRequest(); + _request.SendRequest(); + _steps = ESteps.CheckRequest; + } + } + + // 检测下载结果 + if (_steps == ESteps.CheckRequest) + { + DownloadProgress = _request.DownloadProgress; + DownloadedBytes = _fileOriginLength + _request.DownloadedBytes; + Progress = DownloadProgress; + if (_request.IsDone == false) + return; + + // 检查网络错误 + if (_request.Status == EDownloadRequestStatus.Succeed) + { + _steps = ESteps.VerifyBundleFile; + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = _request.Error; + } + + // 在遇到特殊错误的时候删除文件 + if (_enableResume) + ClearTempFileWhenError(_request.HttpCode); + + // 最终释放请求器 + _request.Dispose(); + } + + // 验证下载结果 + if (_steps == ESteps.VerifyBundleFile) + { + if (_verifyOperation == null) + { + var element = new TempFileElement(_tempFilePath, _bundle.FileCRC, _bundle.FileSize); + _verifyOperation = new VerifyTempFileOperation(element); + _verifyOperation.StartOperation(); + AddChildOperation(_verifyOperation); + } + + if (IsWaitForAsyncComplete) + _verifyOperation.WaitForAsyncComplete(); + + _verifyOperation.UpdateOperation(); + if (_verifyOperation.IsDone == false) + return; + + if (_verifyOperation.Status == EOperationStatus.Succeed) + { + _steps = ESteps.CacheBundleFile; + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = _verifyOperation.Error; + + // 注意:验证失败后直接删除文件 + if (File.Exists(_tempFilePath)) + File.Delete(_tempFilePath); + } + } + + // 缓存文件 + if (_steps == ESteps.CacheBundleFile) + { + if (_fileSystem.WriteCacheBundleFile(_bundle, _tempFilePath)) + { + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = $"{_fileSystem.GetType().FullName} failed to write file !"; + } + + // 注意:缓存完成后直接删除临时文件 + if (File.Exists(_tempFilePath)) + File.Delete(_tempFilePath); + } + } + internal override void InternalAbort() + { + if (_request != null) + _request.AbortRequest(); + } + internal override void InternalWaitForAsyncComplete() + { + if (_steps != ESteps.Done) + { + // 注意:不中断下载任务,保持后台继续下载 + YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote : {URL} !"); + } + } + + private IDownloadRequest CreateResumeRequest() + { + // 获取下载起始位置 + if (File.Exists(_tempFilePath)) + { + FileInfo fileInfo = new FileInfo(_tempFilePath); + if (fileInfo.Length >= _bundle.FileSize) + { + File.Delete(_tempFilePath); + } + else + { + _fileOriginLength = fileInfo.Length; + } + } + + int watchdogTime = _fileSystem.DownloadWatchDogTime; + int timeout = 0; //注意:文件下载不做超时检测 + bool appendToFile = true; + bool removeFileOnAbort = false; + long resumeFromBytes = _fileOriginLength; + var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime, appendToFile, removeFileOnAbort, resumeFromBytes); + return _fileSystem.DownloadBackend.CreateFileRequest(args); + } + private IDownloadRequest CreateNormalRequest() + { + // 删除历史缓存文件 + if (File.Exists(_tempFilePath)) + File.Delete(_tempFilePath); + + int watchdogTime = _fileSystem.DownloadWatchDogTime; + int timeout = 0; //注意:文件下载不做超时检测 + var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime); + return _fileSystem.DownloadBackend.CreateFileRequest(args); + } + private void ClearTempFileWhenError(long httpCode) + { + if (_fileSystem.ResumeDownloadResponseCodes == null) + return; + + //说明:如果遇到以下错误返回码,验证失败直接删除文件 + if (_fileSystem.ResumeDownloadResponseCodes.Contains(httpCode)) + { + if (File.Exists(_tempFilePath)) + File.Delete(_tempFilePath); + } + } + } +} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheRemoteFileOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheRemoteFileOperation.cs.meta new file mode 100644 index 00000000..5021f136 --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheRemoteFileOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad910a81855976e44b4f1f09051910b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadSchedulerOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadSchedulerOperation.cs new file mode 100644 index 00000000..943934e6 --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadSchedulerOperation.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; + +namespace YooAsset +{ + /// + /// 下载调度器 + /// + /// + /// 管理所有活跃的下载任务,控制并发数量。 + /// + internal class DownloadSchedulerOperation : AsyncOperationBase, IDisposable + { + private readonly DefaultCacheFileSystem _fileSystem; + private readonly Dictionary _downloaders = new Dictionary(1000); + private readonly List _removeList = new List(1000); + + /// + /// 是否已暂停 + /// + public bool Paused { get; private set; } = false; + + /// + /// 当前活跃的下载任务数 + /// + public int ActiveDownloadCount { get; private set; } + + /// + /// 当前等待中的下载任务数 + /// + public int PendingDownloadCount + { + get + { + return _downloaders.Count - ActiveDownloadCount; + } + } + + + /// + /// 构造下载中心 + /// + public DownloadSchedulerOperation(DefaultCacheFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + internal override void InternalStart() + { + } + internal override void InternalUpdate() + { + // 驱动下载后台 + _fileSystem.DownloadBackend.Update(); + + // 获取可移除的下载器集合 + _removeList.Clear(); + foreach (var valuePair in _downloaders) + { + var downloader = valuePair.Value; + downloader.UpdateOperation(); + if (downloader.IsDone) + { + _removeList.Add(valuePair.Key); + continue; + } + + // 注意:主动终止引用计数为零的下载任务 + if (downloader.RefCount <= 0) + { + _removeList.Add(valuePair.Key); + downloader.AbortOperation(); + continue; + } + } + + // 移除下载器 + foreach (var key in _removeList) + { + if (_downloaders.TryGetValue(key, out var downloader)) + { + RemoveChildOperation(downloader); + _downloaders.Remove(key); + } + } + + // 暂停时不启动新任务 + if (Paused) + return; + + // 最大并发数检测 + ActiveDownloadCount = GetProcessingOperationCount(); + if (ActiveDownloadCount != _downloaders.Count) + { + int maxConcurrency = _fileSystem.DownloadMaxConcurrency; + int maxRequestPerFrame = _fileSystem.DownloadMaxRequestPerFrame; + if (ActiveDownloadCount < maxConcurrency) + { + int startCount = maxConcurrency - ActiveDownloadCount; + if (startCount > maxRequestPerFrame) + startCount = maxRequestPerFrame; + + foreach (var operationPair in _downloaders) + { + var operation = operationPair.Value; + if (operation.Status == EOperationStatus.None) + { + operation.StartOperation(); + startCount--; + if (startCount <= 0) + break; + } + } + } + } + } + + /// + /// 中止所有下载任务 + /// + public void AbortAll() + { + foreach (var valuePair in _downloaders) + { + valuePair.Value.AbortOperation(); + } + _downloaders.Clear(); + } + + /// + /// 释放资源 + /// + public void Dispose() + { + AbortAll(); + } + + /// + /// 创建下载任务 + /// + /// 资源包信息 + /// 下载地址 + /// 下载操作 + public DownloadAndCacheFileOperation DownloadAndCacheFileAsync(PackageBundle bundle, string url) + { + // 查询旧的下载器 + if (_downloaders.TryGetValue(bundle.BundleGUID, out var oldDownloader)) + { + oldDownloader.Reference(); + return oldDownloader; + } + + // 创建新的下载器 + DownloadAndCacheFileOperation newDownloader; + bool isRequestLocalFile = DownloadSystemHelper.IsRequestLocalFile(url); + if (isRequestLocalFile) + { + newDownloader = new DownloadAndCacheLocalFileOperation(_fileSystem, bundle, url); + } + else + { + newDownloader = new DownloadAndCacheRemoteFileOperation(_fileSystem, bundle, url); + } + + AddChildOperation(newDownloader); + _downloaders.Add(bundle.BundleGUID, newDownloader); + newDownloader.Reference(); + return newDownloader; + } + + /// + /// 获取正在进行中的下载器总数 + /// + private int GetProcessingOperationCount() + { + int count = 0; + foreach (var operationPair in _downloaders) + { + var operation = operationPair.Value; + if (operation.Status != EOperationStatus.None) + count++; + } + return count; + } + } +} diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadSchedulerOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadSchedulerOperation.cs.meta new file mode 100644 index 00000000..7c959f60 --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadSchedulerOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73441e829c36a36418f5d677e189e9f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadFileOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadFileOperation.cs deleted file mode 100644 index cb022017..00000000 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadFileOperation.cs +++ /dev/null @@ -1,98 +0,0 @@ - -namespace YooAsset -{ - internal abstract class UnityDownloadFileOperation : UnityWebRequestOperation - { - protected enum ESteps - { - None, - CreateRequest, - Download, - CopyLocalFile, - VerifyFile, - Done, - } - - protected readonly DefaultCacheFileSystem _fileSystem; - protected readonly PackageBundle _bundle; - protected readonly string _tempFilePath; - - private bool _watchDogInit = false; - private bool _watchDogAborted = false; - private ulong _lastDownloadBytes; - private double _lastGetDataTime; - - /// - /// 引用计数 - /// - public int RefCount { private set; get; } - - internal UnityDownloadFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url) : base(url) - { - _fileSystem = fileSystem; - _bundle = bundle; - _tempFilePath = _fileSystem.GetTempFilePath(bundle); - } - internal override string InternalGetDesc() - { - return $"RefCount : {RefCount}"; - } - - /// - /// 更新看门狗监测 - /// 说明:监控时间范围内,如果没有接收到任何下载数据,那么直接终止任务! - /// - protected void UpdateWatchDog() - { - if (_fileSystem.DownloadWatchDogTime == int.MaxValue) - return; - - if (_watchDogAborted) - return; - -#if UNITY_2020_3_OR_NEWER - double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartupAsDouble; -#else - double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartup; -#endif - - if (_watchDogInit == false) - { - _watchDogInit = true; - _lastDownloadBytes = 0; - _lastGetDataTime = realtimeSinceStartup; - } - - if (_webRequest.downloadedBytes != _lastDownloadBytes) - { - _lastDownloadBytes = _webRequest.downloadedBytes; - _lastGetDataTime = realtimeSinceStartup; - } - else - { - double deltaTime = realtimeSinceStartup - _lastGetDataTime; - if (deltaTime > _fileSystem.DownloadWatchDogTime) - { - _watchDogAborted = true; - InternalAbort(); //终止网络请求 - } - } - } - - /// - /// 减少引用计数 - /// - public void Release() - { - RefCount--; - } - - /// - /// 增加引用计数 - /// - public void Reference() - { - RefCount++; - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadFileOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadFileOperation.cs.meta deleted file mode 100644 index eec39b4e..00000000 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadFileOperation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 40bb5e9391f413c42ae70e48ca90c4b7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadLocalFileOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadLocalFileOperation.cs.meta deleted file mode 100644 index 6514b3aa..00000000 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadLocalFileOperation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c68640bb1d36552469024324e3357bc2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadNormalFileOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadNormalFileOperation.cs deleted file mode 100644 index d2ded35b..00000000 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadNormalFileOperation.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System.IO; -using UnityEngine; -using UnityEngine.Networking; - -namespace YooAsset -{ - internal sealed class UnityDownloadNormalFileOperation : UnityDownloadFileOperation - { - private VerifyTempFileOperation _verifyOperation; - private ESteps _steps = ESteps.None; - - internal UnityDownloadNormalFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url) - : base(fileSystem, bundle, url) - { - } - internal override void InternalStart() - { - _steps = ESteps.CreateRequest; - } - internal override void InternalUpdate() - { - if (_steps == ESteps.None || _steps == ESteps.Done) - return; - - // 创建下载器 - if (_steps == ESteps.CreateRequest) - { - FileUtility.CreateFileDirectory(_tempFilePath); - if (File.Exists(_tempFilePath)) - File.Delete(_tempFilePath); - - CreateWebRequest(); - _steps = ESteps.Download; - } - - // 检测下载结果 - if (_steps == ESteps.Download) - { - DownloadProgress = _webRequest.downloadProgress; - DownloadedBytes = (long)_webRequest.downloadedBytes; - Progress = DownloadProgress; - - UpdateWatchDog(); - if (_webRequest.isDone == false) - return; - - // 检查网络错误 - if (CheckRequestResult()) - { - _steps = ESteps.VerifyFile; - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - } - - // 注意:最终释放请求器 - DisposeRequest(); - } - - // 验证下载文件 - if (_steps == ESteps.VerifyFile) - { - if (_verifyOperation == null) - { - var element = new TempFileElement(_tempFilePath, _bundle.FileCRC, _bundle.FileSize); - _verifyOperation = new VerifyTempFileOperation(element); - _verifyOperation.StartOperation(); - AddChildOperation(_verifyOperation); - } - - if (IsWaitForAsyncComplete) - _verifyOperation.WaitForAsyncComplete(); - - _verifyOperation.UpdateOperation(); - if (_verifyOperation.IsDone == false) - return; - - if (_verifyOperation.Status == EOperationStatus.Succeed) - { - if (_fileSystem.WriteCacheBundleFile(_bundle, _tempFilePath)) - { - _steps = ESteps.Done; - Status = EOperationStatus.Succeed; - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = $"{_fileSystem.GetType().FullName} failed to write file ! {_tempFilePath}"; - } - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = _verifyOperation.Error; - } - - // 注意:验证完成后直接删除文件 - if (File.Exists(_tempFilePath)) - File.Delete(_tempFilePath); - } - } - internal override void InternalWaitForAsyncComplete() - { - if (_steps != ESteps.Done) - { - YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote : {_requestURL} !"); - } - } - - private void CreateWebRequest() - { - DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath); - handler.removeFileOnAbort = true; - _webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL); - _webRequest.downloadHandler = handler; - _webRequest.disposeDownloadHandlerOnDispose = true; - _webRequest.SendWebRequest(); - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadNormalFileOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadNormalFileOperation.cs.meta deleted file mode 100644 index 2ca0d680..00000000 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadNormalFileOperation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 759967d543776a0469b625eff171d235 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadResumeFileOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadResumeFileOperation.cs deleted file mode 100644 index 7a0cf47f..00000000 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadResumeFileOperation.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System.IO; -using UnityEngine; -using UnityEngine.Networking; - -namespace YooAsset -{ - internal sealed class UnityDownloadResumeFileOperation : UnityDownloadFileOperation - { - private VerifyTempFileOperation _verifyOperation; - private long _fileOriginLength = 0; - private ESteps _steps = ESteps.None; - - internal UnityDownloadResumeFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url) - : base(fileSystem, bundle, url) - { - } - internal override void InternalStart() - { - _steps = ESteps.CreateRequest; - } - internal override void InternalUpdate() - { - if (_steps == ESteps.None || _steps == ESteps.Done) - return; - - // 创建下载器 - if (_steps == ESteps.CreateRequest) - { - FileUtility.CreateFileDirectory(_tempFilePath); - - // 获取下载起始位置 - _fileOriginLength = 0; - long fileBeginLength = -1; - if (File.Exists(_tempFilePath)) - { - FileInfo fileInfo = new FileInfo(_tempFilePath); - if (fileInfo.Length >= _bundle.FileSize) - { - File.Delete(_tempFilePath); - } - else - { - fileBeginLength = fileInfo.Length; - _fileOriginLength = fileBeginLength; - DownloadedBytes = _fileOriginLength; - } - } - - CreateWebRequest(fileBeginLength); - _steps = ESteps.Download; - } - - // 检测下载结果 - if (_steps == ESteps.Download) - { - DownloadProgress = _webRequest.downloadProgress; - DownloadedBytes = _fileOriginLength + (long)_webRequest.downloadedBytes; - Progress = DownloadProgress; - - UpdateWatchDog(); - if (_webRequest.isDone == false) - return; - - // 检查网络错误 - if (CheckRequestResult()) - { - _steps = ESteps.VerifyFile; - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - } - - // 在遇到特殊错误的时候删除文件 - ClearTempFileWhenError(); - - // 注意:最终释放请求器 - DisposeRequest(); - } - - // 验证下载文件 - if (_steps == ESteps.VerifyFile) - { - if (_verifyOperation == null) - { - var element = new TempFileElement(_tempFilePath, _bundle.FileCRC, _bundle.FileSize); - _verifyOperation = new VerifyTempFileOperation(element); - _verifyOperation.StartOperation(); - AddChildOperation(_verifyOperation); - } - - if (IsWaitForAsyncComplete) - _verifyOperation.WaitForAsyncComplete(); - - _verifyOperation.UpdateOperation(); - if (_verifyOperation.IsDone == false) - return; - - if (_verifyOperation.Status == EOperationStatus.Succeed) - { - if (_fileSystem.WriteCacheBundleFile(_bundle, _tempFilePath)) - { - _steps = ESteps.Done; - Status = EOperationStatus.Succeed; - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = $"{_fileSystem.GetType().FullName} failed to write file !"; - } - } - else - { - _steps = ESteps.Done; - Status = EOperationStatus.Failed; - Error = _verifyOperation.Error; - } - - // 注意:验证完成后直接删除文件 - if (File.Exists(_tempFilePath)) - File.Delete(_tempFilePath); - } - } - internal override void InternalWaitForAsyncComplete() - { - if (_steps != ESteps.Done) - { - YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote : {_requestURL} !"); - } - } - - private void ClearTempFileWhenError() - { - if (_fileSystem.ResumeDownloadResponseCodes == null) - return; - - //说明:如果遇到以下错误返回码,验证失败直接删除文件 - if (_fileSystem.ResumeDownloadResponseCodes.Contains(HttpCode)) - { - if (File.Exists(_tempFilePath)) - File.Delete(_tempFilePath); - } - } - private void CreateWebRequest(long fileBeginLength) - { - var handler = new DownloadHandlerFile(_tempFilePath, true); - handler.removeFileOnAbort = false; - _webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL); - _webRequest.downloadHandler = handler; - _webRequest.disposeDownloadHandlerOnDispose = true; - if (fileBeginLength > 0) - _webRequest.SetRequestHeader("Range", $"bytes={fileBeginLength}-"); - _webRequest.SendWebRequest(); - } - } -} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadResumeFileOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadResumeFileOperation.cs.meta deleted file mode 100644 index d23cbe76..00000000 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/UnityDownloadResumeFileOperation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9bfb785912326f942a31dc77762eb16a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/DefaultEditorFileSystem.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/DefaultEditorFileSystem.cs index 1ef4009b..f975fce8 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/DefaultEditorFileSystem.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/DefaultEditorFileSystem.cs @@ -11,6 +11,11 @@ namespace YooAsset protected readonly Dictionary _records = new Dictionary(10000); protected string _packageRoot; + /// + /// 下载后台接口 + /// + public IDownloadBackend DownloadBackend { private set; get; } + /// /// 包裹名称 /// @@ -145,6 +150,10 @@ namespace YooAsset throw new YooFileSystemException($"{nameof(DefaultEditorFileSystem)} package root is null or empty !"); _packageRoot = packageRoot; + + // 创建默认的下载后台接口 + if (DownloadBackend == null) + DownloadBackend = new UnityWebRequestBackend(DownloadSystemHelper.UnityWebRequestCreater); } public virtual void OnDestroy() { diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs index 7c6b06a6..192185bb 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs @@ -17,7 +17,7 @@ namespace YooAsset // 下载参数 protected readonly DefaultEditorFileSystem _fileSystem; protected readonly DownloadFileOptions _options; - protected UnityVirtualBundleRequestOperation _unityDownloadFileOp; + protected IDownloadFileRequest _downloadFileOp; protected int _requestCount = 0; protected float _tryAgainTimer = 0; @@ -68,29 +68,22 @@ namespace YooAsset string url = GetRequestURL(); int speed = _fileSystem.VirtualDownloadSpeed; - _unityDownloadFileOp = new UnityVirtualBundleRequestOperation(Bundle, speed, url); - _unityDownloadFileOp.StartOperation(); + var args = new DownloadSimulateRequestArgs(url, Bundle.FileSize, speed); + _downloadFileOp = _fileSystem.DownloadBackend.CreateSimulateRequest(args); + _downloadFileOp.SendRequest(); _steps = ESteps.CheckRequest; } // 检测下载结果 if (_steps == ESteps.CheckRequest) { - if (IsWaitForAsyncComplete) - _unityDownloadFileOp.WaitForAsyncComplete(); - - // 因为并发数量限制,下载器可能被挂起! - if (_unityDownloadFileOp.Status == EOperationStatus.None) + Progress = _downloadFileOp.DownloadProgress; + DownloadedBytes = _downloadFileOp.DownloadedBytes; + DownloadProgress = _downloadFileOp.DownloadProgress; + if (_downloadFileOp.IsDone == false) return; - _unityDownloadFileOp.UpdateOperation(); - Progress = _unityDownloadFileOp.Progress; - DownloadedBytes = _unityDownloadFileOp.DownloadedBytes; - DownloadProgress = _unityDownloadFileOp.DownloadProgress; - if (_unityDownloadFileOp.IsDone == false) - return; - - if (_unityDownloadFileOp.Status == EOperationStatus.Succeed) + if (_downloadFileOp.Status == EDownloadRequestStatus.Succeed) { _fileSystem.RecordDownloadFile(Bundle); _steps = ESteps.Done; @@ -101,13 +94,13 @@ namespace YooAsset if (IsWaitForAsyncComplete == false && _failedTryAgain > 0) { _steps = ESteps.TryAgain; - YooLogger.Warning($"Failed download : {_unityDownloadFileOp.URL} Try again !"); + YooLogger.Warning($"Failed download : {_downloadFileOp.URL} Try again !"); } else { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = _unityDownloadFileOp.Error; + Error = _downloadFileOp.Error; YooLogger.Error(Error); } } @@ -130,13 +123,11 @@ namespace YooAsset } internal override void InternalWaitForAsyncComplete() { - while (true) + if (_steps != ESteps.Done) { - if (ExecuteWhileDone()) - { - _steps = ESteps.Done; - break; - } + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = $"Try load bundle {Bundle.BundleName} from remote !"; } } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/DefaultWebRemoteFileSystem.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/DefaultWebRemoteFileSystem.cs index ed0591c9..c7707d94 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/DefaultWebRemoteFileSystem.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/DefaultWebRemoteFileSystem.cs @@ -10,6 +10,11 @@ namespace YooAsset /// internal class DefaultWebRemoteFileSystem : IFileSystem { + /// + /// 下载后台接口 + /// + public IDownloadBackend DownloadBackend { private set; get; } + /// /// 包裹名称 /// @@ -128,6 +133,10 @@ namespace YooAsset public virtual void OnCreate(string packageName, string packageRoot) { PackageName = packageName; + + // 创建默认的下载后台接口 + if (DownloadBackend == null) + DownloadBackend = new UnityWebRequestBackend(DownloadSystemHelper.UnityWebRequestCreater); } public virtual void OnDestroy() { diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSLoadBundleOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSLoadBundleOperation.cs index 2c65f0e8..b16c1aad 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSLoadBundleOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSLoadBundleOperation.cs @@ -38,16 +38,16 @@ namespace YooAsset string fallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(_bundle.FileName); DownloadFileOptions options = new DownloadFileOptions(int.MaxValue); options.SetURL(mainURL, fallbackURL); - + if (_bundle.Encrypted) { - _loadWebAssetBundleOp = new LoadWebEncryptAssetBundleOperation(_bundle, options, _fileSystem.DecryptionServices); + _loadWebAssetBundleOp = new LoadWebEncryptAssetBundleOperation(_bundle, options, _fileSystem.DecryptionServices, _fileSystem.DownloadBackend); _loadWebAssetBundleOp.StartOperation(); AddChildOperation(_loadWebAssetBundleOp); } else { - _loadWebAssetBundleOp = new LoadWebNormalAssetBundleOperation(_bundle, options, _fileSystem.DisableUnityWebCache); + _loadWebAssetBundleOp = new LoadWebNormalAssetBundleOperation(_bundle, options, _fileSystem.DisableUnityWebCache, _fileSystem.DownloadBackend); _loadWebAssetBundleOp.StartOperation(); AddChildOperation(_loadWebAssetBundleOp); } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSLoadPackageManifestOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSLoadPackageManifestOperation.cs index b39610fa..c0c68ba4 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSLoadPackageManifestOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSLoadPackageManifestOperation.cs @@ -38,7 +38,7 @@ namespace YooAsset { if (_requestWebPackageHashOp == null) { - _requestWebPackageHashOp = new RequestWebPackageHashOperation(_fileSystem.RemoteServices, _fileSystem.PackageName, _packageVersion, _timeout); + _requestWebPackageHashOp = new RequestWebPackageHashOperation(_fileSystem.RemoteServices, _fileSystem.DownloadBackend, _fileSystem.PackageName, _packageVersion, _timeout); _requestWebPackageHashOp.StartOperation(); AddChildOperation(_requestWebPackageHashOp); } @@ -67,7 +67,8 @@ namespace YooAsset string packageName = _fileSystem.PackageName; var manifestServices = _fileSystem.ManifestServices; var remoteServices = _fileSystem.RemoteServices; - _loadWebPackageManifestOp = new LoadWebPackageManifestOperation(manifestServices, remoteServices, packageName, _packageVersion, packageHash, _timeout); + var downloadBackend = _fileSystem.DownloadBackend; + _loadWebPackageManifestOp = new LoadWebPackageManifestOperation(manifestServices, remoteServices, downloadBackend, packageName, _packageVersion, packageHash, _timeout); _loadWebPackageManifestOp.StartOperation(); AddChildOperation(_loadWebPackageManifestOp); } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSRequestPackageVersionOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSRequestPackageVersionOperation.cs index 6d3d817e..82042c38 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSRequestPackageVersionOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebRemoteFileSystem/Operation/DWRFSRequestPackageVersionOperation.cs @@ -36,7 +36,7 @@ namespace YooAsset { if (_requestWebPackageVersionOp == null) { - _requestWebPackageVersionOp = new RequestWebPackageVersionOperation(_fileSystem.RemoteServices, _fileSystem.PackageName, _appendTimeTicks, _timeout); + _requestWebPackageVersionOp = new RequestWebPackageVersionOperation(_fileSystem.RemoteServices, _fileSystem.DownloadBackend, _fileSystem.PackageName, _appendTimeTicks, _timeout); _requestWebPackageVersionOp.StartOperation(); AddChildOperation(_requestWebPackageVersionOp); } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/DefaultWebServerFileSystem.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/DefaultWebServerFileSystem.cs index d90049e8..7c9b1a88 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/DefaultWebServerFileSystem.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/DefaultWebServerFileSystem.cs @@ -24,6 +24,11 @@ namespace YooAsset protected readonly Dictionary _webFilePathMapping = new Dictionary(10000); protected string _webPackageRoot = string.Empty; + /// + /// 下载后台接口 + /// + public IDownloadBackend DownloadBackend { private set; get; } + /// /// 包裹名称 /// @@ -138,6 +143,10 @@ namespace YooAsset _webPackageRoot = GetDefaultWebPackageRoot(packageName); else _webPackageRoot = packageRoot; + + // 创建默认的下载后台接口 + if (DownloadBackend == null) + DownloadBackend = new UnityWebRequestBackend(DownloadSystemHelper.UnityWebRequestCreater); } public virtual void OnDestroy() { diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/DWSFSLoadBundleOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/DWSFSLoadBundleOperation.cs index 9d80ebb1..be4b003b 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/DWSFSLoadBundleOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/DWSFSLoadBundleOperation.cs @@ -41,13 +41,13 @@ namespace YooAsset if (_bundle.Encrypted) { - _loadWebAssetBundleOp = new LoadWebEncryptAssetBundleOperation(_bundle, options, _fileSystem.DecryptionServices); + _loadWebAssetBundleOp = new LoadWebEncryptAssetBundleOperation(_bundle, options, _fileSystem.DecryptionServices, _fileSystem.DownloadBackend); _loadWebAssetBundleOp.StartOperation(); AddChildOperation(_loadWebAssetBundleOp); } else { - _loadWebAssetBundleOp = new LoadWebNormalAssetBundleOperation(_bundle, options, _fileSystem.DisableUnityWebCache); + _loadWebAssetBundleOp = new LoadWebNormalAssetBundleOperation(_bundle, options, _fileSystem.DisableUnityWebCache, _fileSystem.DownloadBackend); _loadWebAssetBundleOp.StartOperation(); AddChildOperation(_loadWebAssetBundleOp); } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/LoadWebServerCatalogFileOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/LoadWebServerCatalogFileOperation.cs index 4cc2370e..786c5a49 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/LoadWebServerCatalogFileOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/LoadWebServerCatalogFileOperation.cs @@ -14,7 +14,7 @@ namespace YooAsset private readonly DefaultWebServerFileSystem _fileSystem; private readonly int _timeout; - private UnityWebDataRequestOperation _webDataRequestOp; + private IDownloadBytesRequest _webDataRequestOp; private ESteps _steps = ESteps.None; internal LoadWebServerCatalogFileOperation(DefaultWebServerFileSystem fileSystem, int timeout) @@ -37,16 +37,15 @@ namespace YooAsset { string filePath = _fileSystem.GetCatalogBinaryFileLoadPath(); string url = DownloadSystemHelper.ConvertToWWWPath(filePath); - _webDataRequestOp = new UnityWebDataRequestOperation(url, _timeout); - _webDataRequestOp.StartOperation(); - AddChildOperation(_webDataRequestOp); + var args = new DownloadDataRequestArgs(url, _timeout, 0); + _webDataRequestOp = _fileSystem.DownloadBackend.CreateBytesRequest(args); + _webDataRequestOp.SendRequest(); } - _webDataRequestOp.UpdateOperation(); if (_webDataRequestOp.IsDone == false) return; - if (_webDataRequestOp.Status == EOperationStatus.Succeed) + if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.LoadCatalog; } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/LoadWebServerPackageManifestOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/LoadWebServerPackageManifestOperation.cs index 5ac17b40..a0165137 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/LoadWebServerPackageManifestOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/LoadWebServerPackageManifestOperation.cs @@ -16,7 +16,7 @@ namespace YooAsset private readonly string _packageVersion; private readonly string _packageHash; private readonly int _timeout; - private UnityWebDataRequestOperation _webDataRequestOp; + private IDownloadBytesRequest _webDataRequestOp; private DeserializeManifestOperation _deserializer; private ESteps _steps = ESteps.None; @@ -48,16 +48,15 @@ namespace YooAsset { string filePath = _fileSystem.GetWebPackageManifestFilePath(_packageVersion); string url = DownloadSystemHelper.ConvertToWWWPath(filePath); - _webDataRequestOp = new UnityWebDataRequestOperation(url, _timeout); - _webDataRequestOp.StartOperation(); - AddChildOperation(_webDataRequestOp); + var args = new DownloadDataRequestArgs(url, _timeout, 0); + _webDataRequestOp = _fileSystem.DownloadBackend.CreateBytesRequest(args); + _webDataRequestOp.SendRequest(); } - _webDataRequestOp.UpdateOperation(); if (_webDataRequestOp.IsDone == false) return; - if (_webDataRequestOp.Status == EOperationStatus.Succeed) + if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.VerifyFileData; } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/RequestWebServerPackageHashOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/RequestWebServerPackageHashOperation.cs index 6b9fbf57..4486fe41 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/RequestWebServerPackageHashOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/RequestWebServerPackageHashOperation.cs @@ -13,7 +13,7 @@ namespace YooAsset private readonly DefaultWebServerFileSystem _fileSystem; private readonly string _packageVersion; private readonly int _timeout; - private UnityWebTextRequestOperation _webTextRequestOp; + private IDownloadTextRequest _webTextRequestOp; private ESteps _steps = ESteps.None; /// @@ -43,17 +43,16 @@ namespace YooAsset { string filePath = _fileSystem.GetWebPackageHashFilePath(_packageVersion); string url = DownloadSystemHelper.ConvertToWWWPath(filePath); - _webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout); - _webTextRequestOp.StartOperation(); - AddChildOperation(_webTextRequestOp); + var args = new DownloadDataRequestArgs(url, _timeout, 0); + _webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args); + _webTextRequestOp.SendRequest(); } - _webTextRequestOp.UpdateOperation(); - Progress = _webTextRequestOp.Progress; + Progress = _webTextRequestOp.DownloadProgress; if (_webTextRequestOp.IsDone == false) return; - if (_webTextRequestOp.Status == EOperationStatus.Succeed) + if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed) { PackageHash = _webTextRequestOp.Result; if (string.IsNullOrEmpty(PackageHash)) diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/RequestWebServerPackageVersionOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/RequestWebServerPackageVersionOperation.cs index 409f6791..b5b031e3 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/RequestWebServerPackageVersionOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultWebServerFileSystem/Operation/internal/RequestWebServerPackageVersionOperation.cs @@ -12,7 +12,7 @@ namespace YooAsset private readonly DefaultWebServerFileSystem _fileSystem; private readonly int _timeout; - private UnityWebTextRequestOperation _webTextRequestOp; + private IDownloadTextRequest _webTextRequestOp; private ESteps _steps = ESteps.None; /// @@ -41,16 +41,15 @@ namespace YooAsset { string filePath = _fileSystem.GetWebPackageVersionFilePath(); string url = DownloadSystemHelper.ConvertToWWWPath(filePath); - _webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout); - _webTextRequestOp.StartOperation(); - AddChildOperation(_webTextRequestOp); + var args = new DownloadDataRequestArgs(url, _timeout, 0); + _webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args); + _webTextRequestOp.SendRequest(); } - _webTextRequestOp.UpdateOperation(); if (_webTextRequestOp.IsDone == false) return; - if (_webTextRequestOp.Status == EOperationStatus.Succeed) + if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed) { PackageVersion = _webTextRequestOp.Result; if (string.IsNullOrEmpty(PackageVersion)) diff --git a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebEncryptAssetBundleOperation.cs b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebEncryptAssetBundleOperation.cs index 71561246..36cf9ef7 100644 --- a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebEncryptAssetBundleOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebEncryptAssetBundleOperation.cs @@ -16,19 +16,21 @@ namespace YooAsset private readonly PackageBundle _bundle; private readonly DownloadFileOptions _options; private readonly IWebDecryptionServices _decryptionServices; - private UnityWebDataRequestOperation _unityWebDataRequestOp; + private readonly IDownloadBackend _downloadBackend; + private IDownloadBytesRequest _unityWebDataRequestOp; private int _requestCount = 0; private float _tryAgainTimer = 0; private int _failedTryAgain; private ESteps _steps = ESteps.None; - internal LoadWebEncryptAssetBundleOperation(PackageBundle bundle, DownloadFileOptions options, IWebDecryptionServices decryptionServices) + internal LoadWebEncryptAssetBundleOperation(PackageBundle bundle, DownloadFileOptions options, IWebDecryptionServices decryptionServices, IDownloadBackend downloadBackend) { _bundle = bundle; _options = options; _failedTryAgain = options.FailedTryAgain; _decryptionServices = decryptionServices; + _downloadBackend = downloadBackend; } internal override void InternalStart() { @@ -52,24 +54,23 @@ namespace YooAsset } string url = GetRequestURL(); - _unityWebDataRequestOp = new UnityWebDataRequestOperation(url, 0); - _unityWebDataRequestOp.StartOperation(); - AddChildOperation(_unityWebDataRequestOp); + var args = new DownloadDataRequestArgs(url, 0, 0); + _unityWebDataRequestOp = _downloadBackend.CreateBytesRequest(args); + _unityWebDataRequestOp.SendRequest(); _steps = ESteps.CheckRequest; } // 检测下载结果 if (_steps == ESteps.CheckRequest) { - _unityWebDataRequestOp.UpdateOperation(); - Progress = _unityWebDataRequestOp.Progress; + Progress = _unityWebDataRequestOp.DownloadProgress; DownloadProgress = _unityWebDataRequestOp.DownloadProgress; DownloadedBytes = _unityWebDataRequestOp.DownloadedBytes; if (_unityWebDataRequestOp.IsDone == false) return; // 检查网络错误 - if (_unityWebDataRequestOp.Status == EOperationStatus.Succeed) + if (_unityWebDataRequestOp.Status == EDownloadRequestStatus.Succeed) { AssetBundle assetBundle = LoadEncryptedAssetBundle(_unityWebDataRequestOp.Result); if (assetBundle == null) diff --git a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebNormalAssetBundleOperation.cs b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebNormalAssetBundleOperation.cs index f3fa65f8..e392c349 100644 --- a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebNormalAssetBundleOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebNormalAssetBundleOperation.cs @@ -16,7 +16,8 @@ namespace YooAsset private readonly PackageBundle _bundle; private readonly DownloadFileOptions _options; private readonly bool _disableUnityWebCache; - private UnityAssetBundleRequestOperation _unityAssetBundleRequestOp; + private readonly IDownloadBackend _downloadBackend; + private IDownloadAssetBundleRequest _unityAssetBundleRequestOp; private int _requestCount = 0; private float _tryAgainTimer = 0; @@ -24,12 +25,13 @@ namespace YooAsset private ESteps _steps = ESteps.None; - internal LoadWebNormalAssetBundleOperation(PackageBundle bundle, DownloadFileOptions options, bool disableUnityWebCache) + internal LoadWebNormalAssetBundleOperation(PackageBundle bundle, DownloadFileOptions options, bool disableUnityWebCache, IDownloadBackend downloadBackend) { _bundle = bundle; _options = options; _failedTryAgain = options.FailedTryAgain; _disableUnityWebCache = disableUnityWebCache; + _downloadBackend = downloadBackend; } internal override void InternalStart() { @@ -44,23 +46,22 @@ namespace YooAsset if (_steps == ESteps.CreateRequest) { string url = GetRequestURL(); - _unityAssetBundleRequestOp = new UnityAssetBundleRequestOperation(_bundle, _disableUnityWebCache, url); - _unityAssetBundleRequestOp.StartOperation(); - AddChildOperation(_unityAssetBundleRequestOp); + var args = new DownloadAssetBundleRequestArgs(url, 0, 0, _disableUnityWebCache, _bundle.FileHash, _bundle.UnityCRC); + _unityAssetBundleRequestOp = _downloadBackend.CreateAssetBundleRequest(args); + _unityAssetBundleRequestOp.SendRequest(); _steps = ESteps.CheckRequest; } // 检测下载结果 if (_steps == ESteps.CheckRequest) { - _unityAssetBundleRequestOp.UpdateOperation(); - Progress = _unityAssetBundleRequestOp.Progress; + Progress = _unityAssetBundleRequestOp.DownloadProgress; DownloadedBytes = _unityAssetBundleRequestOp.DownloadedBytes; DownloadProgress = _unityAssetBundleRequestOp.DownloadProgress; if (_unityAssetBundleRequestOp.IsDone == false) return; - if (_unityAssetBundleRequestOp.Status == EOperationStatus.Succeed) + if (_unityAssetBundleRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; diff --git a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebPackageManifestOperation.cs b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebPackageManifestOperation.cs index b3de3baf..03014d54 100644 --- a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebPackageManifestOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/LoadWebPackageManifestOperation.cs @@ -13,11 +13,12 @@ internal class LoadWebPackageManifestOperation : AsyncOperationBase private readonly IManifestRestoreServices _manifestServices; private readonly IRemoteServices _remoteServices; + private readonly IDownloadBackend _downloadBackend; private readonly string _packageName; private readonly string _packageVersion; private readonly string _packageHash; private readonly int _timeout; - private UnityWebDataRequestOperation _webDataRequestOp; + private IDownloadBytesRequest _webDataRequestOp; private DeserializeManifestOperation _deserializer; private int _requestCount = 0; private ESteps _steps = ESteps.None; @@ -28,11 +29,12 @@ internal class LoadWebPackageManifestOperation : AsyncOperationBase public PackageManifest Manifest { private set; get; } - internal LoadWebPackageManifestOperation(IManifestRestoreServices manifestServices, IRemoteServices remoteServices, + internal LoadWebPackageManifestOperation(IManifestRestoreServices manifestServices, IRemoteServices remoteServices, IDownloadBackend downloadBackend, string packageName, string packageVersion, string packageHash, int timeout) { _manifestServices = manifestServices; _remoteServices = remoteServices; + _downloadBackend = downloadBackend; _packageName = packageName; _packageVersion = packageVersion; _packageHash = packageHash; @@ -54,17 +56,16 @@ internal class LoadWebPackageManifestOperation : AsyncOperationBase { string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_packageName, _packageVersion); string url = GetRequestURL(fileName); - _webDataRequestOp = new UnityWebDataRequestOperation(url, _timeout); - _webDataRequestOp.StartOperation(); - AddChildOperation(_webDataRequestOp); + var args = new DownloadDataRequestArgs(url, _timeout, 0); + _webDataRequestOp = _downloadBackend.CreateBytesRequest(args); + _webDataRequestOp.SendRequest(); } - _webDataRequestOp.UpdateOperation(); - Progress = _webDataRequestOp.Progress; + Progress = _webDataRequestOp.DownloadProgress; if (_webDataRequestOp.IsDone == false) return; - if (_webDataRequestOp.Status == EOperationStatus.Succeed) + if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.VerifyFileData; } diff --git a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/RequestWebPackageHashOperation.cs b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/RequestWebPackageHashOperation.cs index 0e37ac80..c7572317 100644 --- a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/RequestWebPackageHashOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/RequestWebPackageHashOperation.cs @@ -10,10 +10,11 @@ internal class RequestWebPackageHashOperation : AsyncOperationBase } private readonly IRemoteServices _remoteServices; + private readonly IDownloadBackend _downloadBackend; private readonly string _packageName; private readonly string _packageVersion; private readonly int _timeout; - private UnityWebTextRequestOperation _webTextRequestOp; + private IDownloadTextRequest _webTextRequestOp; private int _requestCount = 0; private ESteps _steps = ESteps.None; @@ -23,9 +24,10 @@ internal class RequestWebPackageHashOperation : AsyncOperationBase public string PackageHash { private set; get; } - public RequestWebPackageHashOperation(IRemoteServices remoteServices, string packageName, string packageVersion, int timeout) + public RequestWebPackageHashOperation(IRemoteServices remoteServices, IDownloadBackend downloadBackend, string packageName, string packageVersion, int timeout) { _remoteServices = remoteServices; + _downloadBackend = downloadBackend; _packageName = packageName; _packageVersion = packageVersion; _timeout = timeout; @@ -46,17 +48,16 @@ internal class RequestWebPackageHashOperation : AsyncOperationBase { string fileName = YooAssetSettingsData.GetPackageHashFileName(_packageName, _packageVersion); string url = GetRequestURL(fileName); - _webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout); - _webTextRequestOp.StartOperation(); - AddChildOperation(_webTextRequestOp); + var args = new DownloadDataRequestArgs(url, _timeout, 0); + _webTextRequestOp = _downloadBackend.CreateTextRequest(args); + _webTextRequestOp.SendRequest(); } - _webTextRequestOp.UpdateOperation(); - Progress = _webTextRequestOp.Progress; + Progress = _webTextRequestOp.DownloadProgress; if (_webTextRequestOp.IsDone == false) return; - if (_webTextRequestOp.Status == EOperationStatus.Succeed) + if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed) { PackageHash = _webTextRequestOp.Result; if (string.IsNullOrEmpty(PackageHash)) diff --git a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/RequestWebPackageVersionOperation.cs b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/RequestWebPackageVersionOperation.cs index 7147e65e..36e729ff 100644 --- a/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/RequestWebPackageVersionOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/WebGame/Operation/RequestWebPackageVersionOperation.cs @@ -10,10 +10,11 @@ internal class RequestWebPackageVersionOperation : AsyncOperationBase } private readonly IRemoteServices _remoteServices; + private readonly IDownloadBackend _downloadBackend; private readonly string _packageName; private readonly bool _appendTimeTicks; private readonly int _timeout; - private UnityWebTextRequestOperation _webTextRequestOp; + private IDownloadTextRequest _webTextRequestOp; private int _requestCount = 0; private ESteps _steps = ESteps.None; @@ -23,9 +24,10 @@ internal class RequestWebPackageVersionOperation : AsyncOperationBase public string PackageVersion { private set; get; } - public RequestWebPackageVersionOperation(IRemoteServices remoteServices, string packageName, bool appendTimeTicks, int timeout) + public RequestWebPackageVersionOperation(IRemoteServices remoteServices, IDownloadBackend downloadBackend, string packageName, bool appendTimeTicks, int timeout) { _remoteServices = remoteServices; + _downloadBackend = downloadBackend; _packageName = packageName; _appendTimeTicks = appendTimeTicks; _timeout = timeout; @@ -46,17 +48,16 @@ internal class RequestWebPackageVersionOperation : AsyncOperationBase { string fileName = YooAssetSettingsData.GetPackageVersionFileName(_packageName); string url = GetRequestURL(fileName); - _webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout); - _webTextRequestOp.StartOperation(); - AddChildOperation(_webTextRequestOp); + var args = new DownloadDataRequestArgs(url, _timeout, 0); + _webTextRequestOp = _downloadBackend.CreateTextRequest(args); + _webTextRequestOp.SendRequest(); } - _webTextRequestOp.UpdateOperation(); - Progress = _webTextRequestOp.Progress; + Progress = _webTextRequestOp.DownloadProgress; if (_webTextRequestOp.IsDone == false) return; - if (_webTextRequestOp.Status == EOperationStatus.Succeed) + if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed) { PackageVersion = _webTextRequestOp.Result; if (string.IsNullOrEmpty(PackageVersion)) diff --git a/Assets/YooAsset/Runtime/OperationSystem/AsyncOperationBase.cs b/Assets/YooAsset/Runtime/OperationSystem/AsyncOperationBase.cs index e3126359..9111262e 100644 --- a/Assets/YooAsset/Runtime/OperationSystem/AsyncOperationBase.cs +++ b/Assets/YooAsset/Runtime/OperationSystem/AsyncOperationBase.cs @@ -139,6 +139,19 @@ namespace YooAsset Childs.Add(child); } + /// + /// 移除子任务 + /// + internal void RemoveChildOperation(AsyncOperationBase child) + { +#if UNITY_EDITOR + if (Childs.Contains(child) == false) + throw new YooInternalException($"The child node {child.GetType().Name} not exists !"); +#endif + + Childs.Remove(child); + } + /// /// 获取异步操作说明 /// diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ExtensionOperation/CopyBuildinManifestOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ExtensionOperation/CopyBuildinManifestOperation.cs index bdce494b..4ad500a0 100644 --- a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ExtensionOperation/CopyBuildinManifestOperation.cs +++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ExtensionOperation/CopyBuildinManifestOperation.cs @@ -21,14 +21,16 @@ public class CopyBuildinManifestOperation : GameAsyncOperation private readonly string _packageName; private readonly string _packageVersion; + private readonly IDownloadBackend _backend; + private IDownloadFileRequest _hashFileRequestOp; + private IDownloadFileRequest _manifestFileRequestOp; private ESteps _steps = ESteps.None; - private UnityWebFileRequestOperation _hashFileRequestOp; - private UnityWebFileRequestOperation _manifestFileRequestOp; public CopyBuildinManifestOperation(string packageName, string packageVersion) { _packageName = packageName; _packageVersion = packageVersion; + _backend = new UnityWebRequestBackend(); } protected override void OnStart() { @@ -58,14 +60,15 @@ public class CopyBuildinManifestOperation : GameAsyncOperation string sourcePath = GetBuildinHashFilePath(); string destPath = GetCacheHashFilePath(); string url = DownloadSystemHelper.ConvertToWWWPath(sourcePath); - _hashFileRequestOp = new UnityWebFileRequestOperation(url, destPath, 60); - OperationSystem.StartOperation(_packageName, _hashFileRequestOp); + var args = new DownloadFileRequestArgs(url, destPath, 60, 0); + _hashFileRequestOp = _backend.CreateFileRequest(args); + _hashFileRequestOp.SendRequest(); } if (_hashFileRequestOp.IsDone == false) return; - if (_hashFileRequestOp.Status == EOperationStatus.Succeed) + if (_hashFileRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.CheckManifestFile; } @@ -97,14 +100,15 @@ public class CopyBuildinManifestOperation : GameAsyncOperation string sourcePath = GetBuildinManifestFilePath(); string destPath = GetCacheManifestFilePath(); string url = DownloadSystemHelper.ConvertToWWWPath(sourcePath); - _manifestFileRequestOp = new UnityWebFileRequestOperation(url, destPath, 60); - OperationSystem.StartOperation(_packageName, _manifestFileRequestOp); + var args = new DownloadFileRequestArgs(url, destPath, 60, 0); + _manifestFileRequestOp = _backend.CreateFileRequest(args); + _manifestFileRequestOp.SendRequest(); } if (_manifestFileRequestOp.IsDone == false) return; - if (_manifestFileRequestOp.Status == EOperationStatus.Succeed) + if (_manifestFileRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.Done; Status = EOperationStatus.Succeed; diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ExtensionOperation/GetBuildinPackageVersionOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ExtensionOperation/GetBuildinPackageVersionOperation.cs index 8259546e..6217dca9 100644 --- a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ExtensionOperation/GetBuildinPackageVersionOperation.cs +++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ExtensionOperation/GetBuildinPackageVersionOperation.cs @@ -17,7 +17,8 @@ public class GetBuildinPackageVersionOperation : GameAsyncOperation } private readonly string _packageName; - private UnityWebTextRequestOperation _versionFileRequestOp; + private readonly IDownloadBackend _backend; + private IDownloadTextRequest _versionFileRequestOp; private ESteps _steps = ESteps.None; /// @@ -28,6 +29,7 @@ public class GetBuildinPackageVersionOperation : GameAsyncOperation public GetBuildinPackageVersionOperation(string packageName) { _packageName = packageName; + _backend = new UnityWebRequestBackend(); } protected override void OnStart() { @@ -44,14 +46,15 @@ public class GetBuildinPackageVersionOperation : GameAsyncOperation { string filePath = GetBuildinPackageVersionFilePath(); string url = DownloadSystemHelper.ConvertToWWWPath(filePath); - _versionFileRequestOp = new UnityWebTextRequestOperation(url, 60); - OperationSystem.StartOperation(_packageName, _versionFileRequestOp); + var args = new DownloadDataRequestArgs(url, 60, 0); + _versionFileRequestOp = _backend.CreateTextRequest(args); + _versionFileRequestOp.SendRequest(); } if (_versionFileRequestOp.IsDone == false) return; - if (_versionFileRequestOp.Status == EOperationStatus.Succeed) + if (_versionFileRequestOp.Status == EDownloadRequestStatus.Succeed) { _steps = ESteps.Done; Status = EOperationStatus.Succeed;