Update patch system

pull/4/head
hevinci 2022-03-03 18:07:20 +08:00
parent e112c061ac
commit 8521bbaaf7
8 changed files with 211 additions and 230 deletions

View File

@ -1,14 +0,0 @@

namespace YooAsset
{
/// <summary>
/// 下载状态
/// </summary>
public enum EDownloaderStates
{
None,
Loading,
Failed,
Succeed,
}
}

View File

@ -1,175 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 补丁下载器
/// </summary>
public class PatchDownloader : IEnumerator
{
private const int MAX_LOADER_COUNT = 64;
public delegate void OnDownloadOver(bool isSucceed);
public delegate void OnDownloadProgress(int totalDownloadCount, int currentDownloadCoun, long totalDownloadBytes, long currentDownloadBytes);
public delegate void OnPatchFileDownloadFailed(string fileName);
private readonly HostPlayModeImpl _playModeImpl;
private readonly int _fileLoadingMaxNumber;
private readonly int _failedTryAgain;
private readonly List<AssetBundleInfo> _downloadList;
private readonly List<AssetBundleInfo> _loadFailedList = new List<AssetBundleInfo>();
private readonly List<FileDownloader> _downloaders = new List<FileDownloader>();
private readonly List<FileDownloader> _removeList = new List<FileDownloader>(MAX_LOADER_COUNT);
// 数据相关
public EDownloaderStates DownloadStates { private set; get; }
public int TotalDownloadCount { private set; get; }
public long TotalDownloadBytes { private set; get; }
public int CurrentDownloadCount { private set; get; }
public long CurrentDownloadBytes { private set; get; }
private long _lastDownloadBytes = 0;
private int _lastDownloadCount = 0;
// 委托相关
public OnDownloadOver OnDownloadOverCallback { set; get; }
public OnDownloadProgress OnDownloadProgressCallback { set; get; }
public OnPatchFileDownloadFailed OnPatchFileDownloadFailedCallback { set; get; }
private PatchDownloader()
{
}
internal PatchDownloader(HostPlayModeImpl playModeImpl, List<AssetBundleInfo> downloadList, int fileLoadingMaxNumber, int failedTryAgain)
{
_playModeImpl = playModeImpl;
_downloadList = downloadList;
_fileLoadingMaxNumber = UnityEngine.Mathf.Clamp(fileLoadingMaxNumber, 1, MAX_LOADER_COUNT); ;
_failedTryAgain = failedTryAgain;
DownloadStates = EDownloaderStates.None;
TotalDownloadCount = downloadList.Count;
foreach (var patchBundle in downloadList)
{
TotalDownloadBytes += patchBundle.SizeBytes;
}
}
/// <summary>
/// 是否完毕,无论成功或失败
/// </summary>
public bool IsDone()
{
return DownloadStates == EDownloaderStates.Failed || DownloadStates == EDownloaderStates.Succeed;
}
/// <summary>
/// 开始下载
/// </summary>
public void Download()
{
if (DownloadStates != EDownloaderStates.None)
{
Logger.Warning($"{nameof(PatchDownloader)} is already running.");
return;
}
Logger.Log($"Begine to download : {TotalDownloadCount} files and {TotalDownloadBytes} bytes");
DownloadStates = EDownloaderStates.Loading;
}
/// <summary>
/// 更新下载器
/// </summary>
public void Update()
{
if (DownloadStates != EDownloaderStates.Loading)
return;
// 检测下载器结果
_removeList.Clear();
long downloadBytes = CurrentDownloadBytes;
foreach (var downloader in _downloaders)
{
downloadBytes += (long)downloader.DownloadedBytes;
if (downloader.IsDone() == false)
continue;
AssetBundleInfo bundleInfo = downloader.BundleInfo;
// 检测是否下载失败
if (downloader.HasError())
{
downloader.ReportError();
_removeList.Add(downloader);
_loadFailedList.Add(bundleInfo);
continue;
}
// 下载成功
_removeList.Add(downloader);
CurrentDownloadCount++;
CurrentDownloadBytes += bundleInfo.SizeBytes;
}
// 移除已经完成的下载器(无论成功或失败)
foreach (var loader in _removeList)
{
_downloaders.Remove(loader);
}
// 如果下载进度发生变化
if (_lastDownloadBytes != downloadBytes || _lastDownloadCount != CurrentDownloadCount)
{
_lastDownloadBytes = downloadBytes;
_lastDownloadCount = CurrentDownloadCount;
OnDownloadProgressCallback?.Invoke(TotalDownloadCount, _lastDownloadCount, TotalDownloadBytes, _lastDownloadBytes);
}
// 动态创建新的下载器到最大数量限制
// 注意:如果期间有下载失败的文件,暂停动态创建下载器
if (_downloadList.Count > 0 && _loadFailedList.Count == 0)
{
if (_downloaders.Count < _fileLoadingMaxNumber)
{
int index = _downloadList.Count - 1;
var operation = DownloadSystem.BeginDownload(_downloadList[index], _failedTryAgain);
_downloaders.Add(operation);
_downloadList.RemoveAt(index);
}
}
// 下载结算
if (_downloaders.Count == 0)
{
if (_loadFailedList.Count > 0)
{
DownloadStates = EDownloaderStates.Failed;
OnPatchFileDownloadFailedCallback?.Invoke(_loadFailedList[0].BundleName);
OnDownloadOverCallback?.Invoke(false);
}
else
{
// 结算成功
DownloadStates = EDownloaderStates.Succeed;
OnDownloadOverCallback?.Invoke(true);
}
}
}
#region 异步相关
bool IEnumerator.MoveNext()
{
return !IsDone();
}
void IEnumerator.Reset()
{
}
object IEnumerator.Current
{
get { return null; }
}
#endregion
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: e6483a640bdc429459305f148a863397
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,181 @@
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
public class DownloaderOperation : AsyncOperationBase
{
private enum ESteps
{
None,
Loading,
Done,
}
private const int MAX_LOADER_COUNT = 64;
public delegate void OnDownloadOver(bool isSucceed);
public delegate void OnDownloadProgress(int totalDownloadCount, int currentDownloadCoun, long totalDownloadBytes, long currentDownloadBytes);
public delegate void OnDownloadFileFailed(string fileName);
private readonly int _fileLoadingMaxNumber;
private readonly int _failedTryAgain;
private readonly List<AssetBundleInfo> _downloadList;
private readonly List<AssetBundleInfo> _loadFailedList = new List<AssetBundleInfo>();
private readonly List<FileDownloader> _downloaders = new List<FileDownloader>();
private readonly List<FileDownloader> _removeList = new List<FileDownloader>(MAX_LOADER_COUNT);
// 数据相关
private ESteps _steps = ESteps.None;
private long _lastDownloadBytes = 0;
private int _lastDownloadCount = 0;
/// <summary>
/// 下载文件总数量
/// </summary>
public int TotalDownloadCount { private set; get; }
/// <summary>
/// 下载文件的总大小
/// </summary>
public long TotalDownloadBytes { private set; get; }
/// <summary>
/// 当前已经完成的下载总数量
/// </summary>
public int CurrentDownloadCount { private set; get; }
/// <summary>
/// 当前已经完成的下载总大小
/// </summary>
public long CurrentDownloadBytes { private set; get; }
/// <summary>
/// 当下载器结束(无论成功或失败)
/// </summary>
public OnDownloadOver OnDownloadOverCallback { set; get; }
/// <summary>
/// 当下载进度变化
/// </summary>
public OnDownloadProgress OnDownloadProgressCallback { set; get; }
/// <summary>
/// 当文件下载失败
/// </summary>
public OnDownloadFileFailed OnDownloadFileFailedCallback { set; get; }
internal DownloaderOperation(List<AssetBundleInfo> downloadList, int fileLoadingMaxNumber, int failedTryAgain)
{
_downloadList = downloadList;
_fileLoadingMaxNumber = UnityEngine.Mathf.Clamp(fileLoadingMaxNumber, 1, MAX_LOADER_COUNT); ;
_failedTryAgain = failedTryAgain;
TotalDownloadCount = downloadList.Count;
foreach (var patchBundle in downloadList)
{
TotalDownloadBytes += patchBundle.SizeBytes;
}
}
internal override void Start()
{
Logger.Log($"Begine to download : {TotalDownloadCount} files and {TotalDownloadBytes} bytes");
_steps = ESteps.Loading;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.Loading)
{
// 检测下载器结果
_removeList.Clear();
long downloadBytes = CurrentDownloadBytes;
foreach (var downloader in _downloaders)
{
downloadBytes += (long)downloader.DownloadedBytes;
if (downloader.IsDone() == false)
continue;
AssetBundleInfo bundleInfo = downloader.BundleInfo;
// 检测是否下载失败
if (downloader.HasError())
{
downloader.ReportError();
_removeList.Add(downloader);
_loadFailedList.Add(bundleInfo);
continue;
}
// 下载成功
_removeList.Add(downloader);
CurrentDownloadCount++;
CurrentDownloadBytes += bundleInfo.SizeBytes;
}
// 移除已经完成的下载器(无论成功或失败)
foreach (var loader in _removeList)
{
_downloaders.Remove(loader);
}
// 如果下载进度发生变化
if (_lastDownloadBytes != downloadBytes || _lastDownloadCount != CurrentDownloadCount)
{
_lastDownloadBytes = downloadBytes;
_lastDownloadCount = CurrentDownloadCount;
OnDownloadProgressCallback?.Invoke(TotalDownloadCount, _lastDownloadCount, TotalDownloadBytes, _lastDownloadBytes);
}
// 动态创建新的下载器到最大数量限制
// 注意:如果期间有下载失败的文件,暂停动态创建下载器
if (_downloadList.Count > 0 && _loadFailedList.Count == 0)
{
if (_downloaders.Count < _fileLoadingMaxNumber)
{
int index = _downloadList.Count - 1;
var operation = DownloadSystem.BeginDownload(_downloadList[index], _failedTryAgain);
_downloaders.Add(operation);
_downloadList.RemoveAt(index);
}
}
// 下载结算
if (_downloaders.Count == 0)
{
if (_loadFailedList.Count > 0)
{
string fileName = _loadFailedList[0].BundleName;
Error = $"Failed to download file : {fileName}";
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
OnDownloadFileFailedCallback?.Invoke(fileName);
OnDownloadOverCallback?.Invoke(false);
}
else
{
// 结算成功
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
OnDownloadOverCallback?.Invoke(true);
}
}
}
}
/// <summary>
/// 开始下载
/// </summary>
public void BeginDownload()
{
if (_steps == ESteps.None)
{
OperationUpdater.ProcessOperaiton(this);
}
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: cb052d4c6ef18f54d9407cb48eafdfb9
guid: 96fc897d22c24d64b9faa531c0573c44
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -33,14 +33,14 @@ namespace YooAsset
{
private enum ESteps
{
Idle,
None,
LoadAppManifest,
CheckAppManifest,
Done,
}
private OfflinePlayModeImpl _impl;
private ESteps _steps = ESteps.Idle;
private ESteps _steps = ESteps.None;
private UnityWebRequester _downloader;
private string _downloadURL;
@ -54,7 +54,7 @@ namespace YooAsset
}
internal override void Update()
{
if (_steps == ESteps.Idle)
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadAppManifest)
@ -74,9 +74,9 @@ namespace YooAsset
if (_downloader.HasError())
{
Error = _downloader.GetError();
Status = EOperationStatus.Failed;
_downloader.Dispose();
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
throw new System.Exception($"Fatal error : Failed load application patch manifest file : {_downloadURL}");
}
@ -96,7 +96,7 @@ namespace YooAsset
{
private enum ESteps
{
Idle,
None,
InitCache,
LoadAppManifest,
CheckAppManifest,
@ -105,7 +105,7 @@ namespace YooAsset
}
private HostPlayModeImpl _impl;
private ESteps _steps = ESteps.Idle;
private ESteps _steps = ESteps.None;
private UnityWebRequester _downloader;
private string _downloadURL;
@ -119,7 +119,7 @@ namespace YooAsset
}
internal override void Update()
{
if (_steps == ESteps.Idle)
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.InitCache)
@ -133,7 +133,7 @@ namespace YooAsset
// 注意在覆盖安装的时候会保留APP沙盒目录可以选择清空缓存目录
if (_impl.ClearCacheWhenDirty)
{
Logger.Warning("Clear cache files.");
Logger.Warning("Clear cache files.");
PatchHelper.DeleteSandboxCacheFolder();
}
@ -164,9 +164,9 @@ namespace YooAsset
if (_downloader.HasError())
{
Error = _downloader.GetError();
Status = EOperationStatus.Failed;
_downloader.Dispose();
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
throw new System.Exception($"Fatal error : Failed load application patch manifest file : {_downloadURL}");
}

View File

@ -48,7 +48,7 @@ namespace YooAsset
{
private enum ESteps
{
Idle,
None,
LoadWebManifestHash,
CheckWebManifestHash,
LoadWebManifest,
@ -63,7 +63,7 @@ namespace YooAsset
private readonly HostPlayModeImpl _impl;
private readonly int _updateResourceVersion;
private readonly int _timeout;
private ESteps _steps = ESteps.Idle;
private ESteps _steps = ESteps.None;
private UnityWebRequester _downloaderHash;
private UnityWebRequester _downloaderManifest;
private float _verifyTime;
@ -90,7 +90,7 @@ namespace YooAsset
}
internal override void Update()
{
if (_steps == ESteps.Idle)
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadWebManifestHash)
@ -110,10 +110,10 @@ namespace YooAsset
// Check fatal
if (_downloaderHash.HasError())
{
Error = _downloaderHash.GetError();
Status = EOperationStatus.Failed;
Error = _downloaderHash.GetError();
_downloaderHash.Dispose();
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
return;
}
@ -152,10 +152,10 @@ namespace YooAsset
// Check fatal
if (_downloaderManifest.HasError())
{
Error = _downloaderManifest.GetError();
Status = EOperationStatus.Failed;
Error = _downloaderManifest.GetError();
_downloaderManifest.Dispose();
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
return;
}

View File

@ -63,15 +63,15 @@ namespace YooAsset
}
/// <summary>
/// 创建补丁下载器
/// 创建下载器
/// </summary>
public PatchDownloader CreateDLCDownloader(string[] dlcTags, int fileLoadingMaxNumber, int failedTryAgain)
public DownloaderOperation CreateDownloaderByTags(string[] tags, int fileLoadingMaxNumber, int failedTryAgain)
{
List<AssetBundleInfo> downloadList = GetDLCDownloadList(dlcTags);
PatchDownloader downlader = new PatchDownloader(this, downloadList, fileLoadingMaxNumber, failedTryAgain);
return downlader;
List<AssetBundleInfo> downloadList = GetDownloadListByTags(tags);
var operation = new DownloaderOperation(downloadList, fileLoadingMaxNumber, failedTryAgain);
return operation;
}
private List<AssetBundleInfo> GetDLCDownloadList(string[] dlcTags)
private List<AssetBundleInfo> GetDownloadListByTags(string[] tags)
{
List<PatchBundle> downloadList = new List<PatchBundle>(1000);
foreach (var patchBundle in LocalPatchManifest.BundleList)
@ -98,7 +98,7 @@ namespace YooAsset
else
{
// 查询DLC资源
if (patchBundle.HasTag(dlcTags))
if (patchBundle.HasTag(tags))
{
downloadList.Add(patchBundle);
}
@ -109,15 +109,15 @@ namespace YooAsset
}
/// <summary>
/// 创建补丁下载器
/// 创建下载器
/// </summary>
public PatchDownloader CreateBundleDownloader(List<string> assetPaths, int fileLoadingMaxNumber, int failedTryAgain)
public DownloaderOperation CreateDownloaderByPaths(List<string> assetPaths, int fileLoadingMaxNumber, int failedTryAgain)
{
List<AssetBundleInfo> downloadList = GetBundleDownloadList(assetPaths);
PatchDownloader downlader = new PatchDownloader(this, downloadList, fileLoadingMaxNumber, failedTryAgain);
return downlader;
List<AssetBundleInfo> downloadList = GetDownloadListByPaths(assetPaths);
var operation = new DownloaderOperation(downloadList, fileLoadingMaxNumber, failedTryAgain);
return operation;
}
private List<AssetBundleInfo> GetBundleDownloadList(List<string> assetPaths)
private List<AssetBundleInfo> GetDownloadListByPaths(List<string> assetPaths)
{
// 获取资源对象的资源包和所有依赖资源包
List<PatchBundle> checkList = new List<PatchBundle>();