mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-05-29 20:48:47 +00:00
Compare commits
5 Commits
a3f689d815
...
354ca5197f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
354ca5197f | ||
|
|
ce4d6911db | ||
|
|
b796b1a44e | ||
|
|
7198e639d9 | ||
|
|
294fa18fec |
@@ -255,12 +255,7 @@ namespace YooAsset
|
|||||||
if (_watchdogAborted)
|
if (_watchdogAborted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if UNITY_2020_3_OR_NEWER
|
double realtimeSinceStartup = TimeUtility.RealtimeSinceStartup;
|
||||||
double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartupAsDouble;
|
|
||||||
#else
|
|
||||||
double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartup;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (DownloadedBytes != _lastDownloadBytes)
|
if (DownloadedBytes != _lastDownloadBytes)
|
||||||
{
|
{
|
||||||
_lastDownloadBytes = DownloadedBytes;
|
_lastDownloadBytes = DownloadedBytes;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace YooAsset
|
|||||||
if (Status == EDownloadRequestStatus.None)
|
if (Status == EDownloadRequestStatus.None)
|
||||||
{
|
{
|
||||||
Status = EDownloadRequestStatus.Running;
|
Status = EDownloadRequestStatus.Running;
|
||||||
_lastUpdateTime = GetUnityEngineRealtime();
|
_lastUpdateTime = TimeUtility.RealtimeSinceStartup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ namespace YooAsset
|
|||||||
if (Status != EDownloadRequestStatus.Running)
|
if (Status != EDownloadRequestStatus.Running)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double currentTime = GetUnityEngineRealtime();
|
double currentTime = TimeUtility.RealtimeSinceStartup;
|
||||||
double deltaTime = currentTime - _lastUpdateTime;
|
double deltaTime = currentTime - _lastUpdateTime;
|
||||||
_lastUpdateTime = currentTime;
|
_lastUpdateTime = currentTime;
|
||||||
|
|
||||||
@@ -137,14 +137,5 @@ namespace YooAsset
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private double GetUnityEngineRealtime()
|
|
||||||
{
|
|
||||||
#if UNITY_2020_3_OR_NEWER
|
|
||||||
return UnityEngine.Time.realtimeSinceStartupAsDouble;
|
|
||||||
#else
|
|
||||||
return UnityEngine.Time.realtimeSinceStartup;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
private readonly DefaultCacheFileSystem _fileSystem;
|
private readonly DefaultCacheFileSystem _fileSystem;
|
||||||
private IEnumerator<string> _filesEnumerator = null;
|
private IEnumerator<string> _filesEnumerator = null;
|
||||||
private float _verifyStartTime;
|
private double _verifyStartTime;
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -33,7 +33,7 @@ namespace YooAsset
|
|||||||
internal override void InternalStart()
|
internal override void InternalStart()
|
||||||
{
|
{
|
||||||
_steps = ESteps.Prepare;
|
_steps = ESteps.Prepare;
|
||||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
_verifyStartTime = TimeUtility.RealtimeSinceStartup;
|
||||||
}
|
}
|
||||||
internal override void InternalUpdate()
|
internal override void InternalUpdate()
|
||||||
{
|
{
|
||||||
@@ -58,7 +58,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
double costTime = TimeUtility.RealtimeSinceStartup - _verifyStartTime;
|
||||||
YooLogger.Log($"Search cache files elapsed time {costTime:f1} seconds");
|
YooLogger.Log($"Search cache files elapsed time {costTime:f1} seconds");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace YooAsset
|
|||||||
private List<VerifyFileElement> _verifyingList;
|
private List<VerifyFileElement> _verifyingList;
|
||||||
private int _verifyMaxNum;
|
private int _verifyMaxNum;
|
||||||
private int _verifyTotalCount;
|
private int _verifyTotalCount;
|
||||||
private float _verifyStartTime;
|
private double _verifyStartTime;
|
||||||
private int _succeedCount;
|
private int _succeedCount;
|
||||||
private int _failedCount;
|
private int _failedCount;
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
@@ -40,7 +40,7 @@ namespace YooAsset
|
|||||||
internal override void InternalStart()
|
internal override void InternalStart()
|
||||||
{
|
{
|
||||||
_steps = ESteps.InitVerify;
|
_steps = ESteps.InitVerify;
|
||||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
_verifyStartTime = TimeUtility.RealtimeSinceStartup;
|
||||||
}
|
}
|
||||||
internal override void InternalUpdate()
|
internal override void InternalUpdate()
|
||||||
{
|
{
|
||||||
@@ -84,7 +84,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
double costTime = TimeUtility.RealtimeSinceStartup - _verifyStartTime;
|
||||||
YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds");
|
YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,9 +155,19 @@ namespace YooAsset
|
|||||||
if (_childs == null)
|
if (_childs == null)
|
||||||
_childs = new List<AsyncOperationBase>(10);
|
_childs = new List<AsyncOperationBase>(10);
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR || DEBUG
|
||||||
|
if (child == null)
|
||||||
|
throw new YooInternalException("The child node is null !");
|
||||||
|
|
||||||
|
if (ReferenceEquals(child, this))
|
||||||
|
throw new YooInternalException("The child node cannot be itself !");
|
||||||
|
|
||||||
if (_childs.Contains(child))
|
if (_childs.Contains(child))
|
||||||
throw new YooInternalException($"The child node {child.GetType().Name} already exists !");
|
throw new YooInternalException($"The child node {child.GetType().Name} already exists !");
|
||||||
|
|
||||||
|
// 禁止形成环依赖
|
||||||
|
if (WouldCreateCycle(child))
|
||||||
|
throw new YooInternalException($"AddChildOperation would create a cycle : {this.GetType().Name} -> {child.GetType().Name}");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_childs.Add(child);
|
_childs.Add(child);
|
||||||
@@ -171,7 +181,10 @@ namespace YooAsset
|
|||||||
if (_childs == null)
|
if (_childs == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR || DEBUG
|
||||||
|
if (child == null)
|
||||||
|
throw new YooInternalException("The child node is null !");
|
||||||
|
|
||||||
if (_childs.Contains(child) == false)
|
if (_childs.Contains(child) == false)
|
||||||
throw new YooInternalException($"The child node {child.GetType().Name} not exists !");
|
throw new YooInternalException($"The child node {child.GetType().Name} not exists !");
|
||||||
#endif
|
#endif
|
||||||
@@ -200,8 +213,17 @@ namespace YooAsset
|
|||||||
DebugBeginRecording();
|
DebugBeginRecording();
|
||||||
|
|
||||||
// 开始任务
|
// 开始任务
|
||||||
|
try
|
||||||
|
{
|
||||||
InternalStart();
|
InternalStart();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = ex.ToString();
|
||||||
|
YooLogger.Error($"Exception in {this.GetType().Name}.InternalStart : {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -215,8 +237,19 @@ namespace YooAsset
|
|||||||
DebugUpdateRecording();
|
DebugUpdateRecording();
|
||||||
|
|
||||||
// 更新任务
|
// 更新任务
|
||||||
|
// 注意:兜底隔离机制
|
||||||
|
// 说明:检测的异常源包含:I/O(解压/读写权限/磁盘满),平台差异等
|
||||||
|
try
|
||||||
|
{
|
||||||
InternalUpdate();
|
InternalUpdate();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = ex.ToString();
|
||||||
|
YooLogger.Error($"Exception in {this.GetType().Name}.InternalUpdate : {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (IsDone && IsFinish == false)
|
if (IsDone && IsFinish == false)
|
||||||
{
|
{
|
||||||
@@ -244,12 +277,15 @@ namespace YooAsset
|
|||||||
Error = "user abort";
|
Error = "user abort";
|
||||||
YooLogger.Warning($"Async operation {this.GetType().Name} has been aborted !");
|
YooLogger.Warning($"Async operation {this.GetType().Name} has been aborted !");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//注意:强制收尾,确保Task能完成
|
||||||
|
FinishOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 强制结束异步任务
|
/// 强制结束异步任务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void FinishOperation()
|
private void FinishOperation()
|
||||||
{
|
{
|
||||||
if (IsFinish == false)
|
if (IsFinish == false)
|
||||||
{
|
{
|
||||||
@@ -261,6 +297,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//TODO 单个回调异常会阻断后续回调
|
||||||
_callback?.Invoke(this);
|
_callback?.Invoke(this);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -307,14 +344,9 @@ namespace YooAsset
|
|||||||
// 当执行次数用完时
|
// 当执行次数用完时
|
||||||
runCount--;
|
runCount--;
|
||||||
if (runCount <= 0)
|
if (runCount <= 0)
|
||||||
{
|
|
||||||
Status = EOperationStatus.Failed;
|
|
||||||
Error = $"Operation {this.GetType().Name} failed to wait for async complete !";
|
|
||||||
YooLogger.Error(Error);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 无限次数的执行更新逻辑,直到任务完成
|
/// 无限次数的执行更新逻辑,直到任务完成
|
||||||
@@ -341,11 +373,7 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void WaitForAsyncComplete()
|
public void WaitForAsyncComplete()
|
||||||
{
|
{
|
||||||
if (IsDone)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//TODO 防止异步操作被挂起陷入无限死循环!
|
//TODO 防止异步操作被挂起陷入无限死循环!
|
||||||
// 例如:文件解压任务或者文件导入任务!
|
|
||||||
if (Status == EOperationStatus.None)
|
if (Status == EOperationStatus.None)
|
||||||
{
|
{
|
||||||
StartOperation();
|
StartOperation();
|
||||||
@@ -354,7 +382,19 @@ namespace YooAsset
|
|||||||
if (IsWaitForAsyncComplete == false)
|
if (IsWaitForAsyncComplete == false)
|
||||||
{
|
{
|
||||||
IsWaitForAsyncComplete = true;
|
IsWaitForAsyncComplete = true;
|
||||||
|
|
||||||
|
if (IsDone == false)
|
||||||
InternalWaitForAsyncComplete();
|
InternalWaitForAsyncComplete();
|
||||||
|
|
||||||
|
if (IsDone == false)
|
||||||
|
{
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = $"Operation {this.GetType().Name} failed to wait for async complete !";
|
||||||
|
YooLogger.Error(Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
//注意:强制收尾,确保Task能完成
|
||||||
|
FinishOperation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +402,7 @@ namespace YooAsset
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始的时间
|
/// 开始的时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string BeginTime = string.Empty;
|
public string BeginTime { protected set; get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理耗时(单位:毫秒)
|
/// 处理耗时(单位:毫秒)
|
||||||
@@ -377,7 +417,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_watch == null)
|
if (_watch == null)
|
||||||
{
|
{
|
||||||
BeginTime = SpawnTimeToString(UnityEngine.Time.realtimeSinceStartup);
|
BeginTime = SpawnTimeToString(TimeUtility.RealtimeSinceStartup);
|
||||||
_watch = Stopwatch.StartNew();
|
_watch = Stopwatch.StartNew();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,13 +441,46 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SpawnTimeToString(float spawnTime)
|
private string SpawnTimeToString(double spawnTime)
|
||||||
{
|
{
|
||||||
float h = UnityEngine.Mathf.FloorToInt(spawnTime / 3600f);
|
double h = System.Math.Floor(spawnTime / 3600);
|
||||||
float m = UnityEngine.Mathf.FloorToInt(spawnTime / 60f - h * 60f);
|
double m = System.Math.Floor(spawnTime / 60 - h * 60);
|
||||||
float s = UnityEngine.Mathf.FloorToInt(spawnTime - m * 60f - h * 3600f);
|
double s = System.Math.Floor(spawnTime - m * 60 - h * 3600);
|
||||||
return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00");
|
return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00");
|
||||||
}
|
}
|
||||||
|
private bool WouldCreateCycle(AsyncOperationBase child)
|
||||||
|
{
|
||||||
|
const int maxVisited = 4096;
|
||||||
|
var stack = new Stack<AsyncOperationBase>();
|
||||||
|
var visited = new HashSet<AsyncOperationBase>();
|
||||||
|
stack.Push(child);
|
||||||
|
|
||||||
|
while (stack.Count > 0)
|
||||||
|
{
|
||||||
|
var node = stack.Pop();
|
||||||
|
if (node == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (visited.Add(node) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (visited.Count > maxVisited)
|
||||||
|
throw new YooInternalException("Child operation graph is too large, cycle check aborted !");
|
||||||
|
|
||||||
|
if (ReferenceEquals(node, this))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (node._childs == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int i = 0; i < node._childs.Count; i++)
|
||||||
|
{
|
||||||
|
stack.Push(node._childs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
internal DebugOperationInfo GetDebugOperationInfo()
|
internal DebugOperationInfo GetDebugOperationInfo()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
private readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(100);
|
private readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(100);
|
||||||
private readonly List<AsyncOperationBase> _newList = new List<AsyncOperationBase>(100);
|
private readonly List<AsyncOperationBase> _newList = new List<AsyncOperationBase>(100);
|
||||||
|
private uint _priority = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所属包裹名称
|
/// 所属包裹名称
|
||||||
@@ -19,7 +20,23 @@ namespace YooAsset
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 调度器优先级(值越大越优先)
|
/// 调度器优先级(值越大越优先)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Priority { private set; get; }
|
public uint Priority
|
||||||
|
{
|
||||||
|
get { return _priority; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_priority != value)
|
||||||
|
{
|
||||||
|
_priority = value;
|
||||||
|
IsDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 优先级是否已变更(需要重新排序)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDirty { set; get; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建顺序(用于同优先级稳定排序)
|
/// 创建顺序(用于同优先级稳定排序)
|
||||||
@@ -27,10 +44,9 @@ namespace YooAsset
|
|||||||
public int CreateIndex { private set; get; }
|
public int CreateIndex { private set; get; }
|
||||||
|
|
||||||
|
|
||||||
public OperationScheduler(string packageName, int priority, int createIndex)
|
public OperationScheduler(string packageName, int createIndex)
|
||||||
{
|
{
|
||||||
PackageName = packageName;
|
PackageName = packageName;
|
||||||
Priority = priority;
|
|
||||||
CreateIndex = createIndex;
|
CreateIndex = createIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +120,6 @@ namespace YooAsset
|
|||||||
foreach (var operation in _newList)
|
foreach (var operation in _newList)
|
||||||
{
|
{
|
||||||
operation.AbortOperation();
|
operation.AbortOperation();
|
||||||
operation.FinishOperation(); //注意:强制收尾,确保Task能完成
|
|
||||||
}
|
}
|
||||||
_newList.Clear();
|
_newList.Clear();
|
||||||
|
|
||||||
@@ -112,7 +127,6 @@ namespace YooAsset
|
|||||||
foreach (var operation in _operations)
|
foreach (var operation in _operations)
|
||||||
{
|
{
|
||||||
operation.AbortOperation();
|
operation.AbortOperation();
|
||||||
operation.FinishOperation(); //注意:强制收尾,确保Task能完成
|
|
||||||
}
|
}
|
||||||
_operations.Clear();
|
_operations.Clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Diagnostics;
|
|||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
internal class OperationSystem
|
internal static class OperationSystem
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
|
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
@@ -21,7 +21,6 @@ namespace YooAsset
|
|||||||
private static readonly Dictionary<string, OperationScheduler> _schedulerDic = new Dictionary<string, OperationScheduler>(100);
|
private static readonly Dictionary<string, OperationScheduler> _schedulerDic = new Dictionary<string, OperationScheduler>(100);
|
||||||
private static readonly List<OperationScheduler> _schedulerList = new List<OperationScheduler>(100);
|
private static readonly List<OperationScheduler> _schedulerList = new List<OperationScheduler>(100);
|
||||||
private static bool _isInitialize = false;
|
private static bool _isInitialize = false;
|
||||||
private static bool _schedulerListDirty = false;
|
|
||||||
private static int _createIndex = 0;
|
private static int _createIndex = 0;
|
||||||
|
|
||||||
// 计时器相关
|
// 计时器相关
|
||||||
@@ -56,12 +55,15 @@ namespace YooAsset
|
|||||||
/// 初始化异步操作系统
|
/// 初始化异步操作系统
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
if (_isInitialize == false)
|
||||||
{
|
{
|
||||||
_isInitialize = true;
|
_isInitialize = true;
|
||||||
_watch = Stopwatch.StartNew();
|
_watch = Stopwatch.StartNew();
|
||||||
|
|
||||||
// 创建全局调度器
|
// 创建全局调度器
|
||||||
CreatePackageScheduler(GLOBAL_SCHEDULER_NAME, 0);
|
CreatePackageScheduler(GLOBAL_SCHEDULER_NAME, uint.MaxValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -72,10 +74,18 @@ namespace YooAsset
|
|||||||
if (_isInitialize == false)
|
if (_isInitialize == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 重新排序调度器
|
// 检测是否需要执行排序
|
||||||
if (_schedulerListDirty)
|
bool isDirty = false;
|
||||||
|
foreach (var scheduler in _schedulerList)
|
||||||
|
{
|
||||||
|
if (scheduler.IsDirty)
|
||||||
|
{
|
||||||
|
scheduler.IsDirty = false;
|
||||||
|
isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isDirty)
|
||||||
{
|
{
|
||||||
_schedulerListDirty = false;
|
|
||||||
_schedulerList.Sort();
|
_schedulerList.Sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +107,9 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static void DestroyAll()
|
public static void DestroyAll()
|
||||||
{
|
{
|
||||||
|
_isInitialize = false;
|
||||||
|
YooLogger.Log("Operation system destroy all !");
|
||||||
|
|
||||||
// 清空所有调度器
|
// 清空所有调度器
|
||||||
foreach (var scheduler in _schedulerList)
|
foreach (var scheduler in _schedulerList)
|
||||||
{
|
{
|
||||||
@@ -104,9 +117,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
_schedulerDic.Clear();
|
_schedulerDic.Clear();
|
||||||
_schedulerList.Clear();
|
_schedulerList.Clear();
|
||||||
_schedulerListDirty = false;
|
|
||||||
_createIndex = 0;
|
_createIndex = 0;
|
||||||
_isInitialize = false;
|
|
||||||
|
|
||||||
_watch = null;
|
_watch = null;
|
||||||
_frameTime = 0;
|
_frameTime = 0;
|
||||||
@@ -116,17 +127,20 @@ namespace YooAsset
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建包裹调度器
|
/// 创建包裹调度器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void CreatePackageScheduler(string packageName, int priority)
|
public static OperationScheduler CreatePackageScheduler(string packageName, uint priority)
|
||||||
{
|
{
|
||||||
|
DebugCheckInitialize(packageName);
|
||||||
|
|
||||||
if (_schedulerDic.ContainsKey(packageName))
|
if (_schedulerDic.ContainsKey(packageName))
|
||||||
{
|
{
|
||||||
throw new YooInternalException($"Package scheduler already exists: {packageName}");
|
throw new YooInternalException($"Package scheduler already exists: {packageName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var scheduler = new OperationScheduler(packageName, priority, _createIndex++);
|
var scheduler = new OperationScheduler(packageName, _createIndex++);
|
||||||
_schedulerDic.Add(packageName, scheduler);
|
_schedulerDic.Add(packageName, scheduler);
|
||||||
_schedulerList.Add(scheduler);
|
_schedulerList.Add(scheduler);
|
||||||
_schedulerListDirty = true;
|
scheduler.Priority = priority;
|
||||||
|
return scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -134,6 +148,8 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static void DestroyPackageScheduler(string packageName)
|
public static void DestroyPackageScheduler(string packageName)
|
||||||
{
|
{
|
||||||
|
DebugCheckInitialize(packageName);
|
||||||
|
|
||||||
// 不允许销毁默认调度器
|
// 不允许销毁默认调度器
|
||||||
if (packageName == GLOBAL_SCHEDULER_NAME)
|
if (packageName == GLOBAL_SCHEDULER_NAME)
|
||||||
{
|
{
|
||||||
@@ -153,6 +169,8 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static void ClearPackageOperation(string packageName)
|
public static void ClearPackageOperation(string packageName)
|
||||||
{
|
{
|
||||||
|
DebugCheckInitialize(packageName);
|
||||||
|
|
||||||
var scheduler = GetScheduler(packageName);
|
var scheduler = GetScheduler(packageName);
|
||||||
scheduler.ClearAll();
|
scheduler.ClearAll();
|
||||||
}
|
}
|
||||||
@@ -162,10 +180,34 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static void StartOperation(string packageName, AsyncOperationBase operation)
|
public static void StartOperation(string packageName, AsyncOperationBase operation)
|
||||||
{
|
{
|
||||||
|
DebugCheckInitialize(packageName);
|
||||||
|
|
||||||
var scheduler = GetScheduler(packageName);
|
var scheduler = GetScheduler(packageName);
|
||||||
scheduler.StartOperation(operation);
|
scheduler.StartOperation(operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置调度器优先级
|
||||||
|
/// </summary>
|
||||||
|
public static void SetSchedulerPriority(string packageName, uint priority)
|
||||||
|
{
|
||||||
|
DebugCheckInitialize(packageName);
|
||||||
|
|
||||||
|
var scheduler = GetScheduler(packageName);
|
||||||
|
scheduler.Priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取调度器优先级
|
||||||
|
/// </summary>
|
||||||
|
public static uint GetSchedulerPriority(string packageName)
|
||||||
|
{
|
||||||
|
DebugCheckInitialize(packageName);
|
||||||
|
|
||||||
|
var scheduler = GetScheduler(packageName);
|
||||||
|
return scheduler.Priority;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取调度器(严格模式)
|
/// 获取调度器(严格模式)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -177,15 +219,29 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 严格模式:非默认包裹必须先创建调度器
|
// 严格模式:非默认包裹必须先创建调度器
|
||||||
throw new YooInternalException($"Package scheduler not found: {packageName}. Please call YooAssets.CreatePackage() first!");
|
throw new YooInternalException($"Operation scheduler not found: {packageName}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 调试信息
|
#region 调试信息
|
||||||
internal static List<DebugOperationInfo> GetDebugOperationInfos(string packageName)
|
internal static List<DebugOperationInfo> GetDebugOperationInfos(string packageName)
|
||||||
{
|
{
|
||||||
|
DebugCheckInitialize(packageName);
|
||||||
|
|
||||||
var scheduler = GetScheduler(packageName);
|
var scheduler = GetScheduler(packageName);
|
||||||
return scheduler.GetDebugOperationInfos();
|
return scheduler.GetDebugOperationInfos();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region 调试方法
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
private static void DebugCheckInitialize(string packageName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(packageName))
|
||||||
|
throw new YooInternalException("Package name is null or empty.");
|
||||||
|
|
||||||
|
if (_isInitialize == false)
|
||||||
|
throw new YooInternalException($"{nameof(OperationSystem)} not initialized !");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,6 +217,16 @@ public static void ClearPackageOperation(string packageName);
|
|||||||
/// 启动异步操作
|
/// 启动异步操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void StartOperation(string packageName, AsyncOperationBase operation);
|
public static void StartOperation(string packageName, AsyncOperationBase operation);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置调度器优先级
|
||||||
|
/// </summary>
|
||||||
|
public static void SetSchedulerPriority(string packageName, uint priority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取调度器优先级
|
||||||
|
/// </summary>
|
||||||
|
public static uint GetSchedulerPriority(string packageName);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 包裹调度说明
|
#### 包裹调度说明
|
||||||
@@ -227,16 +237,16 @@ public static void StartOperation(string packageName, AsyncOperationBase operati
|
|||||||
|
|
||||||
#### 回调监听
|
#### 回调监听
|
||||||
|
|
||||||
```csharp
|
OperationSystem **当前未提供**全局任务开始/结束回调的注册接口。
|
||||||
/// <summary>
|
|
||||||
/// 注册任务开始回调
|
|
||||||
/// </summary>
|
|
||||||
public static void RegisterStartCallback(Action<string, AsyncOperationBase> callback);
|
|
||||||
|
|
||||||
/// <summary>
|
如需监听任务结束(推荐),请直接订阅具体任务的 `Completed` 事件:
|
||||||
/// 注册任务结束回调
|
|
||||||
/// </summary>
|
```csharp
|
||||||
public static void RegisterFinishCallback(Action<string, AsyncOperationBase> callback);
|
var operation = package.LoadAssetAsync<GameObject>(location);
|
||||||
|
operation.Completed += op =>
|
||||||
|
{
|
||||||
|
// TODO : 根据 op.Status 判断成功/失败
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -315,14 +325,36 @@ void LoadAssetSync()
|
|||||||
|
|
||||||
操作按 `Priority` 属性降序排列,优先级高的操作先执行。
|
操作按 `Priority` 属性降序排列,优先级高的操作先执行。
|
||||||
|
|
||||||
|
#### 操作优先级
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var operation = package.LoadAssetAsync<GameObject>(location);
|
var operation = package.LoadAssetAsync<GameObject>(location);
|
||||||
operation.Priority = 100; // 设置高优先级
|
operation.Priority = 100; // 设置高优先级
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 包裹优先级
|
||||||
|
|
||||||
|
通过 `ResourcePackage.PackagePriority` 可以设置包裹的调度器优先级,值越大越优先更新。
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 创建包裹时指定优先级
|
||||||
|
var package = YooAssets.CreatePackage("MyPackage", 100);
|
||||||
|
|
||||||
|
// 运行时动态调整优先级
|
||||||
|
package.PackagePriority = 200;
|
||||||
|
|
||||||
|
// 获取当前优先级
|
||||||
|
uint priority = package.PackagePriority;
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用场景:**
|
||||||
|
- 多包裹场景下,可根据游戏状态动态调整包裹优先级
|
||||||
|
- 例如:进入战斗时提高战斗资源包的优先级,退出战斗时恢复默认优先级
|
||||||
|
|
||||||
**排序规则:**
|
**排序规则:**
|
||||||
- 新操作添加时:若新增队列存在非零优先级,则触发排序
|
- 新操作添加时:若新增队列存在非零优先级,则触发排序
|
||||||
- 运行时修改 `Priority`:会在下一次调度器更新时自动触发重排(即时生效,通常为下一帧)
|
- 运行中修改 `Priority`:调度器会在每帧 `Update()` 的排序阶段检测 `IsDirty` 并触发重排;若在某个操作的 `InternalUpdate()` 内修改(本帧排序已完成),则新的优先级会延后一帧生效(可能与预期不符)
|
||||||
|
- 若期望本帧生效:请尽量在任务入队前或本帧调度器 `Update()` 开始前设置 `Priority`,避免在 `InternalUpdate()` 内临时调整
|
||||||
- 排序使用 `List.Sort()` 进行原地排序;频繁修改优先级会带来额外排序开销,建议按需使用
|
- 排序使用 `List.Sort()` 进行原地排序;频繁修改优先级会带来额外排序开销,建议按需使用
|
||||||
|
|
||||||
### 时间切片
|
### 时间切片
|
||||||
@@ -514,4 +546,4 @@ IEnumerator + IComparable<AsyncOperationBase>
|
|||||||
4. **子任务中止**:父操作中止时会自动中止所有子操作
|
4. **子任务中止**:父操作中止时会自动中止所有子操作
|
||||||
5. **回调异常**:`Completed` 回调中的异常会被捕获并记录,不会中断系统
|
5. **回调异常**:`Completed` 回调中的异常会被捕获并记录,不会中断系统
|
||||||
6. **编辑器重置**:编辑器中使用 `RuntimeInitializeOnLoadMethod` 自动重置状态
|
6. **编辑器重置**:编辑器中使用 `RuntimeInitializeOnLoadMethod` 自动重置状态
|
||||||
7. **循环保护**:在 `InternalWaitForAsyncComplete()` 中如果使用 `ExecuteWhileDone()`,内部默认有 1000 次执行保护,防止无限循环
|
7. **循环保护**:在 `InternalWaitForAsyncComplete()` 中建议使用 `RunBatchExecution()`(默认 1000 次)限制单次推进次数,避免陷入无限循环或长时间占用主线程
|
||||||
|
|||||||
@@ -44,6 +44,15 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 包裹优先级(值越大越优先更新)
|
||||||
|
/// </summary>
|
||||||
|
public uint PackagePriority
|
||||||
|
{
|
||||||
|
get { return OperationSystem.GetSchedulerPriority(PackageName); }
|
||||||
|
set { OperationSystem.SetSchedulerPriority(PackageName, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
internal ResourcePackage(string packageName)
|
internal ResourcePackage(string packageName)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,27 @@ using System.Text;
|
|||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 时间工具类
|
||||||
|
/// </summary>
|
||||||
|
internal static class TimeUtility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The real time in seconds since the game started
|
||||||
|
/// </summary>
|
||||||
|
public static double RealtimeSinceStartup
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if UNITY_2020_3_OR_NEWER
|
||||||
|
return UnityEngine.Time.realtimeSinceStartupAsDouble;
|
||||||
|
#else
|
||||||
|
return UnityEngine.Time.realtimeSinceStartup;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 路径工具类
|
/// 路径工具类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ namespace YooAsset
|
|||||||
_driver.AddComponent<RemoteDebuggerInRuntime>();
|
_driver.AddComponent<RemoteDebuggerInRuntime>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// 初始化异步操作系统
|
||||||
OperationSystem.Initialize();
|
OperationSystem.Initialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,8 +76,8 @@ namespace YooAsset
|
|||||||
if (_driver != null)
|
if (_driver != null)
|
||||||
GameObject.Destroy(_driver);
|
GameObject.Destroy(_driver);
|
||||||
|
|
||||||
// 终止并清空所有包裹的异步操作
|
// 销毁异步操作系统
|
||||||
ClearAllPackageOperation();
|
OperationSystem.DestroyAll();
|
||||||
|
|
||||||
// 卸载所有AssetBundle
|
// 卸载所有AssetBundle
|
||||||
AssetBundle.UnloadAllAssetBundles(true);
|
AssetBundle.UnloadAllAssetBundles(true);
|
||||||
@@ -97,18 +98,6 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 终止并清空所有包裹的异步操作
|
|
||||||
/// </summary>
|
|
||||||
internal static void ClearAllPackageOperation()
|
|
||||||
{
|
|
||||||
foreach (var package in _packages)
|
|
||||||
{
|
|
||||||
OperationSystem.ClearPackageOperation(package.PackageName);
|
|
||||||
}
|
|
||||||
OperationSystem.DestroyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建资源包裹
|
/// 创建资源包裹
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -123,7 +112,7 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="packageName">包裹名称</param>
|
/// <param name="packageName">包裹名称</param>
|
||||||
/// <param name="packagePriority">包裹优先级(值越大越优先更新)</param>
|
/// <param name="packagePriority">包裹优先级(值越大越优先更新)</param>
|
||||||
public static ResourcePackage CreatePackage(string packageName, int packagePriority)
|
public static ResourcePackage CreatePackage(string packageName, uint packagePriority)
|
||||||
{
|
{
|
||||||
CheckException(packageName);
|
CheckException(packageName);
|
||||||
if (ContainsPackage(packageName))
|
if (ContainsPackage(packageName))
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace YooAsset
|
|||||||
void OnApplicationQuit()
|
void OnApplicationQuit()
|
||||||
{
|
{
|
||||||
// 说明:在编辑器下确保播放被停止时IO类操作被终止。
|
// 说明:在编辑器下确保播放被停止时IO类操作被终止。
|
||||||
YooAssets.ClearAllPackageOperation();
|
YooAssets.Destroy();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user