VersionFlow/Assets/VersionFlow/Runtime/OptionalBundleDownloader.cs

168 lines
5.1 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace VersionFlow.Runtime
{
public class OptionalBundleDownloader
{
/// <summary> 总体积,字节数 </summary>
public ulong TotalSize { get; private set; }
private ulong m_downloadedBytes;
/// <summary> 已下载字节数 </summary>
public ulong DownloadedBytes
{
get
{
ulong downloadingBytes = 0;
if (m_downloadingAB != null && m_downloadingAB.IsDownloading)
{
downloadingBytes = m_downloadingAB.abAsyncDownloader.downloadingBytes;
}
return m_downloadedBytes + downloadingBytes;
}
set => m_downloadedBytes = value;
}
private ABEntity m_downloadingAB;
EnumDownloadState m_state;
/// <summary> 下载器状态 </summary>
public EnumDownloadState State
{
get => m_state;
set
{
if (m_state == value) return;
m_state = value;
OnStateChange?.Invoke();
}
}
public string Group { get; private set; }
private List<ABEntity> entities = new List<ABEntity>();
public Action OnStateChange;
public OptionalBundleDownloader(string group)
{
Group = group;
}
public void CollectAB(ABEntity abEntity)
{
entities.Add(abEntity);
}
internal void CalcState()
{
//收集依赖的AB
HashSet<ABEntity> temp = new HashSet<ABEntity>(entities);
foreach (var entity in entities)
{
foreach (var depAB in entity.m_dependencyAB)
temp.Add(depAB);
}
entities = temp.ToList();
foreach (var entity in entities)
{
TotalSize += (ulong)entity.m_manifestBundleInfo.Size;
if (entity.m_isDownloaded)
DownloadedBytes += (ulong)entity.m_manifestBundleInfo.Size;
}
if (DownloadedBytes == TotalSize)
State = EnumDownloadState.Complete;
else
State = EnumDownloadState.Idle;
}
private Coroutine m_downloadingFlow;
public void BeginDownload()
{
if (State == EnumDownloadState.Downloading || State == EnumDownloadState.Complete) return;
m_downloadingFlow = VersionFlowX.BeginCoroutine(DownloadFlow());
}
public void CancelDownload()
{
if (State != EnumDownloadState.Downloading) return;
if (m_downloadingFlow == null) return;
VersionFlowX.Stop(m_downloadingFlow);
if (m_downloadingAB != null && m_downloadingAB.IsDownloading)
{
m_downloadingAB.abAsyncDownloader.Cancel();
}
}
private IEnumerator DownloadFlow()
{
State = EnumDownloadState.Downloading;
while (true)
{
m_downloadingAB = entities.FirstOrDefault(ab => !ab.m_isDownloaded);
if (m_downloadingAB == null)
{
State = EnumDownloadState.Complete;
yield break;
}
if (m_downloadingAB.IsDownloading)
yield return new WaitUntil(() =>
{
return !m_downloadingAB.IsDownloading;
});
else
{
m_downloadingAB.abAsyncDownloader = VersionFlowX.DownloadBundleAsync(m_downloadingAB.m_manifestBundleInfo);
yield return m_downloadingAB.abAsyncDownloader;
if (m_downloadingAB.abAsyncDownloader.Success)
{
m_downloadingAB.m_isDownloaded = true;
m_downloadingAB.abAsyncDownloader = null;
}
else
{
var msg = m_downloadingAB.abAsyncDownloader.Error;
m_downloadingAB.abAsyncDownloader = null;
State = EnumDownloadState.Idle;
m_downloadingAB = null;
m_downloadingFlow = null;
throw new System.Exception($"下载 AB {this} 失败 \n {msg}");
}
}
DownloadedBytes += (ulong)m_downloadingAB.m_manifestBundleInfo.Size;
m_downloadingAB = null;
}
}
public static string GetByteSizeString(ulong byteCount)
{
if (byteCount < 1024) return $"{byteCount}B";
if (byteCount < 1024 * 1024) return $"{byteCount / (1024f):.00}KB";
else return $"{byteCount / (1024f * 1024):.00}MB";
}
public enum EnumDownloadState
{
Idle,
Downloading,
Complete
}
}
}