diff --git a/Assets/YooAsset/Runtime/OperationSystem/AsyncOperationBase.cs b/Assets/YooAsset/Runtime/OperationSystem/AsyncOperationBase.cs index 64d59e86..cb621a75 100644 --- a/Assets/YooAsset/Runtime/OperationSystem/AsyncOperationBase.cs +++ b/Assets/YooAsset/Runtime/OperationSystem/AsyncOperationBase.cs @@ -228,7 +228,18 @@ namespace YooAsset DebugUpdateRecording(); // 更新任务 - InternalUpdate(); + // 注意:兜底隔离机制 + // 说明:检测的异常源包含:I/O(解压/读写权限/磁盘满),平台差异等 + try + { + InternalUpdate(); + } + catch (Exception ex) + { + Status = EOperationStatus.Failed; + Error = ex.ToString(); + YooLogger.Error($"Exception in {this.GetType().Name}.InternalUpdate : {ex}"); + } } if (IsDone && IsFinish == false) @@ -353,7 +364,6 @@ namespace YooAsset public void WaitForAsyncComplete() { //TODO 防止异步操作被挂起陷入无限死循环! - // 例如:文件解压任务或者文件导入任务! if (Status == EOperationStatus.None) { StartOperation(); diff --git a/Assets/YooAsset/Runtime/OperationSystem/OperationSystem.cs b/Assets/YooAsset/Runtime/OperationSystem/OperationSystem.cs index 876c4aba..e72de0df 100644 --- a/Assets/YooAsset/Runtime/OperationSystem/OperationSystem.cs +++ b/Assets/YooAsset/Runtime/OperationSystem/OperationSystem.cs @@ -5,7 +5,7 @@ using System.Diagnostics; namespace YooAsset { - internal class OperationSystem + internal static class OperationSystem { #if UNITY_EDITOR [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)] @@ -57,11 +57,14 @@ namespace YooAsset /// public static void Initialize() { - _isInitialize = true; - _watch = Stopwatch.StartNew(); + if (_isInitialize == false) + { + _isInitialize = true; + _watch = Stopwatch.StartNew(); - // 创建全局调度器 - CreatePackageScheduler(GLOBAL_SCHEDULER_NAME, 0); + // 创建全局调度器 + CreatePackageScheduler(GLOBAL_SCHEDULER_NAME, int.MaxValue); + } } /// @@ -97,6 +100,7 @@ namespace YooAsset /// public static void DestroyAll() { + _isInitialize = false; YooLogger.Log("Operation system destroy all !"); // 清空所有调度器 @@ -108,7 +112,6 @@ namespace YooAsset _schedulerList.Clear(); _schedulerListDirty = false; _createIndex = 0; - _isInitialize = false; _watch = null; _frameTime = 0; @@ -120,6 +123,8 @@ namespace YooAsset /// public static void CreatePackageScheduler(string packageName, int priority) { + DebugCheckInitialize(packageName); + if (_schedulerDic.ContainsKey(packageName)) { throw new YooInternalException($"Package scheduler already exists: {packageName}"); @@ -136,6 +141,8 @@ namespace YooAsset /// public static void DestroyPackageScheduler(string packageName) { + DebugCheckInitialize(packageName); + // 不允许销毁默认调度器 if (packageName == GLOBAL_SCHEDULER_NAME) { @@ -155,6 +162,8 @@ namespace YooAsset /// public static void ClearPackageOperation(string packageName) { + DebugCheckInitialize(packageName); + var scheduler = GetScheduler(packageName); scheduler.ClearAll(); } @@ -164,6 +173,8 @@ namespace YooAsset /// public static void StartOperation(string packageName, AsyncOperationBase operation) { + DebugCheckInitialize(packageName); + var scheduler = GetScheduler(packageName); scheduler.StartOperation(operation); } @@ -179,15 +190,29 @@ namespace YooAsset } // 严格模式:非默认包裹必须先创建调度器 - throw new YooInternalException($"Operation scheduler not found: {packageName}. Please call YooAssets.CreatePackage() first!"); + throw new YooInternalException($"Operation scheduler not found: {packageName}."); } #region 调试信息 internal static List GetDebugOperationInfos(string packageName) { + DebugCheckInitialize(packageName); + var scheduler = GetScheduler(packageName); return scheduler.GetDebugOperationInfos(); } #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 } } diff --git a/Assets/YooAsset/Runtime/OperationSystem/README.md b/Assets/YooAsset/Runtime/OperationSystem/README.md index 128659b4..5cd39d31 100644 --- a/Assets/YooAsset/Runtime/OperationSystem/README.md +++ b/Assets/YooAsset/Runtime/OperationSystem/README.md @@ -227,16 +227,16 @@ public static void StartOperation(string packageName, AsyncOperationBase operati #### 回调监听 -```csharp -/// -/// 注册任务开始回调 -/// -public static void RegisterStartCallback(Action callback); +OperationSystem **当前未提供**全局任务开始/结束回调的注册接口。 -/// -/// 注册任务结束回调 -/// -public static void RegisterFinishCallback(Action callback); +如需监听任务结束(推荐),请直接订阅具体任务的 `Completed` 事件: + +```csharp +var operation = package.LoadAssetAsync(location); +operation.Completed += op => +{ + // TODO : 根据 op.Status 判断成功/失败 +}; ``` --- @@ -515,4 +515,4 @@ IEnumerator + IComparable 4. **子任务中止**:父操作中止时会自动中止所有子操作 5. **回调异常**:`Completed` 回调中的异常会被捕获并记录,不会中断系统 6. **编辑器重置**:编辑器中使用 `RuntimeInitializeOnLoadMethod` 自动重置状态 -7. **循环保护**:在 `InternalWaitForAsyncComplete()` 中如果使用 `ExecuteWhileDone()`,内部默认有 1000 次执行保护,防止无限循环 +7. **循环保护**:在 `InternalWaitForAsyncComplete()` 中建议使用 `RunBatchExecution()`(默认 1000 次)限制单次推进次数,避免陷入无限循环或长时间占用主线程