diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs new file mode 100644 index 00000000..1923bfd8 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs @@ -0,0 +1,65 @@ +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/UnityVirtualBundleRequestOperation.cs.meta b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs.meta new file mode 100644 index 00000000..c59ceee4 --- /dev/null +++ b/Assets/YooAsset/Runtime/DownloadSystem/Operation/Internal/UnityVirtualBundleRequestOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e71e850eded0da43906cb4f7cb75629 +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 b4108bc2..88357b24 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/DefaultEditorFileSystem.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/DefaultEditorFileSystem.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace YooAsset { @@ -7,6 +8,7 @@ namespace YooAsset /// internal class DefaultEditorFileSystem : IFileSystem { + protected readonly HashSet _records = new HashSet(); protected string _packageRoot; /// @@ -37,15 +39,25 @@ namespace YooAsset } #region 自定义参数 + /// + /// 模拟虚拟下载模式 + /// + public bool VirtualDownloadMode { private set; get; } = false; + + /// + /// 模拟虚拟下载的网速(单位:字节) + /// + public int VirtualDownloadSpeed { private set; get; } = 1024; + /// /// 异步模拟加载最小帧数 /// - public int _asyncSimulateMinFrame = 1; + public int AsyncSimulateMinFrame { private set; get; } = 1; /// /// 异步模拟加载最大帧数 /// - public int _asyncSimulateMaxFrame = 1; + public int AsyncSimulateMaxFrame { private set; get; } = 1; #endregion public DefaultEditorFileSystem() @@ -73,7 +85,10 @@ namespace YooAsset } public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadFileOptions options) { - throw new System.NotImplementedException(); + string mainURL = bundle.BundleName; + options.SetURL(mainURL, mainURL); + var downloader = new DownloadVirtualBundleOperation(this, bundle, options); + return downloader; } public virtual FSLoadBundleOperation LoadBundleFile(PackageBundle bundle) { @@ -92,13 +107,21 @@ namespace YooAsset public virtual void SetParameter(string name, object value) { - if (name == FileSystemParametersDefine.ASYNC_SIMULATE_MIN_FRAME) + if (name == FileSystemParametersDefine.VIRTUAL_DOWNLOAD_MODE) { - _asyncSimulateMinFrame = Convert.ToInt32(value); + VirtualDownloadMode = Convert.ToBoolean(value); + } + else if (name == FileSystemParametersDefine.VIRTUAL_DOWNLOAD_SPEED) + { + VirtualDownloadSpeed = Convert.ToInt32(value); + } + else if (name == FileSystemParametersDefine.ASYNC_SIMULATE_MIN_FRAME) + { + AsyncSimulateMinFrame = Convert.ToInt32(value); } else if (name == FileSystemParametersDefine.ASYNC_SIMULATE_MAX_FRAME) { - _asyncSimulateMaxFrame = Convert.ToInt32(value); + AsyncSimulateMaxFrame = Convert.ToInt32(value); } else { @@ -124,11 +147,21 @@ namespace YooAsset } public virtual bool Exists(PackageBundle bundle) { - return true; + if (VirtualDownloadMode) + { + return _records.Contains(bundle.BundleGUID); + } + else + { + return true; + } } public virtual bool NeedDownload(PackageBundle bundle) { - return false; + if (Belong(bundle) == false) + return false; + + return Exists(bundle) == false; } public virtual bool NeedUnpack(PackageBundle bundle) { @@ -165,6 +198,11 @@ namespace YooAsset } #region 内部方法 + public void RecordDownloadFile(string bundleName) + { + if (_records.Contains(bundleName) == false) + _records.Add(bundleName); + } public string GetEditorPackageVersionFilePath() { string fileName = YooAssetSettingsData.GetPackageVersionFileName(PackageName); @@ -182,12 +220,12 @@ namespace YooAsset } public int GetAsyncSimulateFrame() { - if (_asyncSimulateMinFrame > _asyncSimulateMaxFrame) + if (AsyncSimulateMinFrame > AsyncSimulateMaxFrame) { - _asyncSimulateMinFrame = _asyncSimulateMaxFrame; + AsyncSimulateMinFrame = AsyncSimulateMaxFrame; } - return UnityEngine.Random.Range(_asyncSimulateMinFrame, _asyncSimulateMaxFrame + 1); + return UnityEngine.Random.Range(AsyncSimulateMinFrame, AsyncSimulateMaxFrame + 1); } #endregion } diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/DEFSLoadBundleOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/DEFSLoadBundleOperation.cs index 8edfc97b..a2b5d295 100644 --- a/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/DEFSLoadBundleOperation.cs +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/DEFSLoadBundleOperation.cs @@ -6,6 +6,7 @@ namespace YooAsset protected enum ESteps { None, + CheckExist, DownloadFile, LoadAssetBundle, CheckResult, @@ -14,6 +15,7 @@ namespace YooAsset private readonly DefaultEditorFileSystem _fileSystem; private readonly PackageBundle _bundle; + protected FSDownloadFileOperation _downloadFileOp; private int _asyncSimulateFrame; private ESteps _steps = ESteps.None; @@ -24,19 +26,57 @@ namespace YooAsset } internal override void InternalStart() { - _steps = ESteps.DownloadFile; + _steps = ESteps.CheckExist; + _asyncSimulateFrame = _fileSystem.GetAsyncSimulateFrame(); } internal override void InternalUpdate() { if (_steps == ESteps.None || _steps == ESteps.Done) return; + if (_steps == ESteps.CheckExist) + { + if (_fileSystem.Exists(_bundle)) + { + DownloadProgress = 1f; + DownloadedBytes = _bundle.FileSize; + _steps = ESteps.LoadAssetBundle; + } + else + { + _steps = ESteps.DownloadFile; + } + } + if (_steps == ESteps.DownloadFile) { - _asyncSimulateFrame = _fileSystem.GetAsyncSimulateFrame(); - DownloadProgress = 1f; - DownloadedBytes = _bundle.FileSize; - _steps = ESteps.LoadAssetBundle; + if (_downloadFileOp == null) + { + DownloadFileOptions options = new DownloadFileOptions(int.MaxValue); + _downloadFileOp = _fileSystem.DownloadFileAsync(_bundle, options); + _downloadFileOp.StartOperation(); + AddChildOperation(_downloadFileOp); + } + + if (IsWaitForAsyncComplete) + _downloadFileOp.WaitForAsyncComplete(); + + _downloadFileOp.UpdateOperation(); + DownloadProgress = _downloadFileOp.DownloadProgress; + DownloadedBytes = _downloadFileOp.DownloadedBytes; + if (_downloadFileOp.IsDone == false) + return; + + if (_downloadFileOp.Status == EOperationStatus.Succeed) + { + _steps = ESteps.LoadAssetBundle; + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = _downloadFileOp.Error; + } } if (_steps == ESteps.LoadAssetBundle) diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs new file mode 100644 index 00000000..5e29e1bc --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs @@ -0,0 +1,156 @@ +using UnityEngine; + +namespace YooAsset +{ + internal class DownloadVirtualBundleOperation : FSDownloadFileOperation + { + protected enum ESteps + { + None, + CheckExists, + CreateRequest, + CheckRequest, + TryAgain, + Done, + } + + // 下载参数 + protected readonly DefaultEditorFileSystem _fileSystem; + protected readonly DownloadFileOptions _options; + protected UnityVirtualBundleRequestOperation _unityDownloadFileOp; + + protected int _requestCount = 0; + protected float _tryAgainTimer; + protected int _failedTryAgain; + private ESteps _steps = ESteps.None; + + + internal DownloadVirtualBundleOperation(DefaultEditorFileSystem fileSystem, PackageBundle bundle, DownloadFileOptions options) : base(bundle) + { + _fileSystem = fileSystem; + _options = options; + _failedTryAgain = options.FailedTryAgain; + } + internal override void InternalStart() + { + _steps = ESteps.CheckExists; + } + internal override void InternalUpdate() + { + if (_steps == ESteps.None || _steps == ESteps.Done) + return; + + // 检测文件是否存在 + if (_steps == ESteps.CheckExists) + { + if (_fileSystem.Exists(Bundle)) + { + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + } + else + { + _steps = ESteps.CreateRequest; + } + } + + // 创建下载器 + if (_steps == ESteps.CreateRequest) + { + if (_options.IsValid() == false) + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = "Download file options is invalid !"; + Debug.Log(Error); + return; + } + + string url = GetRequestURL(); + int speed = _fileSystem.VirtualDownloadSpeed; + _unityDownloadFileOp = new UnityVirtualBundleRequestOperation(Bundle, speed, url); + _unityDownloadFileOp.StartOperation(); + _steps = ESteps.CheckRequest; + } + + // 检测下载结果 + if (_steps == ESteps.CheckRequest) + { + if (IsWaitForAsyncComplete) + _unityDownloadFileOp.WaitForAsyncComplete(); + + // 因为并发数量限制,下载器可能被挂起! + if (_unityDownloadFileOp.Status == EOperationStatus.None) + return; + + _unityDownloadFileOp.UpdateOperation(); + Progress = _unityDownloadFileOp.Progress; + DownloadedBytes = _unityDownloadFileOp.DownloadedBytes; + DownloadProgress = _unityDownloadFileOp.DownloadProgress; + if (_unityDownloadFileOp.IsDone == false) + return; + + if (_unityDownloadFileOp.Status == EOperationStatus.Succeed) + { + _fileSystem.RecordDownloadFile(Bundle.BundleName); + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + } + else + { + if (IsWaitForAsyncComplete == false && _failedTryAgain > 0) + { + _steps = ESteps.TryAgain; + YooLogger.Warning($"Failed download : {_unityDownloadFileOp.URL} Try again !"); + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = _unityDownloadFileOp.Error; + YooLogger.Error(Error); + } + } + } + + // 重新尝试下载 + if (_steps == ESteps.TryAgain) + { + _tryAgainTimer += Time.unscaledDeltaTime; + if (_tryAgainTimer > 1f) + { + _tryAgainTimer = 0f; + _failedTryAgain--; + Progress = 0f; + DownloadProgress = 0f; + DownloadedBytes = 0; + _steps = ESteps.CreateRequest; + } + } + } + internal override void InternalWaitForAsyncComplete() + { + while (true) + { + if (ExecuteWhileDone()) + { + _steps = ESteps.Done; + break; + } + } + } + + /// + /// 获取网络请求地址 + /// + protected string GetRequestURL() + { + // 轮流返回请求地址 + _requestCount++; + if (_requestCount % 2 == 0) + return _options.FallbackURL; + else + return _options.MainURL; + } + } +} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs.meta b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs.meta new file mode 100644 index 00000000..fe0f5b42 --- /dev/null +++ b/Assets/YooAsset/Runtime/FileSystem/DefaultEditorFileSystem/Operation/internal/DownloadVirutalBundleOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f043dc0e0f147334380cfd0720636544 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/FileSystem/FileSystemParametersDefine.cs b/Assets/YooAsset/Runtime/FileSystem/FileSystemParametersDefine.cs index b93f2384..df96122a 100644 --- a/Assets/YooAsset/Runtime/FileSystem/FileSystemParametersDefine.cs +++ b/Assets/YooAsset/Runtime/FileSystem/FileSystemParametersDefine.cs @@ -17,6 +17,8 @@ namespace YooAsset public const string DOWNLOAD_MAX_REQUEST_PER_FRAME = "DOWNLOAD_MAX_REQUEST_PER_FRAME"; public const string RESUME_DOWNLOAD_MINMUM_SIZE = "RESUME_DOWNLOAD_MINMUM_SIZE"; public const string RESUME_DOWNLOAD_RESPONSE_CODES = "RESUME_DOWNLOAD_RESPONSE_CODES"; + public const string VIRTUAL_DOWNLOAD_MODE = "ENABLE_VIRTUAL_DOWNLOAD"; + public const string VIRTUAL_DOWNLOAD_SPEED = "VIRTUAL_DOWNLOAD_MAX_SPEED"; public const string ASYNC_SIMULATE_MIN_FRAME = "ASYNC_SIMULATE_MIN_FRAME"; public const string ASYNC_SIMULATE_MAX_FRAME = "ASYNC_SIMULATE_MAX_FRAME"; public const string COPY_BUILDIN_PACKAGE_MANIFEST = "COPY_BUILDIN_PACKAGE_MANIFEST";