using System; using System.Collections.Generic; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.ResourceManagement.Exceptions; using UnityEngine.ResourceManagement.Util; namespace UnityEngine.ResourceManagement { class ChainOperation : AsyncOperationBase { AsyncOperationHandle m_DepOp; AsyncOperationHandle m_WrappedOp; DownloadStatus m_depStatus = default; DownloadStatus m_wrapStatus = default; Func, AsyncOperationHandle> m_Callback; Action> m_CachedOnWrappedCompleted; bool m_ReleaseDependenciesOnFailure = true; public ChainOperation() { m_CachedOnWrappedCompleted = OnWrappedCompleted; } protected override string DebugName { get { return $"ChainOperation<{typeof(TObject).Name},{typeof(TObjectDependency).Name}> - {m_DepOp.DebugName}"; } } /// public override void GetDependencies(List deps) { if (m_DepOp.IsValid()) deps.Add(m_DepOp); } public void Init(AsyncOperationHandle dependentOp, Func, AsyncOperationHandle> callback, bool releaseDependenciesOnFailure) { m_DepOp = dependentOp; m_DepOp.Acquire(); m_Callback = callback; m_ReleaseDependenciesOnFailure = releaseDependenciesOnFailure; RefreshDownloadStatus(); } /// protected override bool InvokeWaitForCompletion() { if (IsDone) return true; if (!m_DepOp.IsDone) m_DepOp.WaitForCompletion(); m_RM?.Update(Time.unscaledDeltaTime); if (!HasExecuted) InvokeExecute(); if (!m_WrappedOp.IsValid()) return m_WrappedOp.IsDone; m_WrappedOp.WaitForCompletion(); return m_WrappedOp.IsDone; } protected override void Execute() { m_WrappedOp = m_Callback(m_DepOp); m_WrappedOp.Completed += m_CachedOnWrappedCompleted; m_Callback = null; } private void OnWrappedCompleted(AsyncOperationHandle x) { OperationException ex = null; if (x.Status == AsyncOperationStatus.Failed) ex = new OperationException($"ChainOperation failed because dependent operation failed", x.OperationException); Complete(m_WrappedOp.Result, x.Status == AsyncOperationStatus.Succeeded, ex, m_ReleaseDependenciesOnFailure); } protected override void Destroy() { if (m_WrappedOp.IsValid()) m_WrappedOp.Release(); if (m_DepOp.IsValid()) m_DepOp.Release(); } internal override void ReleaseDependencies() { if (m_DepOp.IsValid()) m_DepOp.Release(); } internal override DownloadStatus GetDownloadStatus(HashSet visited) { RefreshDownloadStatus(visited); return new DownloadStatus() {DownloadedBytes = m_depStatus.DownloadedBytes + m_wrapStatus.DownloadedBytes, TotalBytes = m_depStatus.TotalBytes + m_wrapStatus.TotalBytes, IsDone = IsDone}; } void RefreshDownloadStatus(HashSet visited = default) { m_depStatus = m_DepOp.IsValid() ? m_DepOp.InternalGetDownloadStatus(visited) : m_depStatus; m_wrapStatus = m_WrappedOp.IsValid() ? m_WrappedOp.InternalGetDownloadStatus(visited) : m_wrapStatus; } protected override float Progress { get { DownloadStatus downloadStatus = GetDownloadStatus(new HashSet()); if (!downloadStatus.IsDone && downloadStatus.DownloadedBytes == 0) return 0.0f; float total = 0f; int numberOfOps = 2; if (m_DepOp.IsValid()) total += m_DepOp.PercentComplete; else total++; if (m_WrappedOp.IsValid()) total += m_WrappedOp.PercentComplete; else total++; return total / numberOfOps; } } } class ChainOperationTypelessDepedency : AsyncOperationBase { AsyncOperationHandle m_DepOp; AsyncOperationHandle m_WrappedOp; DownloadStatus m_depStatus = default; DownloadStatus m_wrapStatus = default; Func> m_Callback; Action> m_CachedOnWrappedCompleted; bool m_ReleaseDependenciesOnFailure = true; internal AsyncOperationHandle WrappedOp => m_WrappedOp; public ChainOperationTypelessDepedency() { m_CachedOnWrappedCompleted = OnWrappedCompleted; } protected override string DebugName { get { return $"ChainOperation<{typeof(TObject).Name}> - {m_DepOp.DebugName}"; } } /// public override void GetDependencies(List deps) { if (m_DepOp.IsValid()) deps.Add(m_DepOp); } public void Init(AsyncOperationHandle dependentOp, Func> callback, bool releaseDependenciesOnFailure) { m_DepOp = dependentOp; m_DepOp.Acquire(); m_Callback = callback; m_ReleaseDependenciesOnFailure = releaseDependenciesOnFailure; RefreshDownloadStatus(); } /// protected override bool InvokeWaitForCompletion() { if (IsDone) return true; if (!m_DepOp.IsDone) m_DepOp.WaitForCompletion(); m_RM?.Update(Time.unscaledDeltaTime); if (!HasExecuted) InvokeExecute(); if (!m_WrappedOp.IsValid()) return m_WrappedOp.IsDone; Result = m_WrappedOp.WaitForCompletion(); return true; } protected override void Execute() { m_WrappedOp = m_Callback(m_DepOp); m_WrappedOp.Completed += m_CachedOnWrappedCompleted; m_Callback = null; } private void OnWrappedCompleted(AsyncOperationHandle x) { OperationException ex = null; if (x.Status == AsyncOperationStatus.Failed) ex = new OperationException($"ChainOperation failed because dependent operation failed", x.OperationException); Complete(m_WrappedOp.Result, x.Status == AsyncOperationStatus.Succeeded, ex, m_ReleaseDependenciesOnFailure); } protected override void Destroy() { if (m_WrappedOp.IsValid()) m_WrappedOp.Release(); if (m_DepOp.IsValid()) m_DepOp.Release(); } internal override void ReleaseDependencies() { if (m_DepOp.IsValid()) m_DepOp.Release(); } internal override DownloadStatus GetDownloadStatus(HashSet visited) { RefreshDownloadStatus(visited); return new DownloadStatus() {DownloadedBytes = m_depStatus.DownloadedBytes + m_wrapStatus.DownloadedBytes, TotalBytes = m_depStatus.TotalBytes + m_wrapStatus.TotalBytes, IsDone = IsDone}; } void RefreshDownloadStatus(HashSet visited = default) { m_depStatus = m_DepOp.IsValid() ? m_DepOp.InternalGetDownloadStatus(visited) : m_depStatus; m_wrapStatus = m_WrappedOp.IsValid() ? m_WrappedOp.InternalGetDownloadStatus(visited) : m_wrapStatus; } protected override float Progress { get { DownloadStatus downloadStatus = GetDownloadStatus(new HashSet()); if (!downloadStatus.IsDone && downloadStatus.DownloadedBytes == 0) return 0.0f; float total = 0f; int numberOfOps = 2; if (m_DepOp.IsValid()) total += m_DepOp.PercentComplete; else total++; if (m_WrappedOp.IsValid()) total += m_WrappedOp.PercentComplete; else total++; return total / numberOfOps; } } } }