using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEditor.Build.Pipeline.Interfaces; using UnityEngine; namespace UnityEditor.Build.Pipeline.Utilities { internal static class TaskCachingUtility { public class WorkItem<T> { public T Context; public int Index; public CacheEntry entry; public string StatusText; public WorkItem(T context, string statusText = "") { this.Context = context; this.StatusText = statusText; } } public interface IRunCachedCallbacks<T> { /// <summary> /// Creates a cache entry for the specified work item. /// </summary> /// <param name="item">The work item.</param> /// <returns>Returns the created entry.</returns> CacheEntry CreateCacheEntry(WorkItem<T> item); /// <summary> /// Process the uncached work item. /// </summary> /// <param name="item">The work item.</param> void ProcessUncached(WorkItem<T> item); /// <summary> /// Process the cached work item. /// </summary> /// <param name="item">The work item.</param> /// <param name="info">The cached information for the work item.</param> void ProcessCached(WorkItem<T> item, CachedInfo info); /// <summary> /// Post processes the work item. /// </summary> /// <param name="item">The work item.</param> void PostProcess(WorkItem<T> item); /// <summary> /// Creates cached information for the specified work item. /// </summary> /// <param name="item">The work item.</param> /// <returns>Returns the cached information created.</returns> CachedInfo CreateCachedInfo(WorkItem<T> item); } public static ReturnCode RunCachedOperation<T>(IBuildCache cache, IBuildLogger log, IProgressTracker tracker, List<WorkItem<T>> workItems, IRunCachedCallbacks<T> cbs ) { using (log.ScopedStep(LogLevel.Info, "RunCachedOperation")) { List<CacheEntry> cacheEntries = null; List<WorkItem<T>> nonCachedItems = workItems; var cachedItems = new List<WorkItem<T>>(); for (int i = 0; i < workItems.Count; i++) { workItems[i].Index = i; } IList<CachedInfo> cachedInfo = null; if (cache != null) { using (log.ScopedStep(LogLevel.Info, "Creating Cache Entries")) for (int i = 0; i < workItems.Count; i++) { workItems[i].entry = cbs.CreateCacheEntry(workItems[i]); } cacheEntries = workItems.Select(i => i.entry).ToList(); using (log.ScopedStep(LogLevel.Info, "Load Cached Data")) cache.LoadCachedData(cacheEntries, out cachedInfo); cachedItems = workItems.Where(x => cachedInfo[x.Index] != null).ToList(); nonCachedItems = workItems.Where(x => cachedInfo[x.Index] == null).ToList(); } using (log.ScopedStep(LogLevel.Info, "Process Entries")) foreach (WorkItem<T> item in nonCachedItems) { if (!tracker.UpdateInfoUnchecked(item.StatusText)) return ReturnCode.Canceled; cbs.ProcessUncached(item); } using (log.ScopedStep(LogLevel.Info, "Process Cached Entries")) foreach (WorkItem<T> item in cachedItems) cbs.ProcessCached(item, cachedInfo[item.Index]); foreach (WorkItem<T> item in workItems) cbs.PostProcess(item); if (cache != null) { List<CachedInfo> uncachedInfo; using (log.ScopedStep(LogLevel.Info, "Saving to Cache")) { using (log.ScopedStep(LogLevel.Info, "Creating Cached Infos")) uncachedInfo = nonCachedItems.Select((item) => cbs.CreateCachedInfo(item)).ToList(); cache.SaveCachedData(uncachedInfo); } } log.AddEntrySafe(LogLevel.Info, $"Total Entries: {workItems.Count}, Processed: {nonCachedItems.Count}, Cached: {cachedItems.Count}"); return ReturnCode.Success; } } } }