yoo2.2,9
This commit is contained in:
Alex-Rachel
2025-01-25 13:46:17 +08:00
parent 634a392a1f
commit 6166fd24c6
584 changed files with 15684 additions and 11714 deletions

View File

@@ -3,4 +3,5 @@
[assembly: InternalsVisibleTo("YooAsset.Editor")]
[assembly: InternalsVisibleTo("YooAsset.EditorExtension")]
[assembly: InternalsVisibleTo("YooAsset.RuntimeExtension")]
[assembly: InternalsVisibleTo("YooAsset.Test.Editor")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor")]

View File

@@ -1,19 +0,0 @@

namespace YooAsset
{
public class CacheFileInfo
{
public string RemoteFileName { private set; get; }
public string FilePath { private set; get; }
public string FileCRC { private set; get; }
public long FileSize { private set; get; }
public CacheFileInfo(string remoteFileName, string filePath, string fileCRC, long fileSize)
{
RemoteFileName = remoteFileName;
FilePath = filePath;
FileCRC = fileCRC;
FileSize = fileSize;
}
}
}

View File

@@ -1,132 +0,0 @@
using System;
using System.IO;
namespace YooAsset
{
internal static class CacheHelper
{
/// <summary>
/// 禁用Unity缓存系统在WebGL平台
/// </summary>
public static bool DisableUnityCacheOnWebGL = false;
#region
private static readonly BufferWriter SharedBuffer = new BufferWriter(1024);
/// <summary>
/// 写入资源包信息
/// </summary>
public static void WriteInfoToFile(string filePath, string dataFileCRC, long dataFileSize)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
SharedBuffer.Clear();
SharedBuffer.WriteUTF8(dataFileCRC);
SharedBuffer.WriteInt64(dataFileSize);
SharedBuffer.WriteToStream(fs);
fs.Flush();
}
}
/// <summary>
/// 读取资源包信息
/// </summary>
public static void ReadInfoFromFile(string filePath, out string dataFileCRC, out long dataFileSize)
{
byte[] binaryData = FileUtility.ReadAllBytes(filePath);
BufferReader buffer = new BufferReader(binaryData);
dataFileCRC = buffer.ReadUTF8();
dataFileSize = buffer.ReadInt64();
}
#endregion
#region
/// <summary>
/// 验证缓存文件(子线程内操作)
/// </summary>
public static EVerifyResult VerifyingCacheFile(VerifyCacheFileElement element, EVerifyLevel verifyLevel)
{
try
{
if (verifyLevel == EVerifyLevel.Low)
{
if (File.Exists(element.InfoFilePath) == false)
return EVerifyResult.InfoFileNotExisted;
if (File.Exists(element.DataFilePath) == false)
return EVerifyResult.DataFileNotExisted;
return EVerifyResult.Succeed;
}
else
{
if (File.Exists(element.InfoFilePath) == false)
return EVerifyResult.InfoFileNotExisted;
// 解析信息文件获取验证数据
CacheHelper.ReadInfoFromFile(element.InfoFilePath, out element.DataFileCRC, out element.DataFileSize);
}
}
catch (Exception)
{
return EVerifyResult.Exception;
}
return VerifyingInternal(element.DataFilePath, element.DataFileSize, element.DataFileCRC, verifyLevel);
}
/// <summary>
/// 验证下载文件(子线程内操作)
/// </summary>
public static EVerifyResult VerifyingTempFile(VerifyTempFileElement element)
{
return VerifyingInternal(element.TempDataFilePath, element.FileSize, element.FileCRC, EVerifyLevel.High);
}
/// <summary>
/// 验证记录文件(主线程内操作)
/// </summary>
public static EVerifyResult VerifyingRecordFile(CacheManager cache, string cacheGUID)
{
var wrapper = cache.TryGetWrapper(cacheGUID);
if (wrapper == null)
return EVerifyResult.CacheNotFound;
EVerifyResult result = VerifyingInternal(wrapper.DataFilePath, wrapper.DataFileSize, wrapper.DataFileCRC, EVerifyLevel.High);
return result;
}
private static EVerifyResult VerifyingInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
{
try
{
if (File.Exists(filePath) == false)
return EVerifyResult.DataFileNotExisted;
// 先验证文件大小
long size = FileUtility.GetFileSize(filePath);
if (size < fileSize)
return EVerifyResult.FileNotComplete;
else if (size > fileSize)
return EVerifyResult.FileOverflow;
// 再验证文件CRC
if (verifyLevel == EVerifyLevel.High)
{
string crc = HashUtility.FileCRC32Safely(filePath);
if (crc == fileCRC)
return EVerifyResult.Succeed;
else
return EVerifyResult.FileCrcError;
}
else
{
return EVerifyResult.Succeed;
}
}
catch (Exception)
{
return EVerifyResult.Exception;
}
}
#endregion
}
}

View File

@@ -1,136 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
internal class CacheManager
{
internal class RecordWrapper
{
public string InfoFilePath { private set; get; }
public string DataFilePath { private set; get; }
public string DataFileCRC { private set; get; }
public long DataFileSize { private set; get; }
public RecordWrapper(string infoFilePath, string dataFilePath, string dataFileCRC, long dataFileSize)
{
InfoFilePath = infoFilePath;
DataFilePath = dataFilePath;
DataFileCRC = dataFileCRC;
DataFileSize = dataFileSize;
}
}
private readonly Dictionary<string, RecordWrapper> _wrappers = new Dictionary<string, RecordWrapper>();
/// <summary>
/// 所属包裹
/// </summary>
public readonly string PackageName;
/// <summary>
/// 验证级别
/// </summary>
public readonly EVerifyLevel BootVerifyLevel;
public CacheManager(string packageName, EVerifyLevel bootVerifyLevel)
{
PackageName = packageName;
BootVerifyLevel = bootVerifyLevel;
}
/// <summary>
/// 清空所有数据
/// </summary>
public void ClearAll()
{
_wrappers.Clear();
}
/// <summary>
/// 查询缓存记录
/// </summary>
public bool IsCached(string cacheGUID)
{
return _wrappers.ContainsKey(cacheGUID);
}
/// <summary>
/// 记录验证结果
/// </summary>
public void Record(string cacheGUID, RecordWrapper wrapper)
{
if (_wrappers.ContainsKey(cacheGUID) == false)
{
_wrappers.Add(cacheGUID, wrapper);
}
else
{
throw new Exception("Should never get here !");
}
}
/// <summary>
/// 丢弃验证结果并删除缓存文件
/// </summary>
public void Discard(string cacheGUID)
{
var wrapper = TryGetWrapper(cacheGUID);
if (wrapper != null)
{
try
{
string dataFilePath = wrapper.DataFilePath;
FileInfo fileInfo = new FileInfo(dataFilePath);
if (fileInfo.Exists)
fileInfo.Directory.Delete(true);
}
catch (Exception e)
{
YooLogger.Error($"Failed to delete cache file ! {e.Message}");
}
}
if (_wrappers.ContainsKey(cacheGUID))
{
_wrappers.Remove(cacheGUID);
}
}
/// <summary>
/// 获取记录对象
/// </summary>
public RecordWrapper TryGetWrapper(string cacheGUID)
{
if (_wrappers.TryGetValue(cacheGUID, out RecordWrapper value))
return value;
else
return null;
}
/// <summary>
/// 获取缓存文件总数
/// </summary>
public int GetAllCachedFilesCount()
{
return _wrappers.Count;
}
/// <summary>
/// 获取缓存GUID集合
/// </summary>
public List<string> GetAllCachedGUIDs()
{
List<string> keys = new List<string>(_wrappers.Keys.Count);
var keyCollection = _wrappers.Keys;
foreach (var key in keyCollection)
{
keys.Add(key);
}
return keys;
}
}
}

View File

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

View File

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

View File

@@ -1,87 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace YooAsset
{
/// <summary>
/// 清理本地包裹未使用的缓存文件
/// </summary>
public sealed class ClearUnusedCacheFilesOperation : AsyncOperationBase
{
private enum ESteps
{
None,
GetUnusedCacheFiles,
ClearUnusedCacheFiles,
Done,
}
private readonly ResourcePackage _package;
private readonly CacheManager _cache;
private List<string> _unusedCacheGUIDs;
private int _unusedFileTotalCount = 0;
private ESteps _steps = ESteps.None;
internal ClearUnusedCacheFilesOperation(ResourcePackage package, CacheManager cache)
{
_package = package;
_cache = cache;
}
internal override void InternalOnStart()
{
_steps = ESteps.GetUnusedCacheFiles;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.GetUnusedCacheFiles)
{
_unusedCacheGUIDs = GetUnusedCacheGUIDs();
_unusedFileTotalCount = _unusedCacheGUIDs.Count;
YooLogger.Log($"Found unused cache file count : {_unusedFileTotalCount}");
_steps = ESteps.ClearUnusedCacheFiles;
}
if (_steps == ESteps.ClearUnusedCacheFiles)
{
for (int i = _unusedCacheGUIDs.Count - 1; i >= 0; i--)
{
string cacheGUID = _unusedCacheGUIDs[i];
_cache.Discard(cacheGUID);
_unusedCacheGUIDs.RemoveAt(i);
if (OperationSystem.IsBusy)
break;
}
if (_unusedFileTotalCount == 0)
Progress = 1.0f;
else
Progress = 1.0f - (_unusedCacheGUIDs.Count / _unusedFileTotalCount);
if (_unusedCacheGUIDs.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
private List<string> GetUnusedCacheGUIDs()
{
var allCacheGUIDs = _cache.GetAllCachedGUIDs();
List<string> result = new List<string>(allCacheGUIDs.Count);
foreach (var cacheGUID in allCacheGUIDs)
{
if (_package.IsIncludeBundleFile(cacheGUID) == false)
{
result.Add(cacheGUID);
}
}
return result;
}
}
}

View File

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

View File

@@ -1,99 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
public class GetAllCacheFileInfosOperation : AsyncOperationBase
{
private enum ESteps
{
None,
TryLoadCacheManifest,
GetCacheFileInfos,
Done,
}
private readonly PersistentManager _persistent;
private readonly CacheManager _cache;
private readonly string _packageVersion;
private LoadCacheManifestOperation _tryLoadCacheManifestOp;
private PackageManifest _manifest;
private ESteps _steps = ESteps.None;
private List<CacheFileInfo> _cacheFileInfos;
/// <summary>
/// 搜索结果
/// </summary>
public List<CacheFileInfo> Result
{
get { return _cacheFileInfos; }
}
internal GetAllCacheFileInfosOperation(PersistentManager persistent, CacheManager cache, string packageVersion)
{
_persistent = persistent;
_cache = cache;
_packageVersion = packageVersion;
}
internal override void InternalOnStart()
{
_steps = ESteps.TryLoadCacheManifest;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.TryLoadCacheManifest)
{
if (_tryLoadCacheManifestOp == null)
{
_tryLoadCacheManifestOp = new LoadCacheManifestOperation(_persistent, _packageVersion);
OperationSystem.StartOperation(_cache.PackageName, _tryLoadCacheManifestOp);
}
if (_tryLoadCacheManifestOp.IsDone == false)
return;
if (_tryLoadCacheManifestOp.Status == EOperationStatus.Succeed)
{
_manifest = _tryLoadCacheManifestOp.Manifest;
_steps = ESteps.GetCacheFileInfos;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _tryLoadCacheManifestOp.Error;
}
}
if (_steps == ESteps.GetCacheFileInfos)
{
var allCachedGUIDs = _cache.GetAllCachedGUIDs();
_cacheFileInfos = new List<CacheFileInfo>(allCachedGUIDs.Count);
for (int i = 0; i < allCachedGUIDs.Count; i++)
{
var cachedGUID = allCachedGUIDs[i];
var wrapper = _cache.TryGetWrapper(cachedGUID);
if (wrapper != null)
{
if (_manifest.TryGetPackageBundleByCacheGUID(cachedGUID, out var packageBundle))
{
var cacheFileInfo = new CacheFileInfo(packageBundle.FileName, wrapper.DataFilePath, wrapper.DataFileCRC, wrapper.DataFileSize);
_cacheFileInfos.Add(cacheFileInfo);
}
}
}
// 注意:总是返回成功
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
}

View File

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

View File

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

View File

@@ -1,254 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace YooAsset
{
internal abstract class VerifyCacheFilesOperation : AsyncOperationBase
{
public static VerifyCacheFilesOperation CreateOperation(CacheManager cache, List<VerifyCacheFileElement> elements)
{
#if UNITY_WEBGL
var operation = new VerifyCacheFilesWithoutThreadOperation(cache, elements);
#else
var operation = new VerifyCacheFilesWithThreadOperation(cache, elements);
#endif
return operation;
}
}
/// <summary>
/// 本地缓存文件验证(线程版)
/// </summary>
internal class VerifyCacheFilesWithThreadOperation : VerifyCacheFilesOperation
{
private enum ESteps
{
None,
InitVerify,
UpdateVerify,
Done,
}
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
private readonly CacheManager _cache;
private List<VerifyCacheFileElement> _waitingList;
private List<VerifyCacheFileElement> _verifyingList;
private int _verifyMaxNum;
private int _verifyTotalCount;
private float _verifyStartTime;
private int _succeedCount;
private int _failedCount;
private ESteps _steps = ESteps.None;
public VerifyCacheFilesWithThreadOperation(CacheManager cache, List<VerifyCacheFileElement> elements)
{
_cache = cache;
_waitingList = elements;
}
internal override void InternalOnStart()
{
_steps = ESteps.InitVerify;
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.InitVerify)
{
int fileCount = _waitingList.Count;
// 设置同时验证的最大数
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
_verifyMaxNum = Math.Min(workerThreads, ioThreads);
_verifyTotalCount = fileCount;
if (_verifyMaxNum < 1)
_verifyMaxNum = 1;
_verifyingList = new List<VerifyCacheFileElement>(_verifyMaxNum);
_steps = ESteps.UpdateVerify;
}
if (_steps == ESteps.UpdateVerify)
{
_syncContext.Update();
Progress = GetProgress();
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds");
}
for (int i = _waitingList.Count - 1; i >= 0; i--)
{
if (OperationSystem.IsBusy)
break;
if (_verifyingList.Count >= _verifyMaxNum)
break;
var element = _waitingList[i];
if (BeginVerifyFileWithThread(element))
{
_waitingList.RemoveAt(i);
_verifyingList.Add(element);
}
else
{
YooLogger.Warning("The thread pool is failed queued.");
break;
}
}
}
}
private float GetProgress()
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
}
private bool BeginVerifyFileWithThread(VerifyCacheFileElement element)
{
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
}
private void VerifyInThread(object obj)
{
VerifyCacheFileElement element = (VerifyCacheFileElement)obj;
element.Result = CacheHelper.VerifyingCacheFile(element, _cache.BootVerifyLevel);
_syncContext.Post(VerifyCallback, element);
}
private void VerifyCallback(object obj)
{
VerifyCacheFileElement element = (VerifyCacheFileElement)obj;
_verifyingList.Remove(element);
if (element.Result == EVerifyResult.Succeed)
{
_succeedCount++;
var wrapper = new CacheManager.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
_cache.Record(element.CacheGUID, wrapper);
}
else
{
_failedCount++;
YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
element.DeleteFiles();
}
}
}
/// <summary>
/// 本地缓存文件验证(非线程版)
/// </summary>
internal class VerifyCacheFilesWithoutThreadOperation : VerifyCacheFilesOperation
{
private enum ESteps
{
None,
InitVerify,
UpdateVerify,
Done,
}
private readonly CacheManager _cache;
private List<VerifyCacheFileElement> _waitingList;
private List<VerifyCacheFileElement> _verifyingList;
private int _verifyMaxNum;
private int _verifyTotalCount;
private float _verifyStartTime;
private int _succeedCount;
private int _failedCount;
private ESteps _steps = ESteps.None;
public VerifyCacheFilesWithoutThreadOperation(CacheManager cache, List<VerifyCacheFileElement> elements)
{
_cache = cache;
_waitingList = elements;
}
internal override void InternalOnStart()
{
_steps = ESteps.InitVerify;
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.InitVerify)
{
int fileCount = _waitingList.Count;
// 设置同时验证的最大数
_verifyMaxNum = fileCount;
_verifyTotalCount = fileCount;
_verifyingList = new List<VerifyCacheFileElement>(_verifyMaxNum);
_steps = ESteps.UpdateVerify;
}
if (_steps == ESteps.UpdateVerify)
{
Progress = GetProgress();
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
YooLogger.Log($"Package verify elapsed time {costTime:f1} seconds");
}
for (int i = _waitingList.Count - 1; i >= 0; i--)
{
if (OperationSystem.IsBusy)
break;
if (_verifyingList.Count >= _verifyMaxNum)
break;
var element = _waitingList[i];
BeginVerifyFileWithoutThread(element);
_waitingList.RemoveAt(i);
_verifyingList.Add(element);
}
// 主线程内验证,可以清空列表
_verifyingList.Clear();
}
}
private float GetProgress()
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
}
private void BeginVerifyFileWithoutThread(VerifyCacheFileElement element)
{
element.Result = CacheHelper.VerifyingCacheFile(element, _cache.BootVerifyLevel);
if (element.Result == EVerifyResult.Succeed)
{
_succeedCount++;
var wrapper = new CacheManager.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
_cache.Record(element.CacheGUID, wrapper);
}
else
{
_failedCount++;
YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
element.DeleteFiles();
}
}
}
}

View File

@@ -1,141 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace YooAsset
{
internal abstract class VerifyTempFileOperation : AsyncOperationBase
{
public EVerifyResult VerifyResult { protected set; get; }
public static VerifyTempFileOperation CreateOperation(VerifyTempFileElement element)
{
#if UNITY_WEBGL
var operation = new VerifyTempFileWithoutThreadOperation(element);
#else
var operation = new VerifyTempFileWithThreadOperation(element);
#endif
return operation;
}
}
/// <summary>
/// 下载文件验证(线程版)
/// </summary>
internal class VerifyTempFileWithThreadOperation : VerifyTempFileOperation
{
private enum ESteps
{
None,
VerifyFile,
Waiting,
Done,
}
private readonly VerifyTempFileElement _element;
private ESteps _steps = ESteps.None;
public VerifyTempFileWithThreadOperation(VerifyTempFileElement element)
{
_element = element;
}
internal override void InternalOnStart()
{
_steps = ESteps.VerifyFile;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.VerifyFile)
{
if (BeginVerifyFileWithThread(_element))
{
_steps = ESteps.Waiting;
}
}
if (_steps == ESteps.Waiting)
{
int result = _element.Result;
if (result == 0)
return;
VerifyResult = (EVerifyResult)result;
if (VerifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {VerifyResult}";
}
}
}
private bool BeginVerifyFileWithThread(VerifyTempFileElement element)
{
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
}
private void VerifyInThread(object obj)
{
VerifyTempFileElement element = (VerifyTempFileElement)obj;
int result = (int)CacheHelper.VerifyingTempFile(element);
element.Result = result;
}
}
/// <summary>
/// 下载文件验证(非线程版)
/// </summary>
internal class VerifyTempFileWithoutThreadOperation : VerifyTempFileOperation
{
private enum ESteps
{
None,
VerifyFile,
Done,
}
private readonly VerifyTempFileElement _element;
private ESteps _steps = ESteps.None;
public VerifyTempFileWithoutThreadOperation(VerifyTempFileElement element)
{
_element = element;
}
internal override void InternalOnStart()
{
_steps = ESteps.VerifyFile;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.VerifyFile)
{
_element.Result = (int)CacheHelper.VerifyingTempFile(_element);
VerifyResult = (EVerifyResult)_element.Result;
if (VerifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {VerifyResult}";
}
}
}
}
}

View File

@@ -1,74 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
internal class PackageCachingOperation : AsyncOperationBase
{
private enum ESteps
{
None,
FindCacheFiles,
VerifyCacheFiles,
Done,
}
private readonly PersistentManager _persistent;
private readonly CacheManager _cache;
private FindCacheFilesOperation _findCacheFilesOp;
private VerifyCacheFilesOperation _verifyCacheFilesOp;
private ESteps _steps = ESteps.None;
public PackageCachingOperation(PersistentManager persistent, CacheManager cache)
{
_persistent = persistent;
_cache = cache;
}
internal override void InternalOnStart()
{
_steps = ESteps.FindCacheFiles;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.FindCacheFiles)
{
if (_findCacheFilesOp == null)
{
_findCacheFilesOp = new FindCacheFilesOperation(_persistent, _cache);
OperationSystem.StartOperation(_cache.PackageName, _findCacheFilesOp);
}
Progress = _findCacheFilesOp.Progress;
if (_findCacheFilesOp.IsDone == false)
return;
_steps = ESteps.VerifyCacheFiles;
}
if (_steps == ESteps.VerifyCacheFiles)
{
if (_verifyCacheFilesOp == null)
{
_verifyCacheFilesOp = VerifyCacheFilesOperation.CreateOperation(_cache, _findCacheFilesOp.VerifyElements);
OperationSystem.StartOperation(_cache.PackageName, _verifyCacheFilesOp);
}
Progress = _verifyCacheFilesOp.Progress;
if (_verifyCacheFilesOp.IsDone == false)
return;
// 注意:总是返回成功
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
int totalCount = _cache.GetAllCachedFilesCount();
YooLogger.Log($"Package '{_cache.PackageName}' cached files count : {totalCount}");
}
}
}
}

View File

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

View File

@@ -1,33 +0,0 @@

namespace YooAsset
{
internal static class PersistentHelper
{
/// <summary>
/// 获取WWW加载本地资源的路径
/// </summary>
public static string ConvertToWWWPath(string path)
{
#if UNITY_EDITOR
return StringUtility.Format("file:///{0}", path);
#elif UNITY_WEBGL
return path;
#elif UNITY_IPHONE
return StringUtility.Format("file://{0}", path);
#elif UNITY_ANDROID
if (path.StartsWith("jar:file://"))
return path;
else
return StringUtility.Format("jar:file://{0}", path);
#elif UNITY_STANDALONE_OSX
return new System.Uri(path).ToString();
#elif UNITY_STANDALONE
return StringUtility.Format("file:///{0}", path);
#elif UNITY_OPENHARMONY
return path;
#else
return path;
#endif
}
}
}

View File

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

View File

@@ -1,217 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
internal class PersistentManager
{
private readonly Dictionary<string, string> _cachedDataFilePaths = new Dictionary<string, string>(10000);
private readonly Dictionary<string, string> _cachedInfoFilePaths = new Dictionary<string, string>(10000);
private readonly Dictionary<string, string> _tempDataFilePaths = new Dictionary<string, string>(10000);
private readonly Dictionary<string, string> _buildinFilePaths = new Dictionary<string, string>(10000);
/// <summary>
/// 所属包裹
/// </summary>
public readonly string PackageName;
public string BuildinRoot { private set; get; }
public string BuildinPackageRoot { private set; get; }
public string SandboxRoot { private set; get; }
public string SandboxPackageRoot { private set; get; }
public string SandboxCacheFilesRoot { private set; get; }
public string SandboxManifestFilesRoot { private set; get; }
public string SandboxAppFootPrintFilePath { private set; get; }
public bool AppendFileExtension { private set; get; }
public PersistentManager(string packageName)
{
PackageName = packageName;
}
/// <summary>
/// 初始化
/// </summary>
public void Initialize(string buildinRoot, string sandboxRoot, bool appendFileExtension)
{
if (string.IsNullOrEmpty(buildinRoot))
BuildinRoot = CreateDefaultBuildinRoot();
else
BuildinRoot = buildinRoot;
if (string.IsNullOrEmpty(sandboxRoot))
SandboxRoot = CreateDefaultSandboxRoot();
else
SandboxRoot = sandboxRoot;
BuildinPackageRoot = PathUtility.Combine(BuildinRoot, PackageName);
SandboxPackageRoot = PathUtility.Combine(SandboxRoot, PackageName);
SandboxCacheFilesRoot = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.CacheFilesFolderName);
SandboxManifestFilesRoot = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.ManifestFolderName);
SandboxAppFootPrintFilePath = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.AppFootPrintFileName);
AppendFileExtension = appendFileExtension;
}
private static string CreateDefaultBuildinRoot()
{
string path = PathUtility.Combine(UnityEngine.Application.streamingAssetsPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#if UNITY_OPENHARMONY
return $"file://{path}";
#else
return path;
#endif
}
private static string CreateDefaultSandboxRoot()
{
#if UNITY_EDITOR
// 注意:为了方便调试查看,编辑器下把存储目录放到项目里。
string projectPath = Path.GetDirectoryName(UnityEngine.Application.dataPath);
projectPath = PathUtility.RegularPath(projectPath);
return PathUtility.Combine(projectPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#elif UNITY_STANDALONE
return PathUtility.Combine(UnityEngine.Application.dataPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#else
return PathUtility.Combine(UnityEngine.Application.persistentDataPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#endif
}
public string GetCachedDataFilePath(PackageBundle bundle)
{
if (_cachedDataFilePaths.TryGetValue(bundle.CacheGUID, out string filePath) == false)
{
string folderName = bundle.FileHash.Substring(0, 2);
filePath = PathUtility.Combine(SandboxCacheFilesRoot, folderName, bundle.CacheGUID, YooAssetSettings.CacheBundleDataFileName);
if (AppendFileExtension)
filePath += bundle.FileExtension;
_cachedDataFilePaths.Add(bundle.CacheGUID, filePath);
}
return filePath;
}
public string GetCachedInfoFilePath(PackageBundle bundle)
{
if (_cachedInfoFilePaths.TryGetValue(bundle.CacheGUID, out string filePath) == false)
{
string folderName = bundle.FileHash.Substring(0, 2);
filePath = PathUtility.Combine(SandboxCacheFilesRoot, folderName, bundle.CacheGUID, YooAssetSettings.CacheBundleInfoFileName);
_cachedInfoFilePaths.Add(bundle.CacheGUID, filePath);
}
return filePath;
}
public string GetTempDataFilePath(PackageBundle bundle)
{
if (_tempDataFilePaths.TryGetValue(bundle.CacheGUID, out string filePath) == false)
{
string cachedDataFilePath = GetCachedDataFilePath(bundle);
filePath = $"{cachedDataFilePath}.temp";
_tempDataFilePaths.Add(bundle.CacheGUID, filePath);
}
return filePath;
}
public string GetBuildinFilePath(PackageBundle bundle)
{
if (_buildinFilePaths.TryGetValue(bundle.CacheGUID, out string filePath) == false)
{
filePath = PathUtility.Combine(BuildinPackageRoot, bundle.FileName);
_buildinFilePaths.Add(bundle.CacheGUID, filePath);
}
return filePath;
}
/// <summary>
/// 删除沙盒里的包裹目录
/// </summary>
public void DeleteSandboxPackageFolder()
{
if (Directory.Exists(SandboxPackageRoot))
Directory.Delete(SandboxPackageRoot, true);
}
/// <summary>
/// 删除沙盒内的缓存文件夹
/// </summary>
public void DeleteSandboxCacheFilesFolder()
{
if (Directory.Exists(SandboxCacheFilesRoot))
Directory.Delete(SandboxCacheFilesRoot, true);
}
/// <summary>
/// 删除沙盒内的清单文件夹
/// </summary>
public void DeleteSandboxManifestFilesFolder()
{
if (Directory.Exists(SandboxManifestFilesRoot))
Directory.Delete(SandboxManifestFilesRoot, true);
}
/// <summary>
/// 获取沙盒内包裹的清单文件的路径
/// </summary>
public string GetSandboxPackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
return PathUtility.Combine(SandboxManifestFilesRoot, fileName);
}
/// <summary>
/// 获取沙盒内包裹的哈希文件的路径
/// </summary>
public string GetSandboxPackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(PackageName, packageVersion);
return PathUtility.Combine(SandboxManifestFilesRoot, fileName);
}
/// <summary>
/// 获取沙盒内包裹的版本文件的路径
/// </summary>
public string GetSandboxPackageVersionFilePath()
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(PackageName);
return PathUtility.Combine(SandboxManifestFilesRoot, fileName);
}
/// <summary>
/// 保存沙盒内默认的包裹版本
/// </summary>
public void SaveSandboxPackageVersionFile(string version)
{
YooLogger.Log($"Save package version : {version}");
string filePath = GetSandboxPackageVersionFilePath();
FileUtility.WriteAllText(filePath, version);
}
/// <summary>
/// 获取APP内包裹的清单文件的路径
/// </summary>
public string GetBuildinPackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
return PathUtility.Combine(BuildinPackageRoot, fileName);
}
/// <summary>
/// 获取APP内包裹的哈希文件的路径
/// </summary>
public string GetBuildinPackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(PackageName, packageVersion);
return PathUtility.Combine(BuildinPackageRoot, fileName);
}
/// <summary>
/// 获取APP内包裹的版本文件的路径
/// </summary>
public string GetBuildinPackageVersionFilePath()
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(PackageName);
return PathUtility.Combine(BuildinPackageRoot, fileName);
}
}
}

View File

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

View File

@@ -1,60 +0,0 @@
using System.IO;
namespace YooAsset
{
/// <summary>
/// 缓存文件验证元素
/// </summary>
internal class VerifyCacheFileElement
{
public string PackageName { private set; get; }
public string CacheGUID { private set; get; }
public string FileRootPath { private set; get; }
public string DataFilePath { private set; get; }
public string InfoFilePath { private set; get; }
public EVerifyResult Result;
public string DataFileCRC;
public long DataFileSize;
public VerifyCacheFileElement(string packageName, string cacheGUID, string fileRootPath, string dataFilePath, string infoFilePath)
{
PackageName = packageName;
CacheGUID = cacheGUID;
FileRootPath = fileRootPath;
DataFilePath = dataFilePath;
InfoFilePath = infoFilePath;
}
public void DeleteFiles()
{
try
{
Directory.Delete(FileRootPath, true);
}
catch (System.Exception e)
{
YooLogger.Warning($"Failed delete cache bundle folder : {e}");
}
}
}
/// <summary>
/// 下载文件验证元素
/// </summary>
internal class VerifyTempFileElement
{
public string TempDataFilePath { private set; get; }
public string FileCRC { private set; get; }
public long FileSize { private set; get; }
public int Result = 0; // 注意:原子操作对象
public VerifyTempFileElement(string tempDataFilePath, string fileCRC, long fileSize)
{
TempDataFilePath = tempDataFilePath;
FileCRC = fileCRC;
FileSize = fileSize;
}
}
}

View File

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

View File

@@ -25,7 +25,7 @@ namespace YooAsset
/// <summary>
/// 加载状态
/// </summary>
public string Status;
public EOperationStatus Status;
public int CompareTo(DebugBundleInfo other)
{

View File

@@ -0,0 +1,97 @@

namespace YooAsset
{
/// <summary>
/// 下载器结束
/// </summary>
public struct DownloaderFinishData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 是否成功
/// </summary>
public bool Succeed;
}
/// <summary>
/// 下载器相关的更新数据
/// </summary>
public struct DownloadUpdateData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 下载进度 (0-1f)
/// </summary>
public float Progress;
/// <summary>
/// 下载文件总数
/// </summary>
public int TotalDownloadCount;
/// <summary>
/// 当前完成的下载文件数量
/// </summary>
public int CurrentDownloadCount;
/// <summary>
/// 下载数据总大小(单位:字节)
/// </summary>
public long TotalDownloadBytes;
/// <summary>
/// 当前完成的下载数据大小(单位:字节)
/// </summary>
public long CurrentDownloadBytes;
}
/// <summary>
/// 下载器相关的错误数据
/// </summary>
public struct DownloadErrorData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 下载失败的文件名称
/// </summary>
public string FileName;
/// <summary>
/// 错误信息
/// </summary>
public string ErrorInfo;
}
/// <summary>
/// 下载器相关的文件数据
/// </summary>
public struct DownloadFileData
{
/// <summary>
/// 所属包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 下载的文件名称
/// </summary>
public string FileName;
/// <summary>
/// 下载的文件大小
/// </summary>
public long FileSize;
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 02ad351eb8539da47a0c789e2f8c468f
guid: 6602c4be2ef295546b7bbb328de8fb0c
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,41 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// 自定义下载器的请求委托
/// </summary>
public delegate UnityWebRequest DownloadRequestDelegate(string url);
internal static class DownloadHelper
{
/// <summary>
/// 下载失败后清理文件的HTTP错误码
/// </summary>
public static List<long> ClearFileResponseCodes { set; get; }
/// <summary>
/// 自定义下载器的请求委托
/// </summary>
public static DownloadRequestDelegate RequestDelegate = null;
/// <summary>
/// 创建一个新的网络请求
/// </summary>
public static UnityWebRequest NewRequest(string requestURL)
{
UnityWebRequest webRequest;
if (RequestDelegate != null)
webRequest = RequestDelegate.Invoke(requestURL);
else
webRequest = new UnityWebRequest(requestURL, UnityWebRequest.kHttpVerbGET);
return webRequest;
}
}
}

View File

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

View File

@@ -1,150 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// 1. 保证每一时刻资源文件只存在一个下载器
/// 2. 保证下载器下载完成后立刻验证并缓存
/// 3. 保证资源文件不会被重复下载
/// </summary>
internal class DownloadManager
{
private readonly Dictionary<string, DownloaderBase> _downloaders = new Dictionary<string, DownloaderBase>(1000);
private readonly List<string> _removeList = new List<string>(1000);
private uint _breakpointResumeFileSize;
/// <summary>
/// 所属包裹
/// </summary>
public readonly string PackageName;
public DownloadManager(string packageName)
{
PackageName = packageName;
}
/// <summary>
/// 初始化
/// </summary>
public void Initialize(uint breakpointResumeFileSize)
{
_breakpointResumeFileSize = breakpointResumeFileSize;
}
/// <summary>
/// 更新下载器
/// </summary>
public void Update()
{
// 更新下载器
_removeList.Clear();
foreach (var valuePair in _downloaders)
{
var downloader = valuePair.Value;
downloader.Update();
if (downloader.IsDone())
{
_removeList.Add(valuePair.Key);
}
}
// 移除下载器
foreach (var key in _removeList)
{
_downloaders.Remove(key);
}
}
/// <summary>
/// 销毁所有下载器
/// </summary>
public void DestroyAll()
{
foreach (var valuePair in _downloaders)
{
var downloader = valuePair.Value;
downloader.Abort();
}
_downloaders.Clear();
_removeList.Clear();
}
/// <summary>
/// 创建下载器
/// 注意:只有第一次请求的参数才有效
/// </summary>
public DownloaderBase CreateDownload(BundleInfo bundleInfo, int failedTryAgain, int timeout = 60)
{
// 查询存在的下载器
if (_downloaders.TryGetValue(bundleInfo.CachedDataFilePath, out var downloader))
{
downloader.Reference();
return downloader;
}
// 如果资源已经缓存
if (bundleInfo.IsCached())
{
var completedDownloader = new CompletedDownloader(bundleInfo);
return completedDownloader;
}
// 创建新的下载器
DownloaderBase newDownloader = null;
YooLogger.Log($"Beginning to download bundle : {bundleInfo.Bundle.BundleName} URL : {bundleInfo.RemoteMainURL}");
#if UNITY_WEBGL
if (bundleInfo.Bundle.Buildpipeline == EDefaultBuildPipeline.RawFileBuildPipeline.ToString())
{
FileUtility.CreateFileDirectory(bundleInfo.CachedDataFilePath);
System.Type requesterType = typeof(FileGeneralRequest);
newDownloader = new FileDownloader(bundleInfo, requesterType, failedTryAgain, timeout);
}
else
{
System.Type requesterType = typeof(AssetBundleWebRequest);
newDownloader = new WebDownloader(bundleInfo, requesterType, failedTryAgain, timeout);
}
#else
FileUtility.CreateFileDirectory(bundleInfo.CachedDataFilePath);
bool resumeDownload = bundleInfo.Bundle.FileSize >= _breakpointResumeFileSize;
if (resumeDownload)
{
System.Type requesterType = typeof(FileResumeRequest);
newDownloader = new FileDownloader(bundleInfo, requesterType, failedTryAgain, timeout);
}
else
{
System.Type requesterType = typeof(FileGeneralRequest);
newDownloader = new FileDownloader(bundleInfo, requesterType, failedTryAgain, timeout);
}
#endif
// 返回新创建的下载器
_downloaders.Add(bundleInfo.CachedDataFilePath, newDownloader);
newDownloader.Reference();
return newDownloader;
}
/// <summary>
/// 停止不再使用的下载器
/// </summary>
public void AbortUnusedDownloader()
{
foreach (var valuePair in _downloaders)
{
var downloader = valuePair.Value;
if (downloader.RefCount <= 0)
{
downloader.Abort();
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,30 @@

namespace YooAsset
{
internal class DownloadParam
{
public readonly int FailedTryAgain;
public readonly int Timeout;
/// <summary>
/// 导入的本地文件路径
/// </summary>
public string ImportFilePath { set; get; }
/// <summary>
/// 主资源地址
/// </summary>
public string MainURL { set; get; }
/// <summary>
/// 备用资源地址
/// </summary>
public string FallbackURL { set; get; }
public DownloadParam(int failedTryAgain, int timeout)
{
FailedTryAgain = failedTryAgain;
Timeout = timeout;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 8616c7550a7890141af598898a12df1b
guid: 56ea224b45d314e4a86b558404e9b6c8
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,83 @@
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// 自定义下载器的请求委托
/// </summary>
public delegate UnityWebRequest UnityWebRequestDelegate(string url);
internal class DownloadSystemHelper
{
public static UnityWebRequestDelegate UnityWebRequestCreater = null;
public static UnityWebRequest NewUnityWebRequestGet(string requestURL)
{
UnityWebRequest webRequest;
if (UnityWebRequestCreater != null)
webRequest = UnityWebRequestCreater.Invoke(requestURL);
else
webRequest = new UnityWebRequest(requestURL, UnityWebRequest.kHttpVerbGET);
return webRequest;
}
/// <summary>
/// 获取WWW加载本地资源的路径
/// </summary>
public static string ConvertToWWWPath(string path)
{
string url;
// 获取对应平台的URL地址
#if UNITY_EDITOR
url = StringUtility.Format("file:///{0}", path);
#elif UNITY_WEBGL
url = path;
#elif UNITY_IPHONE
url = StringUtility.Format("file://{0}", path);
#elif UNITY_ANDROID
if (path.StartsWith("jar:file://"))
url = path;
else
url = StringUtility.Format("jar:file://{0}", path);
#elif UNITY_OPENHARMONY
if (UnityEngine.Application.streamingAssetsPath.StartsWith("jar:file://"))
{
if (path.StartsWith("jar:file://"))
url = path;
else
url = StringUtility.Format("jar:file://{0}", path);
}
else
{
if (path.StartsWith("file://"))
url = path;
else
url = StringUtility.Format("file://{0}", path);
}
#elif UNITY_STANDALONE_OSX
url = new System.Uri(path).ToString();
#elif UNITY_STANDALONE
url = StringUtility.Format("file:///{0}", path);
#else
throw new System.NotImplementedException();
#endif
// For some special cases when users have special characters in their devices, url paths can not be identified correctly.
return url.Replace("+", "%2B").Replace("#", "%23").Replace("?", "%3F");
}
/// <summary>
/// 是否请求的本地文件
/// </summary>
public static bool IsRequestLocalFile(string url)
{
//TODO UNITY_STANDALONE_OSX平台目前无法确定
if (url.StartsWith("file:"))
return true;
if (url.StartsWith("jar:file:"))
return true;
return false;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e4a97c06e069c1146a881fcb359f9b4b
guid: 5bacfa8c42e283a45a2d21cbb93d6e5d
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,28 +0,0 @@
using UnityEngine;
namespace YooAsset
{
internal sealed class CompletedDownloader : DownloaderBase
{
public CompletedDownloader(BundleInfo bundleInfo) : base(bundleInfo, null, 0, 0)
{
DownloadProgress = 1f;
DownloadedBytes = (ulong)bundleInfo.Bundle.FileSize;
_status = EStatus.Succeed;
}
public override void SendRequest(params object[] param)
{
}
public override void Update()
{
}
public override void Abort()
{
}
public override AssetBundle GetAssetBundle()
{
throw new System.NotImplementedException();
}
}
}

View File

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

View File

@@ -1,182 +0,0 @@
using System;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal abstract class DownloaderBase
{
public enum EStatus
{
None = 0,
Succeed,
Failed
}
protected readonly BundleInfo _bundleInfo;
protected readonly System.Type _requesterType;
protected readonly int _timeout;
protected int _failedTryAgain;
protected IWebRequester _requester;
protected EStatus _status = EStatus.None;
protected string _lastestNetError = string.Empty;
protected long _lastestHttpCode = 0;
// 请求次数
protected int _requestCount = 0;
protected string _requestURL;
// 超时相关
protected bool _isAbort = false;
protected ulong _latestDownloadBytes;
protected float _latestDownloadRealtime;
protected float _tryAgainTimer;
/// <summary>
/// 是否等待异步结束
/// 警告只能用于解压APP内部资源
/// </summary>
public bool WaitForAsyncComplete = false;
/// <summary>
/// 下载进度0f~1f
/// </summary>
public float DownloadProgress { protected set; get; }
/// <summary>
/// 已经下载的总字节数
/// </summary>
public ulong DownloadedBytes { protected set; get; }
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; }
public DownloaderBase(BundleInfo bundleInfo, System.Type requesterType, int failedTryAgain, int timeout)
{
_bundleInfo = bundleInfo;
_requesterType = requesterType;
_failedTryAgain = failedTryAgain;
_timeout = timeout;
}
public abstract void SendRequest(params object[] args);
public abstract void Update();
public abstract void Abort();
public abstract AssetBundle GetAssetBundle();
/// <summary>
/// 引用(引用计数递加)
/// </summary>
public void Reference()
{
RefCount++;
}
/// <summary>
/// 释放(引用计数递减)
/// </summary>
public void Release()
{
RefCount--;
}
/// <summary>
/// 检测下载器是否已经完成(无论成功或失败)
/// </summary>
public bool IsDone()
{
return _status == EStatus.Succeed || _status == EStatus.Failed;
}
/// <summary>
/// 下载过程是否发生错误
/// </summary>
public bool HasError()
{
return _status == EStatus.Failed;
}
/// <summary>
/// 按照错误级别打印错误
/// </summary>
public void ReportError()
{
YooLogger.Error(GetLastError());
}
/// <summary>
/// 按照警告级别打印错误
/// </summary>
public void ReportWarning()
{
YooLogger.Warning(GetLastError());
}
/// <summary>
/// 获取最近发生的错误信息
/// </summary>
public string GetLastError()
{
return $"Failed to download : {_requestURL} Error : {_lastestNetError} Code : {_lastestHttpCode}";
}
/// <summary>
/// 获取下载文件的大小
/// </summary>
/// <returns></returns>
public long GetDownloadFileSize()
{
return _bundleInfo.Bundle.FileSize;
}
/// <summary>
/// 获取下载的资源包名称
/// </summary>
public string GetDownloadBundleName()
{
return _bundleInfo.Bundle.BundleName;
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _bundleInfo.RemoteFallbackURL;
else
return _bundleInfo.RemoteMainURL;
}
/// <summary>
/// 超时判定方法
/// </summary>
protected void CheckTimeout()
{
// 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false)
{
if (_latestDownloadBytes != DownloadedBytes)
{
_latestDownloadBytes = DownloadedBytes;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
float offset = Time.realtimeSinceStartup - _latestDownloadRealtime;
if (offset > _timeout)
{
YooLogger.Warning($"Web file request timeout : {_requestURL}");
if (_requester != null)
_requester.Abort();
_isAbort = true;
}
}
}
}
}

View File

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

View File

@@ -1,216 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 文件下载器
/// </summary>
internal sealed class FileDownloader : DownloaderBase
{
private enum ESteps
{
None,
PrepareDownload,
CreateDownloader,
CheckDownload,
VerifyTempFile,
WaitingVerifyTempFile,
CachingFile,
TryAgain,
Done,
}
private VerifyTempFileOperation _verifyFileOp = null;
private ESteps _steps = ESteps.None;
public FileDownloader(BundleInfo bundleInfo, System.Type requesterType, int failedTryAgain, int timeout) : base(bundleInfo, requesterType, failedTryAgain, timeout)
{
}
public override void SendRequest(params object[] args)
{
if (_steps == ESteps.None)
{
_steps = ESteps.PrepareDownload;
}
}
public override void Update()
{
if (_steps == ESteps.None)
return;
if (IsDone())
return;
// 准备下载
if (_steps == ESteps.PrepareDownload)
{
// 获取请求地址
_requestURL = GetRequestURL();
// 重置变量
DownloadProgress = 0f;
DownloadedBytes = 0;
// 重置变量
_isAbort = false;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
// 重置计时器
if (_tryAgainTimer > 0f)
YooLogger.Warning($"Try again download : {_requestURL}");
_tryAgainTimer = 0f;
_steps = ESteps.CreateDownloader;
}
// 创建下载器
if (_steps == ESteps.CreateDownloader)
{
_requester = (IWebRequester)Activator.CreateInstance(_requesterType);
_requester.Create(_requestURL, _bundleInfo);
_steps = ESteps.CheckDownload;
}
// 检测下载结果
if (_steps == ESteps.CheckDownload)
{
_requester.Update();
DownloadedBytes = _requester.DownloadedBytes;
DownloadProgress = _requester.DownloadProgress;
if (_requester.IsDone() == false)
{
CheckTimeout();
return;
}
_lastestNetError = _requester.RequestNetError;
_lastestHttpCode = _requester.RequestHttpCode;
if (_requester.Status != ERequestStatus.Success)
{
_steps = ESteps.TryAgain;
}
else
{
_steps = ESteps.VerifyTempFile;
}
}
// 验证下载文件
if (_steps == ESteps.VerifyTempFile)
{
VerifyTempFileElement element = new VerifyTempFileElement(_bundleInfo.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
_verifyFileOp = VerifyTempFileOperation.CreateOperation(element);
OperationSystem.StartOperation(_bundleInfo.Bundle.PackageName, _verifyFileOp);
_steps = ESteps.WaitingVerifyTempFile;
}
// 等待验证完成
if (_steps == ESteps.WaitingVerifyTempFile)
{
if (WaitForAsyncComplete)
_verifyFileOp.InternalOnUpdate();
if (_verifyFileOp.IsDone == false)
return;
if (_verifyFileOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.CachingFile;
}
else
{
string tempFilePath = _bundleInfo.TempDataFilePath;
if (File.Exists(tempFilePath))
File.Delete(tempFilePath);
_lastestNetError = _verifyFileOp.Error;
_steps = ESteps.TryAgain;
}
}
// 缓存下载文件
if (_steps == ESteps.CachingFile)
{
try
{
CachingFile();
_status = EStatus.Succeed;
_steps = ESteps.Done;
}
catch (Exception e)
{
_lastestNetError = e.Message;
_steps = ESteps.TryAgain;
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
if (_failedTryAgain <= 0)
{
ReportError();
_status = EStatus.Failed;
_steps = ESteps.Done;
return;
}
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_failedTryAgain--;
_steps = ESteps.PrepareDownload;
ReportWarning();
}
}
}
public override void Abort()
{
if (_requester != null)
_requester.Abort();
if (IsDone() == false)
{
_status = EStatus.Failed;
_steps = ESteps.Done;
_lastestNetError = "user abort";
_lastestHttpCode = 0;
}
}
public override AssetBundle GetAssetBundle()
{
throw new NotImplementedException();
}
/// <summary>
/// 缓存下载文件
/// </summary>
private void CachingFile()
{
string tempFilePath = _bundleInfo.TempDataFilePath;
string infoFilePath = _bundleInfo.CachedInfoFilePath;
string dataFilePath = _bundleInfo.CachedDataFilePath;
string dataFileCRC = _bundleInfo.Bundle.FileCRC;
long dataFileSize = _bundleInfo.Bundle.FileSize;
if (File.Exists(infoFilePath))
File.Delete(infoFilePath);
if (File.Exists(dataFilePath))
File.Delete(dataFilePath);
// 移动临时文件路径
FileInfo fileInfo = new FileInfo(tempFilePath);
fileInfo.MoveTo(dataFilePath);
// 写入信息文件记录验证数据
CacheHelper.WriteInfoToFile(infoFilePath, dataFileCRC, dataFileSize);
// 记录缓存文件
_bundleInfo.CacheRecord();
}
}
}

View File

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

View File

@@ -1,140 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace YooAsset
{
internal sealed class WebDownloader : DownloaderBase
{
private enum ESteps
{
None,
PrepareDownload,
CreateDownloader,
CheckDownload,
TryAgain,
Done,
}
private ESteps _steps = ESteps.None;
private bool _getAssetBundle = false;
public WebDownloader(BundleInfo bundleInfo, System.Type requesterType, int failedTryAgain, int timeout) : base(bundleInfo, requesterType, failedTryAgain, timeout)
{
}
public override void SendRequest(params object[] args)
{
if (_steps == ESteps.None)
{
if (args.Length > 0)
{
_getAssetBundle = (bool)args[0];
}
_steps = ESteps.PrepareDownload;
}
}
public override void Update()
{
if (_steps == ESteps.None)
return;
if (IsDone())
return;
// 创建下载器
if (_steps == ESteps.PrepareDownload)
{
// 获取请求地址
_requestURL = GetRequestURL();
// 重置变量
DownloadProgress = 0f;
DownloadedBytes = 0;
// 重置变量
_isAbort = false;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
// 重置计时器
if (_tryAgainTimer > 0f)
YooLogger.Warning($"Try again download : {_requestURL}");
_tryAgainTimer = 0f;
_steps = ESteps.CreateDownloader;
}
// 创建下载器
if (_steps == ESteps.CreateDownloader)
{
_requester = (IWebRequester)Activator.CreateInstance(_requesterType);
_requester.Create(_requestURL, _bundleInfo, _getAssetBundle);
_steps = ESteps.CheckDownload;
}
// 检测下载结果
if (_steps == ESteps.CheckDownload)
{
_requester.Update();
DownloadedBytes = _requester.DownloadedBytes;
DownloadProgress = _requester.DownloadProgress;
if (_requester.IsDone() == false)
{
CheckTimeout();
return;
}
_lastestNetError = _requester.RequestNetError;
_lastestHttpCode = _requester.RequestHttpCode;
if (_requester.Status != ERequestStatus.Success)
{
_steps = ESteps.TryAgain;
}
else
{
_status = EStatus.Succeed;
_steps = ESteps.Done;
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
if (_failedTryAgain <= 0)
{
ReportError();
_status = EStatus.Failed;
_steps = ESteps.Done;
return;
}
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_failedTryAgain--;
_steps = ESteps.PrepareDownload;
ReportWarning();
YooLogger.Warning($"Try again download : {_requestURL}");
}
}
}
public override void Abort()
{
if (_requester != null)
_requester.Abort();
if (IsDone() == false)
{
_status = EStatus.Failed;
_steps = ESteps.Done;
_lastestNetError = "user abort";
_lastestHttpCode = 0;
}
}
public override AssetBundle GetAssetBundle()
{
return (AssetBundle)_requester.GetRequestObject();
}
}
}

View File

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

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d29a9623b2b346e439b7a7e37fafa781
guid: a8f060786f8775b4a82cc3f55d9135e2
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a93a516506b2b5c4492fdefe26eb1175
guid: 4630dac2050606043bb146325fdce6ad
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,77 @@
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebDataRequestOperation : UnityWebRequestOperation
{
private UnityWebRequestAsyncOperation _requestOperation;
/// <summary>
/// 请求结果
/// </summary>
public byte[] Result { private set; get; }
internal UnityWebDataRequestOperation(string url, int timeout = 60) : base(url, timeout)
{
}
internal override void InternalOnStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CreateRequest)
{
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
CreateWebRequest();
_steps = ESteps.Download;
}
if (_steps == ESteps.Download)
{
Progress = _requestOperation.progress;
if (_requestOperation.isDone == false)
{
CheckRequestTimeout();
return;
}
if (CheckRequestResult())
{
_steps = ESteps.Done;
Result = _webRequest.downloadHandler.data;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 注意:最终释放请求器
DisposeRequest();
}
}
internal override void InternalOnAbort()
{
_steps = ESteps.Done;
DisposeRequest();
}
private void CreateWebRequest()
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
DownloadHandlerBuffer handler = new DownloadHandlerBuffer();
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_requestOperation = _webRequest.SendWebRequest();
}
}
}

View File

@@ -0,0 +1,73 @@
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebFileRequestOperation : UnityWebRequestOperation
{
private UnityWebRequestAsyncOperation _requestOperation;
private readonly string _fileSavePath;
internal UnityWebFileRequestOperation(string url, string fileSavePath, int timeout = 60) : base(url, timeout)
{
_fileSavePath = fileSavePath;
}
internal override void InternalOnStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CreateRequest)
{
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
CreateWebRequest();
_steps = ESteps.Download;
}
if (_steps == ESteps.Download)
{
Progress = _requestOperation.progress;
if (_requestOperation.isDone == false)
{
CheckRequestTimeout();
return;
}
if (CheckRequestResult())
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 注意:最终释放请求器
DisposeRequest();
}
}
internal override void InternalOnAbort()
{
_steps = ESteps.Done;
DisposeRequest();
}
private void CreateWebRequest()
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
DownloadHandlerFile handler = new DownloadHandlerFile(_fileSavePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_requestOperation = _webRequest.SendWebRequest();
}
}
}

View File

@@ -6,99 +6,58 @@ using UnityEngine;
namespace YooAsset
{
internal abstract class UnityWebRequesterBase
internal abstract class UnityWebRequestOperation : AsyncOperationBase
{
protected enum ESteps
{
None,
CreateRequest,
Download,
Done,
}
protected UnityWebRequest _webRequest;
protected UnityWebRequestAsyncOperation _operationHandle;
protected readonly string _requestURL;
protected ESteps _steps = ESteps.None;
// 超时相关
private float _timeout;
protected readonly float _timeout;
protected ulong _latestDownloadBytes;
protected float _latestDownloadRealtime;
private bool _isAbort = false;
private ulong _latestDownloadBytes;
private float _latestDownloadRealtime;
/// <summary>
/// 请求URL地址
/// </summary>
public string URL { protected set; get; }
protected void ResetTimeout(float timeout)
public string URL
{
get { return _requestURL; }
}
internal UnityWebRequestOperation(string url, int timeout)
{
_requestURL = url;
_timeout = timeout;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
/// <summary>
/// 释放下载器
/// </summary>
public void Dispose()
protected void DisposeRequest()
{
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
_operationHandle = null;
}
}
/// <summary>
/// 是否完毕(无论成功失败)
/// </summary>
public bool IsDone()
{
if (_operationHandle == null)
return false;
return _operationHandle.isDone;
}
/// <summary>
/// 下载进度
/// </summary>
public float Progress()
{
if (_operationHandle == null)
return 0;
return _operationHandle.progress;
}
/// <summary>
/// 下载是否发生错误
/// </summary>
public bool HasError()
{
#if UNITY_2020_3_OR_NEWER
return _webRequest.result != UnityWebRequest.Result.Success;
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
return true;
else
return false;
#endif
}
/// <summary>
/// 获取错误信息
/// </summary>
public string GetError()
{
if (_webRequest != null)
{
return $"URL : {URL} Error : {_webRequest.error}";
}
return string.Empty;
}
/// <summary>
/// 检测超时
/// </summary>
public void CheckTimeout()
protected void CheckRequestTimeout()
{
// 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false)
{
if (_latestDownloadBytes != _webRequest.downloadedBytes)
if ( _latestDownloadBytes != _webRequest.downloadedBytes)
{
_latestDownloadBytes = _webRequest.downloadedBytes;
_latestDownloadRealtime = Time.realtimeSinceStartup;
@@ -112,5 +71,33 @@ namespace YooAsset
}
}
}
/// <summary>
/// 检测请求结果
/// </summary>
protected bool CheckRequestResult()
{
#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
}
}
}

View File

@@ -0,0 +1,77 @@
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebTextRequestOperation : UnityWebRequestOperation
{
private UnityWebRequestAsyncOperation _requestOperation;
/// <summary>
/// 请求结果
/// </summary>
public string Result { private set; get; }
internal UnityWebTextRequestOperation(string url, int timeout = 60) : base(url, timeout)
{
}
internal override void InternalOnStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CreateRequest)
{
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
CreateWebRequest();
_steps = ESteps.Download;
}
if (_steps == ESteps.Download)
{
Progress = _requestOperation.progress;
if (_requestOperation.isDone == false)
{
CheckRequestTimeout();
return;
}
if (CheckRequestResult())
{
_steps = ESteps.Done;
Result = _webRequest.downloadHandler.text;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 注意:最终释放请求器
DisposeRequest();
}
}
internal override void InternalOnAbort()
{
_steps = ESteps.Done;
DisposeRequest();
}
private void CreateWebRequest()
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
DownloadHandlerBuffer handler = new DownloadHandlerBuffer();
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_requestOperation = _webRequest.SendWebRequest();
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 08f3e92fdbd5d56459d8882be1f54f60
guid: a488de5dcd6f4c448a47c4b574d5c9bc
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 8a97534752300584a9b8c60c04c6a6a8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,145 +0,0 @@
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal class AssetBundleWebRequest : IWebRequester
{
private UnityWebRequest _webRequest;
private DownloadHandlerAssetBundle _downloadhandler;
private AssetBundle _cacheAssetBundle;
private bool _getAssetBundle = false;
public ERequestStatus Status { private set; get; } = ERequestStatus.None;
public float DownloadProgress { private set; get; }
public ulong DownloadedBytes { private set; get; }
public string RequestNetError { private set; get; }
public long RequestHttpCode { private set; get; }
public AssetBundleWebRequest() { }
public void Create(string requestURL, BundleInfo bundleInfo, params object[] args)
{
if (Status != ERequestStatus.None)
throw new System.Exception("Should never get here !");
if (args.Length == 0)
throw new System.Exception("Not found param value");
// 解析附加参数
_getAssetBundle = (bool)args[0];
// 创建下载器
_webRequest = DownloadHelper.NewRequest(requestURL);
if (CacheHelper.DisableUnityCacheOnWebGL)
{
uint crc = bundleInfo.Bundle.UnityCRC;
_downloadhandler = new DownloadHandlerAssetBundle(requestURL, crc);
}
else
{
uint crc = bundleInfo.Bundle.UnityCRC;
var hash = Hash128.Parse(bundleInfo.Bundle.FileHash);
_downloadhandler = new DownloadHandlerAssetBundle(requestURL, hash, crc);
}
#if UNITY_2020_3_OR_NEWER
_downloadhandler.autoLoadAssetBundle = false;
#endif
_webRequest.downloadHandler = _downloadhandler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest();
Status = ERequestStatus.InProgress;
}
public void Update()
{
if (Status == ERequestStatus.None)
return;
if (IsDone())
return;
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = _webRequest.downloadedBytes;
if (_webRequest.isDone == false)
return;
// 检查网络错误
#if UNITY_2020_3_OR_NEWER
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.result != UnityWebRequest.Result.Success)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#else
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#endif
// 缓存加载的AssetBundle对象
if (Status == ERequestStatus.Success)
{
if (_getAssetBundle)
{
_cacheAssetBundle = _downloadhandler.assetBundle;
if (_cacheAssetBundle == null)
{
RequestNetError = "assetBundle is null";
Status = ERequestStatus.Error;
}
}
}
// 最终释放下载器
DisposeWebRequest();
}
public void Abort()
{
// 如果下载任务还未开始
if (Status == ERequestStatus.None)
{
RequestNetError = "user cancel";
Status = ERequestStatus.Error;
}
else
{
// 注意:为了防止同一个文件强制停止之后立马创建新的请求,应该让进行中的请求自然终止。
if (_webRequest != null)
{
if (_webRequest.isDone == false)
_webRequest.Abort(); // If in progress, halts the UnityWebRequest as soon as possible.
}
}
}
public bool IsDone()
{
if (Status == ERequestStatus.Success || Status == ERequestStatus.Error)
return true;
else
return false;
}
public object GetRequestObject()
{
return _cacheAssetBundle;
}
private void DisposeWebRequest()
{
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
}
}
}
}

View File

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

View File

@@ -1,107 +0,0 @@
using System.IO;
using UnityEngine.Networking;
namespace YooAsset
{
internal class FileGeneralRequest : IWebRequester
{
private UnityWebRequest _webRequest;
public ERequestStatus Status { private set; get; } = ERequestStatus.None;
public float DownloadProgress { private set; get; }
public ulong DownloadedBytes { private set; get; }
public string RequestNetError { private set; get; }
public long RequestHttpCode { private set; get; }
public FileGeneralRequest() { }
public void Create(string requestURL, BundleInfo bundleInfo, params object[] args)
{
if (Status != ERequestStatus.None)
throw new System.Exception("Should never get here !");
string tempFilePath = bundleInfo.TempDataFilePath;
// 删除临时文件
if (File.Exists(tempFilePath))
File.Delete(tempFilePath);
// 创建下载器
_webRequest = DownloadHelper.NewRequest(requestURL);
DownloadHandlerFile handler = new DownloadHandlerFile(tempFilePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest();
Status = ERequestStatus.InProgress;
}
public void Update()
{
if (Status == ERequestStatus.None)
return;
if (IsDone())
return;
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = _webRequest.downloadedBytes;
if (_webRequest.isDone == false)
return;
// 检查网络错误
#if UNITY_2020_3_OR_NEWER
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.result != UnityWebRequest.Result.Success)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#else
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#endif
// 最终释放下载器
DisposeWebRequest();
}
public void Abort()
{
DisposeWebRequest();
if (IsDone() == false)
{
RequestNetError = "user abort";
RequestHttpCode = 0;
Status = ERequestStatus.Error;
}
}
public bool IsDone()
{
if (Status == ERequestStatus.Success || Status == ERequestStatus.Error)
return true;
else
return false;
}
public object GetRequestObject()
{
throw new System.NotImplementedException();
}
private void DisposeWebRequest()
{
if (_webRequest != null)
{
_webRequest.Dispose(); //注意引擎底层会自动调用Abort方法
_webRequest = null;
}
}
}
}

View File

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

View File

@@ -1,150 +0,0 @@
using System.IO;
using UnityEngine.Networking;
namespace YooAsset
{
internal class FileResumeRequest : IWebRequester
{
private string _tempFilePath;
private UnityWebRequest _webRequest;
private DownloadHandlerFileRange _downloadHandle;
private ulong _fileOriginLength = 0;
public ERequestStatus Status { private set; get; } = ERequestStatus.None;
public float DownloadProgress { private set; get; }
public ulong DownloadedBytes { private set; get; }
public string RequestNetError { private set; get; }
public long RequestHttpCode { private set; get; }
public FileResumeRequest() { }
public void Create(string requestURL, BundleInfo bundleInfo, params object[] args)
{
if (Status != ERequestStatus.None)
throw new System.Exception("Should never get here !");
_tempFilePath = bundleInfo.TempDataFilePath;
long fileBytes = bundleInfo.Bundle.FileSize;
// 获取下载的起始位置
long fileLength = -1;
if (File.Exists(_tempFilePath))
{
FileInfo fileInfo = new FileInfo(_tempFilePath);
fileLength = fileInfo.Length;
_fileOriginLength = (ulong)fileLength;
DownloadedBytes = _fileOriginLength;
}
// 检测下载起始位置是否有效
if (fileLength >= fileBytes)
{
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
// 创建下载器
_webRequest = DownloadHelper.NewRequest(requestURL);
#if UNITY_2019_4_OR_NEWER
var handler = new DownloadHandlerFile(_tempFilePath, true);
handler.removeFileOnAbort = false;
#else
var handler = new DownloadHandlerFileRange(tempFilePath, _bundleInfo.Bundle.FileSize, _webRequest);
_downloadHandle = handler;
#endif
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
if (fileLength > 0)
_webRequest.SetRequestHeader("Range", $"bytes={fileLength}-");
_webRequest.SendWebRequest();
Status = ERequestStatus.InProgress;
}
public void Update()
{
if (Status == ERequestStatus.None)
return;
if (IsDone())
return;
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = _fileOriginLength + _webRequest.downloadedBytes;
if (_webRequest.isDone == false)
return;
// 检查网络错误
#if UNITY_2020_3_OR_NEWER
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.result != UnityWebRequest.Result.Success)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#else
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#endif
// 注意:下载断点续传文件发生特殊错误码之后删除文件
if (Status == ERequestStatus.Error)
{
if (DownloadHelper.ClearFileResponseCodes != null)
{
if (DownloadHelper.ClearFileResponseCodes.Contains(RequestHttpCode))
{
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
}
// 最终释放下载器
DisposeWebRequest();
}
public void Abort()
{
DisposeWebRequest();
if (IsDone() == false)
{
RequestNetError = "user abort";
RequestHttpCode = 0;
Status = ERequestStatus.Error;
}
}
public bool IsDone()
{
if (Status == ERequestStatus.Success || Status == ERequestStatus.Error)
return true;
else
return false;
}
public object GetRequestObject()
{
throw new System.NotImplementedException();
}
private void DisposeWebRequest()
{
if (_downloadHandle != null)
{
_downloadHandle.Cleanup();
_downloadHandle = null;
}
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
}
}
}
}

View File

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

View File

@@ -1,65 +0,0 @@

namespace YooAsset
{
internal enum ERequestStatus
{
None,
InProgress,
Error,
Success,
}
internal interface IWebRequester
{
/// <summary>
/// 任务状态
/// </summary>
public ERequestStatus Status { get; }
/// <summary>
/// 下载进度0f~1f
/// </summary>
public float DownloadProgress { get; }
/// <summary>
/// 已经下载的总字节数
/// </summary>
public ulong DownloadedBytes { get; }
/// <summary>
/// 返回的网络错误
/// </summary>
public string RequestNetError { get; }
/// <summary>
/// 返回的HTTP CODE
/// </summary>
public long RequestHttpCode { get; }
/// <summary>
/// 创建任务
/// </summary>
public void Create(string url, BundleInfo bundleInfo, params object[] args);
/// <summary>
/// 更新任务
/// </summary>
public void Update();
/// <summary>
/// 终止任务
/// </summary>
public void Abort();
/// <summary>
/// 是否已经完成(无论成功或失败)
/// </summary>
public bool IsDone();
/// <summary>
/// 获取请求的对象
/// </summary>
public object GetRequestObject();
}
}

View File

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

View File

@@ -1,38 +0,0 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Threading;
namespace YooAsset
{
/// <summary>
/// 同步其它线程里的回调到主线程里
/// 注意Unity3D中需要设置Scripting Runtime Version为.NET4.6
/// </summary>
internal sealed class ThreadSyncContext : SynchronizationContext
{
private readonly ConcurrentQueue<Action> _safeQueue = new ConcurrentQueue<Action>();
/// <summary>
/// 更新同步队列
/// </summary>
public void Update()
{
while (true)
{
if (_safeQueue.TryDequeue(out Action action) == false)
return;
action.Invoke();
}
}
/// <summary>
/// 向同步队列里投递一个回调方法
/// </summary>
public override void Post(SendOrPostCallback callback, object state)
{
Action action = new Action(() => { callback(state); });
_safeQueue.Enqueue(action);
}
}
}

View File

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

View File

@@ -1,51 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebDataRequester : UnityWebRequesterBase
{
/// <summary>
/// 发送GET请求
/// </summary>
public void SendRequest(string url, int timeout = 60)
{
if (_webRequest == null)
{
URL = url;
ResetTimeout(timeout);
_webRequest = DownloadHelper.NewRequest(URL);
DownloadHandlerBuffer handler = new DownloadHandlerBuffer();
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_operationHandle = _webRequest.SendWebRequest();
}
}
/// <summary>
/// 获取下载的字节数据
/// </summary>
public byte[] GetData()
{
if (_webRequest != null && IsDone())
return _webRequest.downloadHandler.data;
else
return null;
}
/// <summary>
/// 获取下载的文本数据
/// </summary>
public string GetText()
{
if (_webRequest != null && IsDone())
return _webRequest.downloadHandler.text;
else
return null;
}
}
}

View File

@@ -1,30 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebFileRequester : UnityWebRequesterBase
{
/// <summary>
/// 发送GET请求
/// </summary>
public void SendRequest(string url, string fileSavePath, int timeout = 60)
{
if (_webRequest == null)
{
URL = url;
ResetTimeout(timeout);
_webRequest = DownloadHelper.NewRequest(URL);
DownloadHandlerFile handler = new DownloadHandlerFile(fileSavePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_operationHandle = _webRequest.SendWebRequest();
}
}
}
}

View File

@@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace YooAsset
{
public class RequestHelper
internal class WebRequestCounter
{
/// <summary>
/// 记录网络请求失败事件的次数

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 96a75a20111d6124696665e7aac3564c
guid: d7ac605758b151748980942c6d563fed
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a82eeb6a47cd02c4cb38e851c8ed8784
guid: a9ca0d0d29eb5294b9c6926c6a09e76b
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 167d849df37f45e42a77ab47464a9442
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,73 @@
using System.IO;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace YooAsset
{
internal class AssetBundleResult : BundleResult
{
private readonly IFileSystem _fileSystem;
private readonly PackageBundle _packageBundle;
private readonly AssetBundle _assetBundle;
private readonly Stream _managedStream;
public AssetBundleResult(IFileSystem fileSystem, PackageBundle packageBundle, AssetBundle assetBundle, Stream managedStream)
{
_fileSystem = fileSystem;
_packageBundle = packageBundle;
_assetBundle = assetBundle;
_managedStream = managedStream;
}
public override void UnloadBundleFile()
{
if (_assetBundle != null)
{
_assetBundle.Unload(true);
}
if (_managedStream != null)
{
_managedStream.Close();
_managedStream.Dispose();
}
}
public override string GetBundleFilePath()
{
return _fileSystem.GetBundleFilePath(_packageBundle);
}
public override byte[] ReadBundleFileData()
{
return _fileSystem.ReadBundleFileData(_packageBundle);
}
public override string ReadBundleFileText()
{
return _fileSystem.ReadBundleFileText(_packageBundle);
}
public override FSLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo)
{
var operation = new AssetBundleLoadAssetOperation(_packageBundle, _assetBundle, assetInfo);
OperationSystem.StartOperation(_fileSystem.PackageName, operation);
return operation;
}
public override FSLoadAllAssetsOperation LoadAllAssetsAsync(AssetInfo assetInfo)
{
var operation = new AssetBundleLoadAllAssetsOperation(_packageBundle, _assetBundle, assetInfo);
OperationSystem.StartOperation(_fileSystem.PackageName, operation);
return operation;
}
public override FSLoadSubAssetsOperation LoadSubAssetsAsync(AssetInfo assetInfo)
{
var operation = new AssetBundleLoadSubAssetsOperation(_packageBundle, _assetBundle, assetInfo);
OperationSystem.StartOperation(_fileSystem.PackageName, operation);
return operation;
}
public override FSLoadSceneOperation LoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadParams, bool suspendLoad)
{
var operation = new AssetBundleLoadSceneOperation(assetInfo, loadParams, suspendLoad);
OperationSystem.StartOperation(_fileSystem.PackageName, operation);
return operation;
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e310d20cf53709541bc66d1483afe627
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,121 @@
using UnityEngine;
namespace YooAsset
{
internal class AssetBundleLoadAllAssetsOperation : FSLoadAllAssetsOperation
{
protected enum ESteps
{
None,
CheckBundle,
LoadAsset,
CheckResult,
Done,
}
private readonly PackageBundle _packageBundle;
private readonly AssetBundle _assetBundle;
private readonly AssetInfo _assetInfo;
private AssetBundleRequest _request;
private ESteps _steps = ESteps.None;
public AssetBundleLoadAllAssetsOperation(PackageBundle packageBundle, AssetBundle assetBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
_assetBundle = assetBundle;
_assetInfo = assetInfo;
}
internal override void InternalOnStart()
{
_steps = ESteps.CheckBundle;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckBundle)
{
if (_assetBundle == null)
{
_steps = ESteps.Done;
Error = $"The bundle {_packageBundle.BundleName} has been destroyed due to unity engine bugs !";
Status = EOperationStatus.Failed;
return;
}
_steps = ESteps.LoadAsset;
}
if (_steps == ESteps.LoadAsset)
{
if (IsWaitForAsyncComplete)
{
if (_assetInfo.AssetType == null)
Result = _assetBundle.LoadAllAssets();
else
Result = _assetBundle.LoadAllAssets(_assetInfo.AssetType);
}
else
{
if (_assetInfo.AssetType == null)
_request = _assetBundle.LoadAllAssetsAsync();
else
_request = _assetBundle.LoadAllAssetsAsync(_assetInfo.AssetType);
}
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_request != null)
{
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity asset.");
Result = _request.allAssets;
}
else
{
Progress = _request.progress;
if (_request.isDone == false)
return;
Result = _request.allAssets;
}
}
if (Result == null)
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load all assets : {_assetInfo.AssetPath} AssetType : null AssetBundle : {_packageBundle.BundleName}";
else
error = $"Failed to load all assets : {_assetInfo.AssetPath} AssetType : {_assetInfo.AssetType} AssetBundle : {_packageBundle.BundleName}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
while (true)
{
if (ExecuteWhileDone())
{
_steps = ESteps.Done;
break;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,121 @@
using UnityEngine;
namespace YooAsset
{
internal class AssetBundleLoadAssetOperation : FSLoadAssetOperation
{
protected enum ESteps
{
None,
CheckBundle,
LoadAsset,
CheckResult,
Done,
}
private readonly PackageBundle _packageBundle;
private readonly AssetBundle _assetBundle;
private readonly AssetInfo _assetInfo;
private AssetBundleRequest _request;
private ESteps _steps = ESteps.None;
public AssetBundleLoadAssetOperation(PackageBundle packageBundle, AssetBundle assetBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
_assetBundle = assetBundle;
_assetInfo = assetInfo;
}
internal override void InternalOnStart()
{
_steps = ESteps.CheckBundle;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckBundle)
{
if (_assetBundle == null)
{
_steps = ESteps.Done;
Error = $"The bundle {_packageBundle.BundleName} has been destroyed due to unity engine bugs !";
Status = EOperationStatus.Failed;
return;
}
_steps = ESteps.LoadAsset;
}
if (_steps == ESteps.LoadAsset)
{
if (IsWaitForAsyncComplete)
{
if (_assetInfo.AssetType == null)
Result = _assetBundle.LoadAsset(_assetInfo.AssetPath);
else
Result = _assetBundle.LoadAsset(_assetInfo.AssetPath, _assetInfo.AssetType);
}
else
{
if (_assetInfo.AssetType == null)
_request = _assetBundle.LoadAssetAsync(_assetInfo.AssetPath);
else
_request = _assetBundle.LoadAssetAsync(_assetInfo.AssetPath, _assetInfo.AssetType);
}
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_request != null)
{
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity asset.");
Result = _request.asset;
}
else
{
Progress = _request.progress;
if (_request.isDone == false)
return;
Result = _request.asset;
}
}
if (Result == null)
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load asset : {_assetInfo.AssetPath} AssetType : null AssetBundle : {_packageBundle.BundleName}";
else
error = $"Failed to load asset : {_assetInfo.AssetPath} AssetType : {_assetInfo.AssetType} AssetBundle : {_packageBundle.BundleName}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
while (true)
{
if (ExecuteWhileDone())
{
_steps = ESteps.Done;
break;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,117 @@
using UnityEngine;
using UnityEngine.SceneManagement;
namespace YooAsset
{
internal class AssetBundleLoadSceneOperation : FSLoadSceneOperation
{
protected enum ESteps
{
None,
LoadScene,
CheckResult,
Done,
}
private readonly AssetInfo _assetInfo;
private readonly LoadSceneParameters _loadParams;
private bool _suspendLoad;
private AsyncOperation _asyncOperation;
private ESteps _steps = ESteps.None;
public AssetBundleLoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadParams, bool suspendLoad)
{
_assetInfo = assetInfo;
_loadParams = loadParams;
_suspendLoad = suspendLoad;
}
internal override void InternalOnStart()
{
_steps = ESteps.LoadScene;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadScene)
{
if (IsWaitForAsyncComplete)
{
// 注意:场景同步加载方法不会立即加载场景,而是在下一帧加载。
Result = SceneManager.LoadScene(_assetInfo.AssetPath, _loadParams);
_steps = ESteps.CheckResult;
}
else
{
// 注意如果场景不存在异步加载方法返回NULL
// 注意:即使是异步加载也要在当帧获取到场景对象
_asyncOperation = SceneManager.LoadSceneAsync(_assetInfo.AssetPath, _loadParams);
if (_asyncOperation != null)
{
_asyncOperation.allowSceneActivation = !_suspendLoad;
_asyncOperation.priority = 100;
Result = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
_steps = ESteps.CheckResult;
}
else
{
string error = $"Failed to load scene : {_assetInfo.AssetPath}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
}
}
}
if (_steps == ESteps.CheckResult)
{
if (_asyncOperation != null)
{
if (IsWaitForAsyncComplete)
{
//注意:场景加载无法强制异步转同步
YooLogger.Error("The scene is loading asyn !");
}
else
{
// 注意:在业务层中途可以取消挂起
if (_asyncOperation.allowSceneActivation == false)
{
if (_suspendLoad == false)
_asyncOperation.allowSceneActivation = true;
}
Progress = _asyncOperation.progress;
if (_asyncOperation.isDone == false)
return;
}
}
if (Result.IsValid())
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
string error = $"The loaded scene is invalid : {_assetInfo.AssetPath}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
//TODO 场景加载不支持异步转同步,为了支持同步加载方法需要实现该方法!
InternalOnUpdate();
}
public override void UnSuspendLoad()
{
_suspendLoad = false;
}
}
}

View File

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

View File

@@ -0,0 +1,121 @@
using UnityEngine;
namespace YooAsset
{
internal class AssetBundleLoadSubAssetsOperation : FSLoadSubAssetsOperation
{
protected enum ESteps
{
None,
CheckBundle,
LoadAsset,
CheckResult,
Done,
}
private readonly PackageBundle _packageBundle;
private readonly AssetBundle _assetBundle;
private readonly AssetInfo _assetInfo;
private AssetBundleRequest _request;
private ESteps _steps = ESteps.None;
public AssetBundleLoadSubAssetsOperation(PackageBundle packageBundle, AssetBundle assetBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
_assetBundle = assetBundle;
_assetInfo = assetInfo;
}
internal override void InternalOnStart()
{
_steps = ESteps.CheckBundle;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckBundle)
{
if (_assetBundle == null)
{
_steps = ESteps.Done;
Error = $"The bundle {_packageBundle.BundleName} has been destroyed due to unity engine bugs !";
Status = EOperationStatus.Failed;
return;
}
_steps = ESteps.LoadAsset;
}
if (_steps == ESteps.LoadAsset)
{
if (IsWaitForAsyncComplete)
{
if (_assetInfo.AssetType == null)
Result = _assetBundle.LoadAssetWithSubAssets(_assetInfo.AssetPath);
else
Result = _assetBundle.LoadAssetWithSubAssets(_assetInfo.AssetPath, _assetInfo.AssetType);
}
else
{
if (_assetInfo.AssetType == null)
_request = _assetBundle.LoadAssetWithSubAssetsAsync(_assetInfo.AssetPath);
else
_request = _assetBundle.LoadAssetWithSubAssetsAsync(_assetInfo.AssetPath, _assetInfo.AssetType);
}
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_request != null)
{
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity asset.");
Result = _request.allAssets;
}
else
{
Progress = _request.progress;
if (_request.isDone == false)
return;
Result = _request.allAssets;
}
}
if (Result == null)
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load sub assets : {_assetInfo.AssetPath} AssetType : null AssetBundle : {_packageBundle.BundleName}";
else
error = $"Failed to load sub assets : {_assetInfo.AssetPath} AssetType : {_assetInfo.AssetType} AssetBundle : {_packageBundle.BundleName}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
while (true)
{
if (ExecuteWhileDone())
{
_steps = ESteps.Done;
break;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,48 @@
using UnityEngine.SceneManagement;
namespace YooAsset
{
internal abstract class BundleResult
{
/// <summary>
/// 卸载资源包文件
/// </summary>
public abstract void UnloadBundleFile();
/// <summary>
/// 获取资源包文件的路径
/// </summary>
public abstract string GetBundleFilePath();
/// <summary>
/// 读取资源包文件的二进制数据
/// </summary>
public abstract byte[] ReadBundleFileData();
/// <summary>
/// 读取资源包文件的文本数据
/// </summary>
public abstract string ReadBundleFileText();
/// <summary>
/// 加载资源包内的资源对象
/// </summary>
public abstract FSLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo);
/// <summary>
/// 加载资源包内的所有资源对象
/// </summary>
public abstract FSLoadAllAssetsOperation LoadAllAssetsAsync(AssetInfo assetInfo);
/// <summary>
/// 加载资源包内的资源对象及所有子资源对象
/// </summary>
public abstract FSLoadSubAssetsOperation LoadSubAssetsAsync(AssetInfo assetInfo);
/// <summary>
/// 加载资源包内的场景对象
/// </summary>
public abstract FSLoadSceneOperation LoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadParams, bool suspendLoad);
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 87cc377fd18e5f948ba2b1f3e5175781
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 436e50c3a761f854d990f680fdf277ad
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@

namespace YooAsset
{
internal class RawBundleLoadAllAssetsOperation : FSLoadAllAssetsOperation
{
internal override void InternalOnStart()
{
Error = $"{nameof(RawBundleLoadAllAssetsOperation)} not support load all assets !";
Status = EOperationStatus.Failed;
}
internal override void InternalOnUpdate()
{
}
}
}

View File

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

View File

@@ -0,0 +1,15 @@

namespace YooAsset
{
internal class RawBundleLoadAssetOperation : FSLoadAssetOperation
{
internal override void InternalOnStart()
{
Error = $"{nameof(RawBundleLoadAssetOperation)} not support load asset !";
Status = EOperationStatus.Failed;
}
internal override void InternalOnUpdate()
{
}
}
}

View File

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

View File

@@ -0,0 +1,18 @@

namespace YooAsset
{
internal class RawBundleLoadSceneOperation : FSLoadSceneOperation
{
internal override void InternalOnStart()
{
Error = $"{nameof(RawBundleLoadSceneOperation)} not support load scene !";
Status = EOperationStatus.Failed;
}
internal override void InternalOnUpdate()
{
}
public override void UnSuspendLoad()
{
}
}
}

View File

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

View File

@@ -0,0 +1,15 @@

namespace YooAsset
{
internal class RawBundleLoadSubAssetsOperation : FSLoadSubAssetsOperation
{
internal override void InternalOnStart()
{
Error = $"{nameof(RawBundleLoadSubAssetsOperation)} not support load sub assets !";
Status = EOperationStatus.Failed;
}
internal override void InternalOnUpdate()
{
}
}
}

View File

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

View File

@@ -0,0 +1,57 @@
using UnityEngine.SceneManagement;
namespace YooAsset
{
internal class RawBundleResult : BundleResult
{
private readonly IFileSystem _fileSystem;
private readonly PackageBundle _packageBundle;
public RawBundleResult(IFileSystem fileSystem, PackageBundle packageBundle)
{
_fileSystem = fileSystem;
_packageBundle = packageBundle;
}
public override void UnloadBundleFile()
{
}
public override string GetBundleFilePath()
{
return _fileSystem.GetBundleFilePath(_packageBundle);
}
public override byte[] ReadBundleFileData()
{
return _fileSystem.ReadBundleFileData(_packageBundle);
}
public override string ReadBundleFileText()
{
return _fileSystem.ReadBundleFileText(_packageBundle);
}
public override FSLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo)
{
var operation = new RawBundleLoadAssetOperation();
OperationSystem.StartOperation(_fileSystem.PackageName, operation);
return operation;
}
public override FSLoadAllAssetsOperation LoadAllAssetsAsync(AssetInfo assetInfo)
{
var operation = new RawBundleLoadAllAssetsOperation();
OperationSystem.StartOperation(_fileSystem.PackageName, operation);
return operation;
}
public override FSLoadSubAssetsOperation LoadSubAssetsAsync(AssetInfo assetInfo)
{
var operation = new RawBundleLoadSubAssetsOperation();
OperationSystem.StartOperation(_fileSystem.PackageName, operation);
return operation;
}
public override FSLoadSceneOperation LoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadParams, bool suspendLoad)
{
var operation = new RawBundleLoadSceneOperation();
OperationSystem.StartOperation(_fileSystem.PackageName, operation);
return operation;
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2e49e0ae672b9944783571b2ad737df9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 81e8e8c03e8b3f840aa8ffef751d5207
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,122 @@
using System.Collections.Generic;
namespace YooAsset
{
internal class VirtualBundleLoadAllAssetsOperation : FSLoadAllAssetsOperation
{
protected enum ESteps
{
None,
CheckBundle,
LoadAsset,
CheckResult,
Done,
}
private readonly PackageBundle _packageBundle;
private readonly AssetInfo _assetInfo;
private ESteps _steps = ESteps.None;
public VirtualBundleLoadAllAssetsOperation(PackageBundle packageBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
_assetInfo = assetInfo;
}
internal override void InternalOnStart()
{
#if UNITY_EDITOR
_steps = ESteps.CheckBundle;
#else
_steps = ESteps.Done;
Error = $"{nameof(VirtualBundleLoadAllAssetsOperation)} only support unity editor platform !";
Status = EOperationStatus.Failed;
#endif
}
internal override void InternalOnUpdate()
{
#if UNITY_EDITOR
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckBundle)
{
// 检测资源文件是否存在
string guid = UnityEditor.AssetDatabase.AssetPathToGUID(_assetInfo.AssetPath);
if (string.IsNullOrEmpty(guid))
{
string error = $"Not found asset : {_assetInfo.AssetPath}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
return;
}
_steps = ESteps.LoadAsset;
}
if (_steps == ESteps.LoadAsset)
{
if (_assetInfo.AssetType == null)
{
List<UnityEngine.Object> result = new List<UnityEngine.Object>();
foreach (var packageAsset in _packageBundle.IncludeMainAssets)
{
string assetPath = packageAsset.AssetPath;
UnityEngine.Object mainAsset = UnityEditor.AssetDatabase.LoadMainAssetAtPath(assetPath);
if (mainAsset != null)
result.Add(mainAsset);
}
Result = result.ToArray();
}
else
{
List<UnityEngine.Object> result = new List<UnityEngine.Object>();
foreach (var packageAsset in _packageBundle.IncludeMainAssets)
{
string assetPath = packageAsset.AssetPath;
UnityEngine.Object mainAsset = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPath, _assetInfo.AssetType);
if (mainAsset != null)
result.Add(mainAsset);
}
Result = result.ToArray();
}
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (Result == null)
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load all assets : {_assetInfo.AssetPath} AssetType : null";
else
error = $"Failed to load all assets : {_assetInfo.AssetPath} AssetType : {_assetInfo.AssetType}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
#endif
}
internal override void InternalWaitForAsyncComplete()
{
while (true)
{
if (ExecuteWhileDone())
{
_steps = ESteps.Done;
break;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,101 @@

namespace YooAsset
{
internal class VirtualBundleLoadAssetOperation : FSLoadAssetOperation
{
protected enum ESteps
{
None,
CheckBundle,
LoadAsset,
CheckResult,
Done,
}
private readonly PackageBundle _packageBundle;
private readonly AssetInfo _assetInfo;
private ESteps _steps = ESteps.None;
public VirtualBundleLoadAssetOperation(PackageBundle packageBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
_assetInfo = assetInfo;
}
internal override void InternalOnStart()
{
#if UNITY_EDITOR
_steps = ESteps.CheckBundle;
#else
_steps = ESteps.Done;
Error = $"{nameof(VirtualBundleLoadAssetOperation)} only support unity editor platform !";
Status = EOperationStatus.Failed;
#endif
}
internal override void InternalOnUpdate()
{
#if UNITY_EDITOR
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckBundle)
{
// 检测资源文件是否存在
string guid = UnityEditor.AssetDatabase.AssetPathToGUID(_assetInfo.AssetPath);
if (string.IsNullOrEmpty(guid))
{
string error = $"Not found asset : {_assetInfo.AssetPath}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
return;
}
_steps = ESteps.LoadAsset;
}
if (_steps == ESteps.LoadAsset)
{
if (_assetInfo.AssetType == null)
Result = UnityEditor.AssetDatabase.LoadMainAssetAtPath(_assetInfo.AssetPath);
else
Result = UnityEditor.AssetDatabase.LoadAssetAtPath(_assetInfo.AssetPath, _assetInfo.AssetType);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (Result == null)
{
string error;
if (_assetInfo.AssetType == null)
error = $"Failed to load asset object : {_assetInfo.AssetPath} AssetType : null";
else
error = $"Failed to load asset object : {_assetInfo.AssetPath} AssetType : {_assetInfo.AssetType}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
#endif
}
internal override void InternalWaitForAsyncComplete()
{
while (true)
{
if (ExecuteWhileDone())
{
_steps = ESteps.Done;
break;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,123 @@
using UnityEngine;
using UnityEngine.SceneManagement;
namespace YooAsset
{
internal class VirtualBundleLoadSceneOperation : FSLoadSceneOperation
{
protected enum ESteps
{
None,
LoadScene,
CheckResult,
Done,
}
private readonly AssetInfo _assetInfo;
private readonly LoadSceneParameters _loadParams;
private bool _suspendLoad;
private AsyncOperation _asyncOperation;
private ESteps _steps = ESteps.None;
public VirtualBundleLoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadParams, bool suspendLoad)
{
_assetInfo = assetInfo;
_loadParams = loadParams;
_suspendLoad = suspendLoad;
}
internal override void InternalOnStart()
{
#if UNITY_EDITOR
_steps = ESteps.LoadScene;
#else
_steps = ESteps.Done;
Error = $"{nameof(VirtualBundleLoadSceneOperation)} only support unity editor platform !";
Status = EOperationStatus.Failed;
#endif
}
internal override void InternalOnUpdate()
{
#if UNITY_EDITOR
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadScene)
{
if (IsWaitForAsyncComplete)
{
Result = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneInPlayMode(_assetInfo.AssetPath, _loadParams);
_steps = ESteps.CheckResult;
}
else
{
_asyncOperation = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneAsyncInPlayMode(_assetInfo.AssetPath, _loadParams);
if (_asyncOperation != null)
{
_asyncOperation.allowSceneActivation = !_suspendLoad;
_asyncOperation.priority = 100;
Result = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
_steps = ESteps.CheckResult;
}
else
{
string error = $"Failed to load scene : {_assetInfo.AssetPath}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
return;
}
}
}
if (_steps == ESteps.CheckResult)
{
if (_asyncOperation != null)
{
if (IsWaitForAsyncComplete)
{
// 注意:场景加载无法强制异步转同步
YooLogger.Error("The scene is loading asyn !");
}
else
{
// 注意:在业务层中途可以取消挂起
if (_asyncOperation.allowSceneActivation == false)
{
if (_suspendLoad == false)
_asyncOperation.allowSceneActivation = true;
}
Progress = _asyncOperation.progress;
if (_asyncOperation.isDone == false)
return;
}
}
if (Result.IsValid())
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
string error = $"The loaded scene is invalid : {_assetInfo.AssetPath}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
}
}
#endif
}
internal override void InternalWaitForAsyncComplete()
{
//TODO 场景加载不支持异步转同步,为了支持同步加载方法需要实现该方法!
InternalOnUpdate();
}
public override void UnSuspendLoad()
{
_suspendLoad = false;
}
}
}

Some files were not shown because too many files have changed in this diff Show More