using System; using System.Collections.Generic; using System.Security; using UnityEngine.ResourceManagement.Exceptions; using UnityEngine.ResourceManagement.ResourceLocations; using UnityEngine.ResourceManagement.ResourceProviders; using UnityEngine.ResourceManagement.Util; namespace UnityEngine.ResourceManagement.AsyncOperations { class GroupOperation : AsyncOperationBase>, ICachable { [Flags] public enum GroupOperationSettings { None = 0, ReleaseDependenciesOnFailure = 1, AllowFailedDependencies = 2 } Action m_InternalOnComplete; int m_LoadedCount; GroupOperationSettings m_Settings; string debugName = null; private const int k_MaxDisplayedLocationLength = 45; public GroupOperation() { m_InternalOnComplete = OnOperationCompleted; Result = new List(); } /// protected override bool InvokeWaitForCompletion() { //If Result is null then we've auto released and need to return if (IsDone || Result == null) return true; foreach (var r in Result) { r.WaitForCompletion(); if (Result == null) return true; } m_RM?.Update(Time.unscaledDeltaTime); if (!IsDone && Result != null) Execute(); m_RM?.Update(Time.unscaledDeltaTime); return IsDone; } IOperationCacheKey ICachable.Key { get; set; } internal IList GetDependentOps() { return Result; } /// public override void GetDependencies(List deps) { deps.AddRange(Result); } internal override void ReleaseDependencies() { for (int i = 0; i < Result.Count; i++) if (Result[i].IsValid()) Result[i].Release(); Result.Clear(); } internal override DownloadStatus GetDownloadStatus(HashSet visited) { var status = new DownloadStatus() {IsDone = IsDone}; for (int i = 0; i < Result.Count; i++) { if (Result[i].IsValid()) { var depStatus = Result[i].InternalGetDownloadStatus(visited); status.DownloadedBytes += depStatus.DownloadedBytes; status.TotalBytes += depStatus.TotalBytes; } } return status; } HashSet m_CachedDependencyLocations = new HashSet(); private bool DependenciesAreUnchanged(List deps) { if (m_CachedDependencyLocations.Count != deps.Count) return false; foreach (var d in deps) if (!m_CachedDependencyLocations.Contains(d.LocationName)) return false; return true; } protected override string DebugName { get { List deps = new List(); GetDependencies(deps); if (deps.Count == 0) return "Dependencies"; //Only recalculate DebugName if a name hasn't been generated for currently held dependencies if (debugName != null && DependenciesAreUnchanged(deps)) return debugName; m_CachedDependencyLocations.Clear(); string toBeDisplayed = "Dependencies ["; for (var i = 0; i < deps.Count; i++) { var d = deps[i]; var locationString = d.LocationName; m_CachedDependencyLocations.Add(locationString); if (locationString == null) continue; //Prevent location display from being excessively long if (locationString.Length > k_MaxDisplayedLocationLength) { locationString = AsyncOperationBase.ShortenPath(locationString, true); locationString = locationString.Substring(0, Math.Min(k_MaxDisplayedLocationLength, locationString.Length)) + "..."; } if (i == deps.Count - 1) toBeDisplayed += locationString; else toBeDisplayed += locationString + ", "; } toBeDisplayed += "]"; debugName = toBeDisplayed; return debugName; } } protected override void Execute() { m_LoadedCount = 0; for (int i = 0; i < Result.Count; i++) { if (Result[i].IsDone) m_LoadedCount++; else Result[i].Completed += m_InternalOnComplete; } CompleteIfDependenciesComplete(); } private void CompleteIfDependenciesComplete() { if (m_LoadedCount == Result.Count) { bool success = true; OperationException ex = null; if (!m_Settings.HasFlag(GroupOperationSettings.AllowFailedDependencies)) { for (int i = 0; i < Result.Count; i++) { if (Result[i].Status != AsyncOperationStatus.Succeeded) { success = false; ex = new OperationException("GroupOperation failed because one of its dependencies failed", Result[i].OperationException); break; } } } Complete(Result, success, ex, m_Settings.HasFlag(GroupOperationSettings.ReleaseDependenciesOnFailure)); } } protected override void Destroy() { ReleaseDependencies(); } protected override float Progress { get { float total = 0f; for (int i = 0; i < Result.Count; i++) { var handle = Result[i]; if (!handle.IsDone) total += handle.PercentComplete; else total++; } return total / Result.Count; } } public void Init(List operations, bool releaseDependenciesOnFailure = true, bool allowFailedDependencies = false) { Result = new List(operations); m_Settings = releaseDependenciesOnFailure ? GroupOperationSettings.ReleaseDependenciesOnFailure : GroupOperationSettings.None; if (allowFailedDependencies) m_Settings |= GroupOperationSettings.AllowFailedDependencies; } public void Init(List operations, GroupOperationSettings settings) { Result = new List(operations); m_Settings = settings; } void OnOperationCompleted(AsyncOperationHandle op) { m_LoadedCount++; CompleteIfDependenciesComplete(); } } }