using System; using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; namespace YooAsset { public abstract class AsyncOperationBase : IEnumerator, IComparable { private Action _callback; private string _packageName = null; private int _whileFrame = 1000; /// /// 所有子任务 /// internal readonly List Childs = new List(10); /// /// 等待异步执行完成 /// internal bool IsWaitForAsyncComplete { private set; get; } = false; /// /// 是否已经完成 /// internal bool IsFinish { private set; get; } = false; /// /// 任务优先级 /// public uint Priority { set; get; } = 0; /// /// 任务状态 /// public EOperationStatus Status { get; protected set; } = EOperationStatus.None; /// /// 错误信息 /// public string Error { get; protected set; } /// /// 处理进度 /// public float Progress { get; protected set; } /// /// 所属包裹名称 /// public string PackageName { get { return _packageName; } } /// /// 是否已经完成 /// public bool IsDone { get { return Status == EOperationStatus.Failed || Status == EOperationStatus.Succeed; } } /// /// 完成事件 /// public event Action Completed { add { if (IsDone) value.Invoke(this); else _callback += value; } remove { _callback -= value; } } /// /// 异步操作任务 /// public Task Task { get { if (_taskCompletionSource == null) { _taskCompletionSource = new TaskCompletionSource(); if (IsDone) _taskCompletionSource.SetResult(null); } return _taskCompletionSource.Task; } } internal abstract void InternalStart(); internal abstract void InternalUpdate(); internal virtual void InternalAbort() { } internal virtual void InternalWaitForAsyncComplete() { throw new System.NotImplementedException(this.GetType().Name); } internal virtual string InternalGetDesc() { return string.Empty; } /// /// 设置包裹名称 /// internal void SetPackageName(string packageName) { _packageName = packageName; } /// /// 添加子任务 /// internal void AddChildOperation(AsyncOperationBase child) { #if UNITY_EDITOR if (Childs.Contains(child)) throw new Exception($"The child node {child.GetType().Name} already exists !"); #endif Childs.Add(child); } /// /// 获取异步操作说明 /// internal string GetOperationDesc() { return InternalGetDesc(); } /// /// 开始异步操作 /// internal void StartOperation() { if (Status == EOperationStatus.None) { Status = EOperationStatus.Processing; // 开始记录 DebugBeginRecording(); // 开始任务 InternalStart(); } } /// /// 更新异步操作 /// internal void UpdateOperation() { if (IsDone == false) { // 更新记录 DebugUpdateRecording(); // 更新任务 InternalUpdate(); } if (IsDone && IsFinish == false) { IsFinish = true; // 进度百分百完成 Progress = 1f; // 结束记录 DebugEndRecording(); //注意:如果完成回调内发生异常,会导致Task无限期等待 _callback?.Invoke(this); if (_taskCompletionSource != null) _taskCompletionSource.TrySetResult(null); } } /// /// 终止异步任务 /// internal void AbortOperation() { foreach (var child in Childs) { child.AbortOperation(); } if (IsDone == false) { Status = EOperationStatus.Failed; Error = "user abort"; YooLogger.Warning($"Async operaiton {this.GetType().Name} has been abort !"); InternalAbort(); } } /// /// 执行While循环 /// protected bool ExecuteWhileDone() { if (IsDone == false) { // 执行更新逻辑 InternalUpdate(); // 当执行次数用完时 _whileFrame--; if (_whileFrame <= 0) { Status = EOperationStatus.Failed; Error = $"Operation {this.GetType().Name} failed to wait for async complete !"; YooLogger.Error(Error); } } return IsDone; } /// /// 清空完成回调 /// protected void ClearCompletedCallback() { _callback = null; } /// /// 等待异步执行完毕 /// public void WaitForAsyncComplete() { if (IsDone) return; //TODO 防止异步操作被挂起陷入无限死循环! // 例如:文件解压任务或者文件导入任务! if (Status == EOperationStatus.None) { StartOperation(); } IsWaitForAsyncComplete = true; InternalWaitForAsyncComplete(); } #region 调试信息 /// /// 开始的时间 /// public string BeginTime = string.Empty; /// /// 处理耗时(单位:毫秒) /// public long ProcessTime { protected set; get; } // 加载耗时统计 private Stopwatch _watch = null; [Conditional("DEBUG")] private void DebugBeginRecording() { if (_watch == null) { BeginTime = SpawnTimeToString(UnityEngine.Time.realtimeSinceStartup); _watch = Stopwatch.StartNew(); } } [Conditional("DEBUG")] private void DebugUpdateRecording() { if (_watch != null) { ProcessTime = _watch.ElapsedMilliseconds; } } [Conditional("DEBUG")] private void DebugEndRecording() { if (_watch != null) { ProcessTime = _watch.ElapsedMilliseconds; _watch = null; } } private string SpawnTimeToString(float spawnTime) { float h = UnityEngine.Mathf.FloorToInt(spawnTime / 3600f); float m = UnityEngine.Mathf.FloorToInt(spawnTime / 60f - h * 60f); float s = UnityEngine.Mathf.FloorToInt(spawnTime - m * 60f - h * 3600f); return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00"); } #endregion #region 排序接口实现 public int CompareTo(AsyncOperationBase other) { return other.Priority.CompareTo(this.Priority); } #endregion #region 异步编程相关 bool IEnumerator.MoveNext() { return !IsDone; } void IEnumerator.Reset() { } object IEnumerator.Current => null; private TaskCompletionSource _taskCompletionSource; #endregion } }