| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- using System.Collections;
- using System.Collections.Generic;
- namespace YooAsset
- {
- public abstract class DownloaderOperation : AsyncOperationBase
- {
- private enum ESteps
- {
- None,
- Check,
- Loading,
- Done,
- }
- private const int MAX_LOADER_COUNT = 64;
- #region 委托定义
- /// <summary>
- /// 下载器结束
- /// </summary>
- public delegate void DownloaderFinish(DownloaderFinishData data);
- /// <summary>
- /// 下载进度更新
- /// </summary>
- public delegate void DownloadUpdate(DownloadUpdateData data);
- /// <summary>
- /// 下载发生错误
- /// </summary>
- public delegate void DownloadError(DownloadErrorData data);
- /// <summary>
- /// 开始下载某个文件
- /// </summary>
- public delegate void DownloadFileBegin(DownloadFileData data);
- #endregion
- private readonly string _packageName;
- private readonly int _downloadingMaxNumber;
- private readonly int _failedTryAgain;
- private readonly int _timeout;
- private readonly List<BundleInfo> _bundleInfoList;
- private readonly List<FSDownloadFileOperation> _downloaders = new List<FSDownloadFileOperation>(MAX_LOADER_COUNT);
- private readonly List<FSDownloadFileOperation> _removeList = new List<FSDownloadFileOperation>(MAX_LOADER_COUNT);
- private readonly List<FSDownloadFileOperation> _failedList = new List<FSDownloadFileOperation>(MAX_LOADER_COUNT);
- // 数据相关
- private bool _isPause = false;
- private long _lastDownloadBytes = 0;
- private int _lastDownloadCount = 0;
- private long _cachedDownloadBytes = 0;
- private int _cachedDownloadCount = 0;
- private ESteps _steps = ESteps.None;
- /// <summary>
- /// 统计的下载文件总数量
- /// </summary>
- public int TotalDownloadCount { private set; get; }
- /// <summary>
- /// 统计的下载文件的总大小
- /// </summary>
- public long TotalDownloadBytes { private set; get; }
- /// <summary>
- /// 当前已经完成的下载总数量
- /// </summary>
- public int CurrentDownloadCount
- {
- get { return _lastDownloadCount; }
- }
- /// <summary>
- /// 当前已经完成的下载总大小
- /// </summary>
- public long CurrentDownloadBytes
- {
- get { return _lastDownloadBytes; }
- }
- /// <summary>
- /// 当下载器结束(无论成功或失败)
- /// </summary>
- public DownloaderFinish DownloadFinishCallback { set; get; }
- /// <summary>
- /// 当下载进度发生变化
- /// </summary>
- public DownloadUpdate DownloadUpdateCallback { set; get; }
- /// <summary>
- /// 当下载器发生错误
- /// </summary>
- public DownloadError DownloadErrorCallback { set; get; }
- /// <summary>
- /// 当开始下载某个文件
- /// </summary>
- public DownloadFileBegin DownloadFileBeginCallback { set; get; }
- internal DownloaderOperation(string packageName, List<BundleInfo> downloadList, int downloadingMaxNumber, int failedTryAgain, int timeout)
- {
- _packageName = packageName;
- _bundleInfoList = downloadList;
- _downloadingMaxNumber = UnityEngine.Mathf.Clamp(downloadingMaxNumber, 1, MAX_LOADER_COUNT); ;
- _failedTryAgain = failedTryAgain;
- _timeout = timeout;
- // 设置包裹名称 (fix #210)
- SetPackageName(packageName);
- // 统计下载信息
- CalculatDownloaderInfo();
- }
- internal override void InternalStart()
- {
- YooLogger.Log($"Begine to download {TotalDownloadCount} files and {TotalDownloadBytes} bytes");
- _steps = ESteps.Check;
- }
- internal override void InternalUpdate()
- {
- if (_steps == ESteps.None || _steps == ESteps.Done)
- return;
- if (_steps == ESteps.Check)
- {
- if (_bundleInfoList == null)
- {
- _steps = ESteps.Done;
- Status = EOperationStatus.Failed;
- Error = "Download list is null.";
- }
- else
- {
- _steps = ESteps.Loading;
- }
- }
- if (_steps == ESteps.Loading)
- {
- // 检测下载器结果
- _removeList.Clear();
- long downloadBytes = _cachedDownloadBytes;
- foreach (var downloader in _downloaders)
- {
- downloader.UpdateOperation();
- downloadBytes += downloader.DownloadedBytes;
- if (downloader.IsDone == false)
- continue;
- // 检测是否下载失败
- if (downloader.Status != EOperationStatus.Succeed)
- {
- _removeList.Add(downloader);
- _failedList.Add(downloader);
- continue;
- }
- // 下载成功
- _removeList.Add(downloader);
- _cachedDownloadCount++;
- _cachedDownloadBytes += downloader.DownloadedBytes;
- }
- // 移除已经完成的下载器(无论成功或失败)
- foreach (var downloader in _removeList)
- {
- _downloaders.Remove(downloader);
- }
- // 如果下载进度发生变化
- if (_lastDownloadBytes != downloadBytes || _lastDownloadCount != _cachedDownloadCount)
- {
- _lastDownloadBytes = downloadBytes;
- _lastDownloadCount = _cachedDownloadCount;
- Progress = (float)_lastDownloadBytes / TotalDownloadBytes;
- if (DownloadUpdateCallback != null)
- {
- var data = new DownloadUpdateData();
- data.PackageName = _packageName;
- data.Progress = Progress;
- data.TotalDownloadCount = TotalDownloadCount;
- data.CurrentDownloadCount = _lastDownloadCount;
- data.TotalDownloadBytes = TotalDownloadBytes;
- data.CurrentDownloadBytes = _lastDownloadBytes;
- DownloadUpdateCallback.Invoke(data);
- }
- }
- // 动态创建新的下载器到最大数量限制
- // 注意:如果期间有下载失败的文件,暂停动态创建下载器
- if (_bundleInfoList.Count > 0 && _failedList.Count == 0)
- {
- if (_isPause)
- return;
- if (_downloaders.Count < _downloadingMaxNumber)
- {
- int index = _bundleInfoList.Count - 1;
- var bundleInfo = _bundleInfoList[index];
- var downloader = bundleInfo.CreateDownloader(_failedTryAgain, _timeout);
- downloader.StartOperation();
- this.AddChildOperation(downloader);
- _downloaders.Add(downloader);
- _bundleInfoList.RemoveAt(index);
- if (DownloadFileBeginCallback != null)
- {
- var data = new DownloadFileData();
- data.PackageName = _packageName;
- data.FileName = bundleInfo.Bundle.BundleName;
- data.FileSize = bundleInfo.Bundle.FileSize;
- DownloadFileBeginCallback.Invoke(data);
- }
- }
- }
- // 下载结算
- if (_downloaders.Count == 0)
- {
- if (_failedList.Count > 0)
- {
- var failedDownloader = _failedList[0];
- string bundleName = failedDownloader.Bundle.BundleName;
- _steps = ESteps.Done;
- Status = EOperationStatus.Failed;
- Error = $"Failed to download file : {bundleName}";
- if (DownloadErrorCallback != null)
- {
- var data = new DownloadErrorData();
- data.PackageName = _packageName;
- data.FileName = bundleName;
- data.ErrorInfo = failedDownloader.Error;
- DownloadErrorCallback.Invoke(data);
- }
- if (DownloadFinishCallback != null)
- {
- var data = new DownloaderFinishData();
- data.PackageName = _packageName;
- data.Succeed = false;
- DownloadFinishCallback.Invoke(data);
- }
- }
- else
- {
- // 结算成功
- _steps = ESteps.Done;
- Status = EOperationStatus.Succeed;
- if (DownloadFinishCallback != null)
- {
- var data = new DownloaderFinishData();
- data.PackageName = _packageName;
- data.Succeed = true;
- DownloadFinishCallback.Invoke(data);
- }
- }
- }
- }
- }
- private void CalculatDownloaderInfo()
- {
- if (_bundleInfoList != null)
- {
- TotalDownloadBytes = 0;
- TotalDownloadCount = _bundleInfoList.Count;
- foreach (var packageBundle in _bundleInfoList)
- {
- TotalDownloadBytes += packageBundle.Bundle.FileSize;
- }
- }
- else
- {
- TotalDownloadBytes = 0;
- TotalDownloadCount = 0;
- }
- }
- /// <summary>
- /// 合并其它下载器
- /// </summary>
- /// <param name="downloader">合并的下载器</param>
- public void Combine(DownloaderOperation downloader)
- {
- if (_packageName != downloader._packageName)
- {
- YooLogger.Error("The downloaders have different resource packages !");
- return;
- }
- if (Status != EOperationStatus.None)
- {
- YooLogger.Error("The downloader is running, can not combine with other downloader !");
- return;
- }
- HashSet<string> temper = new HashSet<string>();
- foreach (var bundleInfo in _bundleInfoList)
- {
- string combineGUID = bundleInfo.GetDownloadCombineGUID();
- if (temper.Contains(combineGUID) == false)
- {
- temper.Add(combineGUID);
- }
- }
- // 合并下载列表
- foreach (var bundleInfo in downloader._bundleInfoList)
- {
- string combineGUID = bundleInfo.GetDownloadCombineGUID();
- if (temper.Contains(combineGUID) == false)
- {
- _bundleInfoList.Add(bundleInfo);
- }
- }
- // 重新统计下载信息
- CalculatDownloaderInfo();
- }
- /// <summary>
- /// 开始下载
- /// </summary>
- public void BeginDownload()
- {
- if (_steps == ESteps.None)
- {
- OperationSystem.StartOperation(_packageName, this);
- }
- }
- /// <summary>
- /// 暂停下载
- /// </summary>
- public void PauseDownload()
- {
- _isPause = true;
- }
- /// <summary>
- /// 恢复下载
- /// </summary>
- public void ResumeDownload()
- {
- _isPause = false;
- }
- /// <summary>
- /// 取消下载
- /// </summary>
- public void CancelDownload()
- {
- if (_steps != ESteps.Done)
- {
- _steps = ESteps.Done;
- Status = EOperationStatus.Failed;
- Error = "User cancel.";
- foreach (var downloader in _downloaders)
- {
- downloader.Release();
- }
- }
- }
- }
- public sealed class ResourceDownloaderOperation : DownloaderOperation
- {
- internal ResourceDownloaderOperation(string packageName, List<BundleInfo> downloadList, int downloadingMaxNumber, int failedTryAgain, int timeout)
- : base(packageName, downloadList, downloadingMaxNumber, failedTryAgain, timeout)
- {
- }
- /// <summary>
- /// 创建空的下载器
- /// </summary>
- internal static ResourceDownloaderOperation CreateEmptyDownloader(string packageName, int downloadingMaxNumber, int failedTryAgain, int timeout)
- {
- List<BundleInfo> downloadList = new List<BundleInfo>();
- var operation = new ResourceDownloaderOperation(packageName, downloadList, downloadingMaxNumber, failedTryAgain, timeout);
- return operation;
- }
- }
- public sealed class ResourceUnpackerOperation : DownloaderOperation
- {
- internal ResourceUnpackerOperation(string packageName, List<BundleInfo> downloadList, int downloadingMaxNumber, int failedTryAgain, int timeout)
- : base(packageName, downloadList, downloadingMaxNumber, failedTryAgain, timeout)
- {
- }
- /// <summary>
- /// 创建空的解压器
- /// </summary>
- internal static ResourceUnpackerOperation CreateEmptyUnpacker(string packageName, int upackingMaxNumber, int failedTryAgain, int timeout)
- {
- List<BundleInfo> downloadList = new List<BundleInfo>();
- var operation = new ResourceUnpackerOperation(packageName, downloadList, upackingMaxNumber, failedTryAgain, int.MaxValue);
- return operation;
- }
- }
- public sealed class ResourceImporterOperation : DownloaderOperation
- {
- internal ResourceImporterOperation(string packageName, List<BundleInfo> downloadList, int downloadingMaxNumber, int failedTryAgain, int timeout)
- : base(packageName, downloadList, downloadingMaxNumber, failedTryAgain, timeout)
- {
- }
- /// <summary>
- /// 创建空的导入器
- /// </summary>
- internal static ResourceImporterOperation CreateEmptyImporter(string packageName, int upackingMaxNumber, int failedTryAgain, int timeout)
- {
- List<BundleInfo> downloadList = new List<BundleInfo>();
- var operation = new ResourceImporterOperation(packageName, downloadList, upackingMaxNumber, failedTryAgain, int.MaxValue);
- return operation;
- }
- }
- }
|