initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
@ -0,0 +1,46 @@
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Append a hash to each bundle name.
|
||||
/// </summary>
|
||||
public class AppendBundleHash : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBundleBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext]
|
||||
IBundleBuildResults m_Results;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (!m_Parameters.AppendHash)
|
||||
return ReturnCode.SuccessNotRun;
|
||||
|
||||
string[] bundles = m_Results.BundleInfos.Keys.ToArray();
|
||||
foreach (string bundle in bundles)
|
||||
{
|
||||
var details = m_Results.BundleInfos[bundle];
|
||||
var oldFileName = details.FileName;
|
||||
var newFileName = string.Format("{0}_{1}", details.FileName, details.Hash.ToString());
|
||||
details.FileName = newFileName;
|
||||
m_Results.BundleInfos[bundle] = details;
|
||||
|
||||
File.Delete(newFileName);
|
||||
File.Move(oldFileName, newFileName);
|
||||
}
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f4af5ab96cd890342912b92e54ac2c3e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,442 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Build.Pipeline;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
using BuildCompression = UnityEngine.BuildCompression;
|
||||
#else
|
||||
using BuildCompression = UnityEditor.Build.Content.BuildCompression;
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Archives and compresses all asset bundles.
|
||||
/// </summary>
|
||||
public class ArchiveAndCompressBundles : IBuildTask
|
||||
{
|
||||
private const int kVersion = 2;
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return kVersion; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBundleWriteData m_WriteData;
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBundleBuildContent m_Content;
|
||||
#endif
|
||||
|
||||
[InjectContext]
|
||||
IBundleBuildResults m_Results;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IProgressTracker m_Tracker;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildCache m_Cache;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildLogger m_Log;
|
||||
#pragma warning restore 649
|
||||
|
||||
internal static void CopyFileWithTimestampIfDifferent(string srcPath, string destPath, IBuildLogger log)
|
||||
{
|
||||
if (srcPath == destPath)
|
||||
return;
|
||||
|
||||
srcPath = Path.GetFullPath(srcPath);
|
||||
destPath = Path.GetFullPath(destPath);
|
||||
|
||||
#if UNITY_EDITOR_WIN
|
||||
// Max path length per MS Path code.
|
||||
const int MaxPath = 260;
|
||||
|
||||
if (srcPath.Length > MaxPath)
|
||||
throw new PathTooLongException(srcPath);
|
||||
|
||||
if (destPath.Length > MaxPath)
|
||||
throw new PathTooLongException(destPath);
|
||||
#endif
|
||||
|
||||
DateTime time = File.GetLastWriteTime(srcPath);
|
||||
DateTime destTime = File.Exists(destPath) ? File.GetLastWriteTime(destPath) : new DateTime();
|
||||
|
||||
if (destTime == time)
|
||||
return;
|
||||
|
||||
using (log.ScopedStep(LogLevel.Verbose, "Copying From Cache", $"{srcPath} -> {destPath}"))
|
||||
{
|
||||
var directory = Path.GetDirectoryName(destPath);
|
||||
Directory.CreateDirectory(directory);
|
||||
File.Copy(srcPath, destPath, true);
|
||||
}
|
||||
}
|
||||
|
||||
static CacheEntry GetCacheEntry(IBuildCache cache, string bundleName, IEnumerable<ResourceFile> resources, BuildCompression compression, List<SerializedFileMetaData> hashes)
|
||||
{
|
||||
var entry = new CacheEntry();
|
||||
entry.Type = CacheEntry.EntryType.Data;
|
||||
entry.Guid = HashingMethods.Calculate("ArchiveAndCompressBundles", bundleName).ToGUID();
|
||||
List<object> toHash = new List<object> { kVersion, compression };
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
toHash.Add(resource.serializedFile);
|
||||
toHash.Add(resource.fileAlias);
|
||||
}
|
||||
toHash.AddRange(hashes.Select(x => (object)x.RawFileHash));
|
||||
entry.Hash = HashingMethods.Calculate(toHash).ToHash128();
|
||||
entry.Version = kVersion;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static CachedInfo GetCachedInfo(IBuildCache cache, CacheEntry entry, IEnumerable<ResourceFile> resources, BundleDetails details)
|
||||
{
|
||||
var info = new CachedInfo();
|
||||
info.Asset = entry;
|
||||
info.Dependencies = new CacheEntry[0];
|
||||
info.Data = new object[] { details };
|
||||
return info;
|
||||
}
|
||||
|
||||
internal static Hash128 CalculateHashVersion(ArchiveWorkItem item, string[] dependencies)
|
||||
{
|
||||
List<Hash128> hashes = new List<Hash128>();
|
||||
|
||||
hashes.AddRange(item.SeriliazedFileMetaDatas.Select(x => x.ContentHash));
|
||||
|
||||
return HashingMethods.Calculate(hashes, dependencies).ToHash128();
|
||||
}
|
||||
|
||||
internal class ArchiveWorkItem
|
||||
{
|
||||
public int Index;
|
||||
public string BundleName;
|
||||
public string OutputFilePath;
|
||||
public string CachedArtifactPath;
|
||||
public List<ResourceFile> ResourceFiles;
|
||||
public BuildCompression Compression;
|
||||
public BundleDetails ResultDetails;
|
||||
public List<SerializedFileMetaData> SeriliazedFileMetaDatas = new List<SerializedFileMetaData>();
|
||||
}
|
||||
|
||||
internal struct TaskInput
|
||||
{
|
||||
public Dictionary<string, WriteResult> InternalFilenameToWriteResults;
|
||||
public Dictionary<string, SerializedFileMetaData> InternalFilenameToWriteMetaData;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
public Dictionary<string, List<ResourceFile>> BundleNameToAdditionalFiles;
|
||||
#endif
|
||||
public Dictionary<string, string> InternalFilenameToBundleName;
|
||||
public Func<string, BuildCompression> GetCompressionForIdentifier;
|
||||
public Func<string, string> GetOutputFilePathForIdentifier;
|
||||
public IBuildCache BuildCache;
|
||||
public Dictionary<GUID, List<string>> AssetToFilesDependencies;
|
||||
public IProgressTracker ProgressTracker;
|
||||
public string TempOutputFolder;
|
||||
public bool Threaded;
|
||||
public List<string> OutCachedBundles;
|
||||
public IBuildLogger Log;
|
||||
public bool StripUnityVersion;
|
||||
}
|
||||
|
||||
internal struct TaskOutput
|
||||
{
|
||||
public Dictionary<string, BundleDetails> BundleDetails;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
TaskInput input = new TaskInput();
|
||||
input.InternalFilenameToWriteResults = m_Results.WriteResults;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
input.BundleNameToAdditionalFiles = m_Content.AdditionalFiles;
|
||||
#endif
|
||||
input.InternalFilenameToBundleName = m_WriteData.FileToBundle;
|
||||
input.GetCompressionForIdentifier = (x) => m_Parameters.GetCompressionForIdentifier(x);
|
||||
input.GetOutputFilePathForIdentifier = (x) => m_Parameters.GetOutputFilePathForIdentifier(x);
|
||||
input.BuildCache = m_Parameters.UseCache ? m_Cache : null;
|
||||
input.ProgressTracker = m_Tracker;
|
||||
input.TempOutputFolder = m_Parameters.TempOutputFolder;
|
||||
input.AssetToFilesDependencies = m_WriteData.AssetToFiles;
|
||||
input.InternalFilenameToWriteMetaData = m_Results.WriteResultsMetaData;
|
||||
input.Log = m_Log;
|
||||
input.StripUnityVersion = (m_Parameters.GetContentBuildSettings().buildFlags & ContentBuildFlags.StripUnityVersion) != 0;
|
||||
|
||||
input.Threaded = ReflectionExtensions.SupportsMultiThreadedArchiving && ScriptableBuildPipeline.threadedArchiving;
|
||||
|
||||
TaskOutput output;
|
||||
ReturnCode code = Run(input, out output);
|
||||
|
||||
if (code == ReturnCode.Success)
|
||||
{
|
||||
foreach (var item in output.BundleDetails)
|
||||
m_Results.BundleInfos.Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
internal static Dictionary<string, string[]> CalculateBundleDependencies(List<List<string>> assetFileList, Dictionary<string, string> filenameToBundleName)
|
||||
{
|
||||
var bundleDependencies = new Dictionary<string, string[]>();
|
||||
Dictionary<string, HashSet<string>> bundleDependenciesHash = new Dictionary<string, HashSet<string>>();
|
||||
foreach (var files in assetFileList)
|
||||
{
|
||||
if (files.IsNullOrEmpty())
|
||||
continue;
|
||||
|
||||
string bundle = filenameToBundleName[files.First()];
|
||||
HashSet<string> dependencies;
|
||||
bundleDependenciesHash.GetOrAdd(bundle, out dependencies);
|
||||
dependencies.UnionWith(files.Select(x => filenameToBundleName[x]));
|
||||
dependencies.Remove(bundle);
|
||||
|
||||
// Ensure we create mappings for all encountered files
|
||||
foreach (var file in files)
|
||||
bundleDependenciesHash.GetOrAdd(filenameToBundleName[file], out dependencies);
|
||||
}
|
||||
|
||||
// Recursively combine dependencies
|
||||
foreach (var dependencyPair in bundleDependenciesHash)
|
||||
{
|
||||
List<string> dependencies = dependencyPair.Value.ToList();
|
||||
for (int i = 0; i < dependencies.Count; i++)
|
||||
{
|
||||
if (!bundleDependenciesHash.TryGetValue(dependencies[i], out var recursiveDependencies))
|
||||
continue;
|
||||
foreach (var recursiveDependency in recursiveDependencies)
|
||||
{
|
||||
if (dependencyPair.Value.Add(recursiveDependency))
|
||||
dependencies.Add(recursiveDependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dep in bundleDependenciesHash)
|
||||
{
|
||||
string[] ret = dep.Value.ToArray();
|
||||
Array.Sort(ret);
|
||||
bundleDependencies.Add(dep.Key, ret);
|
||||
}
|
||||
return bundleDependencies;
|
||||
}
|
||||
|
||||
static void PostArchiveProcessing(List<ArchiveWorkItem> items, List<List<string>> assetFileList, Dictionary<string, string> filenameToBundleName, IBuildLogger log)
|
||||
{
|
||||
using (log.ScopedStep(LogLevel.Info, "PostArchiveProcessing"))
|
||||
{
|
||||
Dictionary<string, string[]> bundleDependencies = CalculateBundleDependencies(assetFileList, filenameToBundleName);
|
||||
foreach (ArchiveWorkItem item in items)
|
||||
{
|
||||
// apply bundle dependencies
|
||||
item.ResultDetails.Dependencies = bundleDependencies.ContainsKey(item.BundleName) ? bundleDependencies[item.BundleName] : new string[0];
|
||||
item.ResultDetails.Hash = CalculateHashVersion(item, item.ResultDetails.Dependencies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ArchiveWorkItem GetOrCreateWorkItem(TaskInput input, string bundleName, Dictionary<string, ArchiveWorkItem> bundleToWorkItem)
|
||||
{
|
||||
if (!bundleToWorkItem.TryGetValue(bundleName, out ArchiveWorkItem item))
|
||||
{
|
||||
item = new ArchiveWorkItem();
|
||||
item.BundleName = bundleName;
|
||||
item.Compression = input.GetCompressionForIdentifier(bundleName);
|
||||
item.OutputFilePath = input.GetOutputFilePathForIdentifier(bundleName);
|
||||
item.ResourceFiles = new List<ResourceFile>();
|
||||
bundleToWorkItem[bundleName] = item;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
static RawHash HashResourceFiles(List<ResourceFile> files)
|
||||
{
|
||||
return HashingMethods.Calculate(files.Select((x) => HashingMethods.CalculateFile(x.fileName)));
|
||||
}
|
||||
|
||||
static List<ArchiveWorkItem> CreateWorkItems(TaskInput input)
|
||||
{
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "CreateWorkItems"))
|
||||
{
|
||||
Dictionary<string, ArchiveWorkItem> bundleNameToWorkItem = new Dictionary<string, ArchiveWorkItem>();
|
||||
|
||||
foreach (var pair in input.InternalFilenameToWriteResults)
|
||||
{
|
||||
string internalName = pair.Key;
|
||||
string bundleName = input.InternalFilenameToBundleName[internalName];
|
||||
ArchiveWorkItem item = GetOrCreateWorkItem(input, bundleName, bundleNameToWorkItem);
|
||||
|
||||
if (input.InternalFilenameToWriteMetaData.TryGetValue(pair.Key, out SerializedFileMetaData md))
|
||||
item.SeriliazedFileMetaDatas.Add(md);
|
||||
else
|
||||
throw new Exception($"Archive {bundleName} with internal name {internalName} does not have associated SerializedFileMetaData");
|
||||
|
||||
item.ResourceFiles.AddRange(pair.Value.resourceFiles);
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
if (input.BundleNameToAdditionalFiles.TryGetValue(bundleName, out List<ResourceFile> additionalFiles))
|
||||
{
|
||||
RawHash hash = HashResourceFiles(additionalFiles);
|
||||
item.SeriliazedFileMetaDatas.Add(new SerializedFileMetaData() { ContentHash = hash.ToHash128(), RawFileHash = hash.ToHash128() });
|
||||
item.ResourceFiles.AddRange(additionalFiles);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
List<ArchiveWorkItem> allItems = bundleNameToWorkItem.Select((x, index) => { x.Value.Index = index; return x.Value; }).ToList();
|
||||
return allItems;
|
||||
}
|
||||
}
|
||||
|
||||
static internal ReturnCode Run(TaskInput input, out TaskOutput output)
|
||||
{
|
||||
output = new TaskOutput();
|
||||
output.BundleDetails = new Dictionary<string, BundleDetails>();
|
||||
|
||||
List<ArchiveWorkItem> allItems = CreateWorkItems(input);
|
||||
|
||||
IList<CacheEntry> cacheEntries = null;
|
||||
IList<CachedInfo> cachedInfo = null;
|
||||
List<ArchiveWorkItem> cachedItems = new List<ArchiveWorkItem>();
|
||||
List<ArchiveWorkItem> nonCachedItems = allItems;
|
||||
if (input.BuildCache != null)
|
||||
{
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "Creating Cache Entries"))
|
||||
cacheEntries = allItems.Select(x => GetCacheEntry(input.BuildCache, x.BundleName, x.ResourceFiles, x.Compression, x.SeriliazedFileMetaDatas)).ToList();
|
||||
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "Load Cached Data"))
|
||||
input.BuildCache.LoadCachedData(cacheEntries, out cachedInfo);
|
||||
|
||||
cachedItems = allItems.Where(x => cachedInfo[x.Index] != null).ToList();
|
||||
nonCachedItems = allItems.Where(x => cachedInfo[x.Index] == null).ToList();
|
||||
foreach (ArchiveWorkItem i in allItems)
|
||||
i.CachedArtifactPath = string.Format("{0}/{1}", input.BuildCache.GetCachedArtifactsDirectory(cacheEntries[i.Index]), HashingMethods.Calculate(i.BundleName));
|
||||
}
|
||||
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "CopyingCachedFiles"))
|
||||
{
|
||||
foreach (ArchiveWorkItem item in cachedItems)
|
||||
{
|
||||
if (!input.ProgressTracker.UpdateInfoUnchecked(string.Format("{0} (Cached)", item.BundleName)))
|
||||
return ReturnCode.Canceled;
|
||||
|
||||
item.ResultDetails = (BundleDetails)cachedInfo[item.Index].Data[0];
|
||||
item.ResultDetails.FileName = item.OutputFilePath;
|
||||
CopyFileWithTimestampIfDifferent(item.CachedArtifactPath, item.ResultDetails.FileName, input.Log);
|
||||
}
|
||||
}
|
||||
|
||||
// Write all the files that aren't cached
|
||||
if (!ArchiveItems(nonCachedItems, input.TempOutputFolder, input.ProgressTracker, input.Threaded, input.Log, input.StripUnityVersion))
|
||||
return ReturnCode.Canceled;
|
||||
|
||||
PostArchiveProcessing(allItems, input.AssetToFilesDependencies.Values.ToList(), input.InternalFilenameToBundleName, input.Log);
|
||||
|
||||
// Put everything into the cache
|
||||
if (input.BuildCache != null)
|
||||
{
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "Copying To Cache"))
|
||||
{
|
||||
List<CachedInfo> uncachedInfo = nonCachedItems.Select(x => GetCachedInfo(input.BuildCache, cacheEntries[x.Index], x.ResourceFiles, x.ResultDetails)).ToList();
|
||||
input.BuildCache.SaveCachedData(uncachedInfo);
|
||||
}
|
||||
}
|
||||
|
||||
output.BundleDetails = allItems.ToDictionary((x) => x.BundleName, (x) => x.ResultDetails);
|
||||
|
||||
if (input.OutCachedBundles != null)
|
||||
input.OutCachedBundles.AddRange(cachedItems.Select(x => x.BundleName));
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
static private void ArchiveSingleItem(ArchiveWorkItem item, string tempOutputFolder, IBuildLogger log, bool stripUnityVersion)
|
||||
{
|
||||
using (log.ScopedStep(LogLevel.Info, "ArchiveSingleItem", item.BundleName))
|
||||
{
|
||||
item.ResultDetails = new BundleDetails();
|
||||
string writePath = string.Format("{0}/{1}", tempOutputFolder, item.BundleName);
|
||||
if (!string.IsNullOrEmpty(item.CachedArtifactPath))
|
||||
writePath = item.CachedArtifactPath;
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(writePath));
|
||||
item.ResultDetails.FileName = item.OutputFilePath;
|
||||
item.ResultDetails.Crc = ContentBuildInterface.ArchiveAndCompress(item.ResourceFiles.ToArray(), writePath, item.Compression, stripUnityVersion);
|
||||
|
||||
CopyFileWithTimestampIfDifferent(writePath, item.ResultDetails.FileName, log);
|
||||
}
|
||||
}
|
||||
|
||||
static private bool ArchiveItems(List<ArchiveWorkItem> items, string tempOutputFolder, IProgressTracker tracker, bool threaded, IBuildLogger log, bool stripUnityVersion)
|
||||
{
|
||||
using (log.ScopedStep(LogLevel.Info, "ArchiveItems", threaded))
|
||||
{
|
||||
log?.AddEntry(LogLevel.Info, $"Archiving {items.Count} Bundles");
|
||||
if (threaded)
|
||||
return ArchiveItemsThreaded(items, tempOutputFolder, tracker, log, stripUnityVersion);
|
||||
|
||||
foreach (ArchiveWorkItem item in items)
|
||||
{
|
||||
if (tracker != null && !tracker.UpdateInfoUnchecked(item.BundleName))
|
||||
return false;
|
||||
|
||||
ArchiveSingleItem(item, tempOutputFolder, log, stripUnityVersion);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static private bool ArchiveItemsThreaded(List<ArchiveWorkItem> items, string tempOutputFolder, IProgressTracker tracker, IBuildLogger log, bool stripUnityVersion)
|
||||
{
|
||||
CancellationTokenSource srcToken = new CancellationTokenSource();
|
||||
|
||||
SemaphoreSlim semaphore = new SemaphoreSlim(0);
|
||||
List<Task> tasks = new List<Task>(items.Count);
|
||||
foreach (ArchiveWorkItem item in items)
|
||||
{
|
||||
tasks.Add(Task.Run(() =>
|
||||
{
|
||||
try { ArchiveSingleItem(item, tempOutputFolder, log, stripUnityVersion); }
|
||||
finally { semaphore.Release(); }
|
||||
}, srcToken.Token));
|
||||
}
|
||||
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
semaphore.Wait(srcToken.Token);
|
||||
if (tracker != null && !tracker.UpdateInfoUnchecked($"Archive {i + 1}/{items.Count}"))
|
||||
{
|
||||
srcToken.Cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Task.WaitAny(Task.WhenAll(tasks));
|
||||
int count = 0;
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
if (task.Exception == null)
|
||||
continue;
|
||||
Debug.LogException(task.Exception);
|
||||
count++;
|
||||
}
|
||||
if (count > 0)
|
||||
throw new BuildFailedException($"ArchiveAndCompressBundles encountered {count} exception(s). See console for logged exceptions.");
|
||||
|
||||
return !srcToken.Token.IsCancellationRequested;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b7bdc0bcfab4e714b88a12d6b22bac9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,50 @@
|
|||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Player;
|
||||
using System.IO;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Compiles all player scripts.
|
||||
/// </summary>
|
||||
public class BuildPlayerScripts : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext]
|
||||
IBuildResults m_Results;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (m_Parameters.ScriptInfo != null)
|
||||
{
|
||||
BuildCacheUtility.SetTypeDB(m_Parameters.ScriptInfo);
|
||||
return ReturnCode.SuccessNotRun;
|
||||
}
|
||||
|
||||
// We need to ensure the directory is empty so prior results or other artifacts in this directory do not influence the build result
|
||||
if (Directory.Exists(m_Parameters.ScriptOutputFolder))
|
||||
{
|
||||
Directory.Delete(m_Parameters.ScriptOutputFolder, true);
|
||||
Directory.CreateDirectory(m_Parameters.ScriptOutputFolder);
|
||||
}
|
||||
|
||||
m_Results.ScriptResults = PlayerBuildInterface.CompilePlayerScripts(m_Parameters.GetScriptCompilationSettings(), m_Parameters.ScriptOutputFolder);
|
||||
m_Parameters.ScriptInfo = m_Results.ScriptResults.typeDB;
|
||||
BuildCacheUtility.SetTypeDB(m_Parameters.ScriptInfo);
|
||||
|
||||
if (m_Results.ScriptResults.assemblies.IsNullOrEmpty() && m_Results.ScriptResults.typeDB == null)
|
||||
return ReturnCode.Error;
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c42a8e1e1d1b874e95761dab5bdfbc8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,646 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Player;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
[Serializable]
|
||||
internal class ObjectDependencyInfo
|
||||
{
|
||||
public ObjectIdentifier Object;
|
||||
public List<ObjectIdentifier> Dependencies = new List<ObjectIdentifier>();
|
||||
}
|
||||
|
||||
#if !UNITY_2020_2_OR_NEWER
|
||||
internal class CalculateAssetDependencyHooks
|
||||
{
|
||||
public virtual UnityEngine.Object[] LoadAllAssetRepresentationsAtPath(string assetPath)
|
||||
{
|
||||
return AssetDatabase.LoadAllAssetRepresentationsAtPath(assetPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the dependency data for all assets.
|
||||
/// </summary>
|
||||
public class CalculateAssetDependencyData : IBuildTask
|
||||
{
|
||||
internal const int kVersion = 6;
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return kVersion; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBundleBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildContent m_Content;
|
||||
|
||||
[InjectContext]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext]
|
||||
IObjectDependencyData m_ObjectDependencyData;
|
||||
|
||||
[InjectContext(ContextUsage.InOut, true)]
|
||||
IBuildResults m_Results;
|
||||
|
||||
[InjectContext(ContextUsage.InOut, true)]
|
||||
IBuildSpriteData m_SpriteData;
|
||||
|
||||
[InjectContext(ContextUsage.InOut, true)]
|
||||
IBuildExtendedAssetData m_ExtendedAssetData;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IProgressTracker m_Tracker;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildCache m_Cache;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildLogger m_Log;
|
||||
#pragma warning restore 649
|
||||
|
||||
internal struct TaskInput
|
||||
{
|
||||
public IBuildCache BuildCache;
|
||||
public BuildTarget Target;
|
||||
public TypeDB TypeDB;
|
||||
public List<GUID> Assets;
|
||||
public IProgressTracker ProgressTracker;
|
||||
public BuildUsageTagGlobal GlobalUsage;
|
||||
public BuildUsageCache DependencyUsageCache;
|
||||
#if !UNITY_2020_2_OR_NEWER
|
||||
public CalculateAssetDependencyHooks EngineHooks;
|
||||
#endif
|
||||
public bool NonRecursiveDependencies;
|
||||
public IBuildLogger Logger;
|
||||
}
|
||||
|
||||
internal struct AssetOutput
|
||||
{
|
||||
public GUID asset;
|
||||
public Hash128 Hash;
|
||||
public AssetLoadInfo assetInfo;
|
||||
public List<ObjectDependencyInfo> objectDependencyInfo;
|
||||
public BuildUsageTagSet usageTags;
|
||||
public SpriteImporterData spriteData;
|
||||
public ExtendedAssetData extendedData;
|
||||
public List<ObjectTypes> objectTypes;
|
||||
}
|
||||
|
||||
internal struct TaskOutput
|
||||
{
|
||||
public AssetOutput[] AssetResults;
|
||||
public int CachedAssetCount;
|
||||
}
|
||||
|
||||
static CacheEntry GetCacheEntry(GUID asset, TaskInput input)
|
||||
{
|
||||
if (input.BuildCache == null)
|
||||
return default;
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
CacheEntry entry = input.BuildCache.GetCacheEntry(asset, input.NonRecursiveDependencies ? -kVersion : kVersion);
|
||||
#else
|
||||
CacheEntry entry = input.BuildCache.GetCacheEntry(asset, Version);
|
||||
#endif
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static CachedInfo GetCachedInfo(TaskInput input, GUID asset, AssetLoadInfo assetInfo, List<ObjectDependencyInfo> objectDependencies, BuildUsageTagSet usageTags, SpriteImporterData importerData, ExtendedAssetData assetData)
|
||||
{
|
||||
var info = new CachedInfo();
|
||||
info.Asset = GetCacheEntry(asset, input);
|
||||
|
||||
var uniqueTypes = new HashSet<System.Type>();
|
||||
var objectTypes = new List<ObjectTypes>();
|
||||
var dependencies = new HashSet<CacheEntry>();
|
||||
ExtensionMethods.ExtractCommonCacheData(input.BuildCache, assetInfo.includedObjects, assetInfo.referencedObjects, uniqueTypes, objectTypes, dependencies);
|
||||
info.Dependencies = dependencies.ToArray();
|
||||
|
||||
info.Data = new object[] { assetInfo, usageTags, importerData, assetData, objectTypes, objectDependencies };
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
TaskInput input = new TaskInput();
|
||||
input.Target = m_Parameters.Target;
|
||||
input.TypeDB = m_Parameters.ScriptInfo;
|
||||
input.BuildCache = m_Parameters.UseCache ? m_Cache : null;
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
input.NonRecursiveDependencies = m_Parameters.NonRecursiveDependencies;
|
||||
#else
|
||||
input.NonRecursiveDependencies = false;
|
||||
#endif
|
||||
input.Assets = m_Content.Assets;
|
||||
input.ProgressTracker = m_Tracker;
|
||||
input.DependencyUsageCache = m_DependencyData.DependencyUsageCache;
|
||||
input.GlobalUsage = m_DependencyData.GlobalUsage;
|
||||
input.Logger = m_Log;
|
||||
foreach (SceneDependencyInfo sceneInfo in m_DependencyData.SceneInfo.Values)
|
||||
input.GlobalUsage |= sceneInfo.globalUsage;
|
||||
|
||||
ReturnCode code = RunInternal(input, out TaskOutput output);
|
||||
if (code == ReturnCode.Success)
|
||||
{
|
||||
foreach (AssetOutput o in output.AssetResults)
|
||||
{
|
||||
m_DependencyData.AssetInfo.Add(o.asset, o.assetInfo);
|
||||
foreach (var objectDependencyInfo in o.objectDependencyInfo)
|
||||
m_ObjectDependencyData.ObjectDependencyMap[objectDependencyInfo.Object] = objectDependencyInfo.Dependencies;
|
||||
}
|
||||
|
||||
foreach (AssetOutput assetOutput in output.AssetResults)
|
||||
{
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
if (!input.NonRecursiveDependencies)
|
||||
ExpandReferences(assetOutput, m_ObjectDependencyData.ObjectDependencyMap);
|
||||
#endif
|
||||
|
||||
m_DependencyData.AssetUsage.Add(assetOutput.asset, assetOutput.usageTags);
|
||||
|
||||
Dictionary<ObjectIdentifier, System.Type[]> objectTypes = new Dictionary<ObjectIdentifier, Type[]>();
|
||||
foreach (var objectType in assetOutput.objectTypes)
|
||||
objectTypes.Add(objectType.ObjectID, objectType.Types);
|
||||
|
||||
if (m_Results != null)
|
||||
{
|
||||
AssetResultData resultData = new AssetResultData
|
||||
{
|
||||
Guid = assetOutput.asset,
|
||||
Hash = assetOutput.Hash,
|
||||
IncludedObjects = assetOutput.assetInfo.includedObjects,
|
||||
ReferencedObjects = assetOutput.assetInfo.referencedObjects,
|
||||
ObjectTypes = objectTypes
|
||||
};
|
||||
m_Results.AssetResults.Add(assetOutput.asset, resultData);
|
||||
}
|
||||
|
||||
if (assetOutput.spriteData != null)
|
||||
{
|
||||
if (m_SpriteData == null)
|
||||
m_SpriteData = new BuildSpriteData();
|
||||
m_SpriteData.ImporterData.Add(assetOutput.asset, assetOutput.spriteData);
|
||||
}
|
||||
|
||||
if (!m_Parameters.DisableVisibleSubAssetRepresentations && assetOutput.extendedData != null)
|
||||
{
|
||||
if (m_ExtendedAssetData == null)
|
||||
m_ExtendedAssetData = new BuildExtendedAssetData();
|
||||
m_ExtendedAssetData.ExtendedData.Add(assetOutput.asset, assetOutput.extendedData);
|
||||
}
|
||||
|
||||
if (assetOutput.objectTypes != null)
|
||||
BuildCacheUtility.SetTypeForObjects(assetOutput.objectTypes);
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
// expand dependencies to explicit assets, results in the same output as recursive dependency calculation
|
||||
private void ExpandReferences(AssetOutput assetOutput, Dictionary<ObjectIdentifier, List<ObjectIdentifier>> objectDependencyMap)
|
||||
{
|
||||
HashSet<ObjectIdentifier> processed = new HashSet<ObjectIdentifier>();
|
||||
HashSet<ObjectIdentifier> referencedObjects = new HashSet<ObjectIdentifier>(assetOutput.assetInfo.referencedObjects);
|
||||
Stack<ObjectIdentifier> processStack = new Stack<ObjectIdentifier>(1024);
|
||||
if (assetOutput.objectDependencyInfo != null && assetOutput.objectDependencyInfo.Count > 0)
|
||||
{
|
||||
foreach (ObjectDependencyInfo info in assetOutput.objectDependencyInfo)
|
||||
{
|
||||
foreach (ObjectIdentifier dependency in info.Dependencies)
|
||||
{
|
||||
if (processed.Contains(dependency) || dependency.guid == assetOutput.asset)
|
||||
continue;
|
||||
|
||||
processStack.Push(dependency);
|
||||
referencedObjects.Add(dependency);
|
||||
}
|
||||
|
||||
// internal object to asset o
|
||||
processed.Add(info.Object);
|
||||
}
|
||||
|
||||
List<ObjectIdentifier> dependencies;
|
||||
while (processStack.Count > 0)
|
||||
{
|
||||
var dep = processStack.Pop();
|
||||
processed.Add(dep);
|
||||
if (!objectDependencyMap.TryGetValue(dep, out dependencies) || dependencies.Count == 0)
|
||||
continue;
|
||||
|
||||
foreach (ObjectIdentifier dependency in dependencies)
|
||||
{
|
||||
if (processed.Contains(dependency) || dependency.guid == assetOutput.asset)
|
||||
continue;
|
||||
|
||||
processStack.Push(dependency);
|
||||
referencedObjects.Add(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
// go through all object dependencies that are not to self, add to stack
|
||||
// loop through external dependencies
|
||||
var refs = new List<ObjectIdentifier>(referencedObjects.ToArray());
|
||||
|
||||
// to mimic recursive dependency calculation
|
||||
assetOutput.assetInfo.referencedObjects = refs;
|
||||
}
|
||||
}
|
||||
|
||||
#if !UNITY_2020_2_OR_NEWER
|
||||
static internal void GatherAssetRepresentations(string assetPath, System.Func<string, UnityEngine.Object[]> loadAllAssetRepresentations, ObjectIdentifier[] includedObjects, out ExtendedAssetData extendedData)
|
||||
{
|
||||
extendedData = null;
|
||||
var representations = loadAllAssetRepresentations(assetPath);
|
||||
if (representations.IsNullOrEmpty())
|
||||
return;
|
||||
|
||||
var resultData = new ExtendedAssetData();
|
||||
for (int j = 0; j < representations.Length; j++)
|
||||
{
|
||||
if (representations[j] == null)
|
||||
{
|
||||
BuildLogger.LogWarning($"SubAsset {j} inside {assetPath} is null. It will not be included in the build.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AssetDatabase.IsMainAsset(representations[j]))
|
||||
continue;
|
||||
|
||||
string guid;
|
||||
long localId;
|
||||
if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(representations[j], out guid, out localId))
|
||||
continue;
|
||||
|
||||
resultData.Representations.AddRange(includedObjects.Where(x => x.localIdentifierInFile == localId));
|
||||
}
|
||||
|
||||
if (resultData.Representations.Count > 0)
|
||||
extendedData = resultData;
|
||||
}
|
||||
|
||||
#else
|
||||
static internal void GatherAssetRepresentations(GUID asset, BuildTarget target, ObjectIdentifier[] includedObjects, out ExtendedAssetData extendedData)
|
||||
{
|
||||
extendedData = null;
|
||||
var includeSet = new HashSet<ObjectIdentifier>(includedObjects);
|
||||
// GetPlayerAssetRepresentations can return editor only objects, filter out those to only include what is in includedObjects
|
||||
ObjectIdentifier[] representations = ContentBuildInterface.GetPlayerAssetRepresentations(asset, target);
|
||||
var filteredRepresentations = representations.Where(includeSet.Contains);
|
||||
// Main Asset always returns at index 0, we only want representations, so check for greater than 1 length
|
||||
if (representations.IsNullOrEmpty() || filteredRepresentations.Count() < 2)
|
||||
return;
|
||||
|
||||
extendedData = new ExtendedAssetData();
|
||||
extendedData.Representations.AddRange(filteredRepresentations.Skip(1));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static internal ReturnCode RunInternal(TaskInput input, out TaskOutput output)
|
||||
{
|
||||
#if !UNITY_2020_2_OR_NEWER
|
||||
input.EngineHooks = input.EngineHooks != null ? input.EngineHooks : new CalculateAssetDependencyHooks();
|
||||
#endif
|
||||
output = new TaskOutput();
|
||||
output.AssetResults = new AssetOutput[input.Assets.Count];
|
||||
|
||||
IList<CachedInfo> cachedInfo = null;
|
||||
using (input.Logger.ScopedStep(LogLevel.Info, "Gathering Cache Entries to Load"))
|
||||
{
|
||||
if (input.BuildCache != null)
|
||||
{
|
||||
IList<CacheEntry> entries = input.Assets.Select(x => GetCacheEntry(x, input)).ToList();
|
||||
input.BuildCache.LoadCachedData(entries, out cachedInfo);
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<GUID> explicitAssets = new HashSet<GUID>(input.Assets);
|
||||
Dictionary<GUID, AssetOutput> implicitAssetsOutput = new Dictionary<GUID, AssetOutput>();
|
||||
var textureImporters = new Dictionary<GUID, TextureImporter>();
|
||||
|
||||
for (int i = 0; i < input.Assets.Count; i++)
|
||||
{
|
||||
using (input.Logger.ScopedStep(LogLevel.Info, "Calculate Asset Dependencies"))
|
||||
{
|
||||
AssetOutput assetResult = new AssetOutput();
|
||||
assetResult.asset = input.Assets[i];
|
||||
|
||||
if (cachedInfo != null && cachedInfo[i] != null)
|
||||
{
|
||||
var objectTypes = cachedInfo[i].Data[4] as List<ObjectTypes>;
|
||||
var assetInfos = cachedInfo[i].Data[0] as AssetLoadInfo;
|
||||
var objectDependencyInfo = cachedInfo[i].Data[5] as List<ObjectDependencyInfo>;
|
||||
|
||||
bool useCachedData = true;
|
||||
foreach (var objectType in objectTypes)
|
||||
{
|
||||
//Sprite association to SpriteAtlas might have changed since last time data was cached, this might
|
||||
//imply that we have stale data in our cache, if so ensure we regenerate the data.
|
||||
if (objectType.Types[0] == typeof(UnityEngine.Sprite))
|
||||
{
|
||||
var referencedObjectOld = assetInfos.referencedObjects.ToArray();
|
||||
ObjectIdentifier[] referencedObjectsNew = null;
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
referencedObjectsNew = GetPlayerDependenciesForAsset(input.Assets[i], assetInfos.includedObjects.ToArray(), input, assetResult, explicitAssets, implicitAssetsOutput, textureImporters);
|
||||
#else
|
||||
referencedObjectsNew = ContentBuildInterface.GetPlayerDependenciesForObjects(assetInfos.includedObjects.ToArray(), input.Target, input.TypeDB);
|
||||
#endif
|
||||
|
||||
if (Enumerable.SequenceEqual(referencedObjectOld, referencedObjectsNew) == false)
|
||||
{
|
||||
useCachedData = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (useCachedData)
|
||||
{
|
||||
assetResult.assetInfo = assetInfos;
|
||||
assetResult.objectDependencyInfo = objectDependencyInfo;
|
||||
assetResult.usageTags = cachedInfo[i].Data[1] as BuildUsageTagSet;
|
||||
assetResult.spriteData = cachedInfo[i].Data[2] as SpriteImporterData;
|
||||
assetResult.extendedData = cachedInfo[i].Data[3] as ExtendedAssetData;
|
||||
assetResult.objectTypes = objectTypes;
|
||||
output.AssetResults[i] = assetResult;
|
||||
output.CachedAssetCount++;
|
||||
input.Logger.AddEntrySafe(LogLevel.Info, $"{assetResult.asset} (cached)");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
GUID asset = input.Assets[i];
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(asset.ToString());
|
||||
|
||||
if (!input.ProgressTracker.UpdateInfoUnchecked(assetPath))
|
||||
return ReturnCode.Canceled;
|
||||
|
||||
input.Logger.AddEntrySafe(LogLevel.Info, $"{assetResult.asset}");
|
||||
|
||||
assetResult.assetInfo = new AssetLoadInfo();
|
||||
assetResult.objectDependencyInfo = new List<ObjectDependencyInfo>();
|
||||
assetResult.usageTags = new BuildUsageTagSet();
|
||||
|
||||
assetResult.assetInfo.asset = asset;
|
||||
var includedObjects = ContentBuildInterface.GetPlayerObjectIdentifiersInAsset(asset, input.Target);
|
||||
assetResult.assetInfo.includedObjects = new List<ObjectIdentifier>(includedObjects);
|
||||
ObjectIdentifier[] referencedObjects;
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
referencedObjects = GetPlayerDependenciesForAsset(asset, includedObjects, input, assetResult, explicitAssets, implicitAssetsOutput, textureImporters);
|
||||
#else
|
||||
referencedObjects = ContentBuildInterface.GetPlayerDependenciesForObjects(includedObjects, input.Target, input.TypeDB);
|
||||
#endif
|
||||
|
||||
assetResult.assetInfo.referencedObjects = new List<ObjectIdentifier>(referencedObjects);
|
||||
var allObjects = new List<ObjectIdentifier>(includedObjects);
|
||||
allObjects.AddRange(referencedObjects);
|
||||
ContentBuildInterface.CalculateBuildUsageTags(allObjects.ToArray(), includedObjects, input.GlobalUsage, assetResult.usageTags, input.DependencyUsageCache);
|
||||
|
||||
TextureImporter importer = null;
|
||||
bool isSprite = false;
|
||||
if (textureImporters.ContainsKey(asset))
|
||||
{
|
||||
importer = textureImporters[asset];
|
||||
isSprite = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
|
||||
isSprite = importer != null && importer.textureType == TextureImporterType.Sprite;
|
||||
if (isSprite)
|
||||
textureImporters.Add(asset, importer);
|
||||
}
|
||||
|
||||
if (isSprite)
|
||||
{
|
||||
assetResult.spriteData = new SpriteImporterData();
|
||||
assetResult.spriteData.PackedSprite = false;
|
||||
assetResult.spriteData.SourceTexture = includedObjects.FirstOrDefault();
|
||||
|
||||
if (EditorSettings.spritePackerMode != SpritePackerMode.Disabled)
|
||||
assetResult.spriteData.PackedSprite = referencedObjects.Length > 0;
|
||||
#if !UNITY_2020_1_OR_NEWER
|
||||
if (EditorSettings.spritePackerMode == SpritePackerMode.AlwaysOn || EditorSettings.spritePackerMode == SpritePackerMode.BuildTimeOnly)
|
||||
assetResult.spriteData.PackedSprite = !string.IsNullOrEmpty(importer.spritePackingTag);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !UNITY_2020_2_OR_NEWER
|
||||
GatherAssetRepresentations(assetPath, input.EngineHooks.LoadAllAssetRepresentationsAtPath, includedObjects, out assetResult.extendedData);
|
||||
#else
|
||||
GatherAssetRepresentations(asset, input.Target, includedObjects, out assetResult.extendedData);
|
||||
#endif
|
||||
output.AssetResults[i] = assetResult;
|
||||
}
|
||||
}
|
||||
|
||||
using (input.Logger.ScopedStep(LogLevel.Info, "Gathering Cache Entries to Save"))
|
||||
{
|
||||
if (input.BuildCache != null)
|
||||
{
|
||||
List<CachedInfo> toCache = new List<CachedInfo>();
|
||||
for (int i = 0; i < input.Assets.Count; i++)
|
||||
{
|
||||
AssetOutput r = output.AssetResults[i];
|
||||
CachedInfo info = cachedInfo[i];
|
||||
if (info == null)
|
||||
{
|
||||
info = GetCachedInfo(input, input.Assets[i], r.assetInfo, r.objectDependencyInfo, r.usageTags, r.spriteData, r.extendedData);
|
||||
toCache.Add(info);
|
||||
}
|
||||
|
||||
r.Hash = info.Asset.Hash;
|
||||
if (r.objectTypes == null && info.Data.Length > 4)
|
||||
{
|
||||
List<ObjectTypes> types = info.Data[4] as List<ObjectTypes>;
|
||||
r.objectTypes = types;
|
||||
}
|
||||
output.AssetResults[i] = r;
|
||||
}
|
||||
input.BuildCache.SaveCachedData(toCache);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < input.Assets.Count; i++)
|
||||
{
|
||||
AssetOutput r = output.AssetResults[i];
|
||||
if (r.objectTypes != null)
|
||||
continue;
|
||||
|
||||
var info = BuildCacheUtility.GetCacheEntry(input.Assets[i], input.NonRecursiveDependencies ? -kVersion : kVersion);
|
||||
r.Hash = info.Hash;
|
||||
|
||||
r.objectTypes = new List<ObjectTypes>(r.assetInfo.includedObjects.Count);
|
||||
foreach (var objectId in r.assetInfo.includedObjects)
|
||||
{
|
||||
var types = BuildCacheUtility.GetSortedUniqueTypesForObject(objectId);
|
||||
r.objectTypes.Add(new ObjectTypes(objectId, types));
|
||||
}
|
||||
output.AssetResults[i] = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
private static ObjectIdentifier[] GetPlayerDependenciesForAsset(GUID inputAssetGuid, ObjectIdentifier[] includedObjects, TaskInput input, AssetOutput assetResult, HashSet<GUID> explicitAssets,
|
||||
in Dictionary<GUID, AssetOutput> implicitAssetsOutput, Dictionary<GUID, TextureImporter> textureImporters)
|
||||
{
|
||||
HashSet<ObjectIdentifier> otherReferencedAssetObjectsHashSet = new HashSet<ObjectIdentifier>();
|
||||
ObjectIdentifier[] singleObjectIdArray = new ObjectIdentifier[1];
|
||||
foreach (ObjectIdentifier subObject in includedObjects)
|
||||
{
|
||||
singleObjectIdArray[0] = subObject;
|
||||
ObjectIdentifier[] objs = ContentBuildInterface.GetPlayerDependenciesForObjects(singleObjectIdArray, input.Target, input.TypeDB, DependencyType.ValidReferences);
|
||||
foreach (ObjectIdentifier objRef in objs)
|
||||
{
|
||||
// inputAssetGuid is an explicit build asset, so it is all objects in the asset and do not need to include them
|
||||
if (objRef.guid == inputAssetGuid)
|
||||
continue;
|
||||
otherReferencedAssetObjectsHashSet.Add(objRef);
|
||||
}
|
||||
|
||||
if (objs.Length > 0)
|
||||
{
|
||||
if (assetResult.objectDependencyInfo == null)
|
||||
assetResult.objectDependencyInfo = new List<ObjectDependencyInfo>();
|
||||
assetResult.objectDependencyInfo.Add(new ObjectDependencyInfo()
|
||||
{
|
||||
Object = subObject,
|
||||
Dependencies = new List<ObjectIdentifier>(objs)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var collectedImmediateReferences = new HashSet<ObjectIdentifier>();
|
||||
var encounteredExplicitAssetDependencies = new HashSet<ObjectIdentifier>();
|
||||
var mainRepresentationNeeded = new HashSet<GUID>();
|
||||
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(inputAssetGuid.ToString());
|
||||
bool isSpriteAtlas = AssetDatabase.GetMainAssetTypeAtPath(assetPath) == typeof(UnityEngine.U2D.SpriteAtlas);
|
||||
Stack<ObjectIdentifier> objectLookingAt = new Stack<ObjectIdentifier>(otherReferencedAssetObjectsHashSet);
|
||||
while (objectLookingAt.Count > 0)
|
||||
{
|
||||
var obj = objectLookingAt.Pop();
|
||||
|
||||
// Track which roots we encounter to do dependency pruning
|
||||
if (obj.guid != inputAssetGuid && explicitAssets.Contains(obj.guid))
|
||||
{
|
||||
encounteredExplicitAssetDependencies.Add(obj); // might just be able to add to collected
|
||||
|
||||
// Don't include source textures for sprites included in an atlas
|
||||
if (isSpriteAtlas)
|
||||
{
|
||||
string explicitAssetPath = AssetDatabase.GUIDToAssetPath(obj.guid.ToString());
|
||||
TextureImporter importer = null;
|
||||
bool isSprite = false;
|
||||
if (textureImporters.ContainsKey(obj.guid))
|
||||
{
|
||||
importer = textureImporters[obj.guid];
|
||||
isSprite = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
importer = AssetImporter.GetAtPath(explicitAssetPath) as TextureImporter;
|
||||
isSprite = importer != null && importer.textureType == TextureImporterType.Sprite;
|
||||
if (isSprite)
|
||||
textureImporters.Add(obj.guid, importer);
|
||||
}
|
||||
if (isSprite)
|
||||
continue;
|
||||
}
|
||||
|
||||
mainRepresentationNeeded.Add(obj.guid);
|
||||
}
|
||||
// looking for implicit assets we have not visited yet
|
||||
else if (!explicitAssets.Contains(obj.guid) && !collectedImmediateReferences.Contains(obj))
|
||||
{
|
||||
collectedImmediateReferences.Add(obj);
|
||||
|
||||
ObjectIdentifier[] referencedObjects = null;
|
||||
if (!implicitAssetsOutput.TryGetValue(obj.guid, out var implicitOutput))
|
||||
{
|
||||
implicitOutput = new AssetOutput()
|
||||
{
|
||||
asset = obj.guid,
|
||||
objectDependencyInfo = new List<ObjectDependencyInfo>()
|
||||
};
|
||||
implicitAssetsOutput[obj.guid] = implicitOutput;
|
||||
}
|
||||
else // implicit player dependencies for asset is cached, check for specific object
|
||||
{
|
||||
List<ObjectIdentifier> foundObjectDependencies = null;
|
||||
foreach (ObjectDependencyInfo dependencyInfo in implicitOutput.objectDependencyInfo)
|
||||
{
|
||||
if (dependencyInfo.Object == obj)
|
||||
{
|
||||
foundObjectDependencies = dependencyInfo.Dependencies;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundObjectDependencies != null)
|
||||
{
|
||||
foreach (ObjectIdentifier o in foundObjectDependencies)
|
||||
objectLookingAt.Push(o);
|
||||
|
||||
if (foundObjectDependencies.Count > 0)
|
||||
{
|
||||
assetResult.objectDependencyInfo.Add(new ObjectDependencyInfo()
|
||||
{
|
||||
Object = obj,
|
||||
Dependencies = foundObjectDependencies
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// have not got the object references for this object yet
|
||||
singleObjectIdArray[0] = obj;
|
||||
referencedObjects = ContentBuildInterface.GetPlayerDependenciesForObjects(singleObjectIdArray, input.Target, input.TypeDB, DependencyType.ValidReferences);
|
||||
List<ObjectIdentifier> referencedObjectList = new List<ObjectIdentifier>(referencedObjects);
|
||||
implicitOutput.objectDependencyInfo.Add(new ObjectDependencyInfo()
|
||||
{
|
||||
Object = obj,
|
||||
Dependencies = referencedObjectList
|
||||
});
|
||||
if (referencedObjectList.Count > 0)
|
||||
{
|
||||
assetResult.objectDependencyInfo.Add(new ObjectDependencyInfo()
|
||||
{
|
||||
Object = obj,
|
||||
Dependencies = referencedObjectList
|
||||
});
|
||||
}
|
||||
|
||||
foreach (ObjectIdentifier o in referencedObjects)
|
||||
objectLookingAt.Push(o);
|
||||
}
|
||||
}
|
||||
|
||||
// We need to ensure that we have a reference to a visible representation so our runtime dependency appending process
|
||||
// can find something that can be appended, otherwise the necessary data will fail to load correctly in all cases. (EX: prefab A has reference to component on prefab B)
|
||||
foreach (var dependency in mainRepresentationNeeded)
|
||||
{
|
||||
// For each dependency, add just the main representation as a reference
|
||||
var representations = ContentBuildInterface.GetPlayerAssetRepresentations(dependency, input.Target);
|
||||
collectedImmediateReferences.Add(representations[0]);
|
||||
}
|
||||
collectedImmediateReferences.UnionWith(encounteredExplicitAssetDependencies);
|
||||
return collectedImmediateReferences.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 40e93d78541d2664e8424875bca4e041
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,207 @@
|
|||
#if UNITY_2019_3_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Build Task that calculates teh included objects and references objects for custom assets not tracked by the AssetDatabase.
|
||||
/// <seealso cref="IBuildTask"/>
|
||||
/// </summary>
|
||||
public class CalculateCustomDependencyData : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 2; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.InOut)]
|
||||
IBundleBuildContent m_Content;
|
||||
|
||||
[InjectContext(ContextUsage.InOut)]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext(ContextUsage.Out, true)]
|
||||
ICustomAssets m_CustomAssets;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IProgressTracker m_Tracker;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildCache m_Cache;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildLogger m_Log;
|
||||
#pragma warning restore 649
|
||||
|
||||
BuildUsageTagGlobal m_GlobalUsage;
|
||||
BuildUsageTagGlobal m_CustomUsage;
|
||||
|
||||
Dictionary<string, AssetLoadInfo> m_AssetInfo = new Dictionary<string, AssetLoadInfo>();
|
||||
Dictionary<string, BuildUsageTagSet> m_BuildUsage = new Dictionary<string, BuildUsageTagSet>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
m_CustomAssets = new CustomAssets();
|
||||
m_GlobalUsage = m_DependencyData.GlobalUsage;
|
||||
foreach (SceneDependencyInfo sceneInfo in m_DependencyData.SceneInfo.Values)
|
||||
m_GlobalUsage |= sceneInfo.globalUsage;
|
||||
|
||||
foreach (CustomContent info in m_Content.CustomAssets)
|
||||
{
|
||||
if (!m_Tracker.UpdateInfoUnchecked(info.Asset.ToString()))
|
||||
return ReturnCode.Canceled;
|
||||
|
||||
using (m_Log.ScopedStep(LogLevel.Verbose, "CustomAssetDependency", info.Asset.ToString()))
|
||||
info.Processor(info.Asset, this);
|
||||
}
|
||||
|
||||
// Add all the additional global usage for custom assets back into the dependency data result
|
||||
// for use in the write serialized file build task
|
||||
m_DependencyData.GlobalUsage |= m_CustomUsage;
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
CacheEntry GetCacheEntry(string path, BuildUsageTagGlobal additionalGlobalUsage)
|
||||
{
|
||||
var entry = new CacheEntry();
|
||||
entry.Type = CacheEntry.EntryType.Data;
|
||||
entry.Guid = HashingMethods.Calculate("CalculateCustomDependencyData", path).ToGUID();
|
||||
entry.Hash = HashingMethods.Calculate(HashingMethods.CalculateFile(path), additionalGlobalUsage).ToHash128();
|
||||
entry.Version = Version;
|
||||
return entry;
|
||||
}
|
||||
|
||||
CachedInfo GetCachedInfo(CacheEntry entry, AssetLoadInfo assetInfo, BuildUsageTagSet usageTags)
|
||||
{
|
||||
var info = new CachedInfo();
|
||||
info.Asset = entry;
|
||||
|
||||
var uniqueTypes = new HashSet<Type>();
|
||||
var objectTypes = new List<ObjectTypes>();
|
||||
var dependencies = new HashSet<CacheEntry>();
|
||||
ExtensionMethods.ExtractCommonCacheData(m_Cache, assetInfo.includedObjects, assetInfo.referencedObjects, uniqueTypes, objectTypes, dependencies);
|
||||
info.Dependencies = dependencies.ToArray();
|
||||
|
||||
info.Data = new object[] { assetInfo, usageTags, objectTypes };
|
||||
return info;
|
||||
}
|
||||
|
||||
bool LoadCachedData(string path, out AssetLoadInfo assetInfo, out BuildUsageTagSet buildUsage, BuildUsageTagGlobal globalUsage)
|
||||
{
|
||||
assetInfo = default;
|
||||
buildUsage = default;
|
||||
|
||||
if (!m_Parameters.UseCache || m_Cache == null)
|
||||
return false;
|
||||
|
||||
CacheEntry entry = GetCacheEntry(path, globalUsage);
|
||||
m_Cache.LoadCachedData(new List<CacheEntry> { entry }, out IList<CachedInfo> cachedInfos);
|
||||
var cachedInfo = cachedInfos[0];
|
||||
if (cachedInfo != null)
|
||||
{
|
||||
assetInfo = (AssetLoadInfo)cachedInfo.Data[0];
|
||||
buildUsage = (BuildUsageTagSet)cachedInfo.Data[1];
|
||||
var objectTypes = (List<ObjectTypes>)cachedInfo.Data[2];
|
||||
BuildCacheUtility.SetTypeForObjects(objectTypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
GatherAssetData(path, out assetInfo, out buildUsage, globalUsage);
|
||||
cachedInfo = GetCachedInfo(entry, assetInfo, buildUsage);
|
||||
m_Cache.SaveCachedData(new List<CachedInfo> { cachedInfo });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GatherAssetData(string path, out AssetLoadInfo assetInfo, out BuildUsageTagSet buildUsage, BuildUsageTagGlobal globalUsage)
|
||||
{
|
||||
assetInfo = new AssetLoadInfo();
|
||||
buildUsage = new BuildUsageTagSet();
|
||||
|
||||
var includedObjects = ContentBuildInterface.GetPlayerObjectIdentifiersInSerializedFile(path, m_Parameters.Target);
|
||||
var referencedObjects = ContentBuildInterface.GetPlayerDependenciesForObjects(includedObjects, m_Parameters.Target, m_Parameters.ScriptInfo);
|
||||
|
||||
assetInfo.includedObjects = new List<ObjectIdentifier>(includedObjects);
|
||||
assetInfo.referencedObjects = new List<ObjectIdentifier>(referencedObjects);
|
||||
|
||||
ContentBuildInterface.CalculateBuildUsageTags(referencedObjects, includedObjects, globalUsage, buildUsage, m_DependencyData.DependencyUsageCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Object Identifiers and Types in a raw Unity Serialized File. The resulting arrays will be empty if a non-serialized file path was used.
|
||||
/// </summary>
|
||||
/// <param name="path">Path to the Unity Serialized File</param>
|
||||
/// <param name="objectIdentifiers">Object Identifiers for all the objects in the serialized file</param>
|
||||
/// <param name="types">Types for all the objects in the serialized file</param>
|
||||
public void GetObjectIdentifiersAndTypesForSerializedFile(string path, out ObjectIdentifier[] objectIdentifiers, out Type[] types)
|
||||
{
|
||||
GetObjectIdentifiersAndTypesForSerializedFile(path, out objectIdentifiers, out types, default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Object Identifiers and Types in a raw Unity Serialized File. The resulting arrays will be empty if a non-serialized file path was used.
|
||||
/// </summary>
|
||||
/// <param name="path">Path to the Unity Serialized File</param>
|
||||
/// <param name="objectIdentifiers">Object Identifiers for all the objects in the serialized file</param>
|
||||
/// <param name="types">Types for all the objects in the serialized file</param>
|
||||
/// <param name="additionalGlobalUsage">Additional global lighting usage information to include with this custom asset</param>
|
||||
public void GetObjectIdentifiersAndTypesForSerializedFile(string path, out ObjectIdentifier[] objectIdentifiers, out Type[] types, BuildUsageTagGlobal additionalGlobalUsage)
|
||||
{
|
||||
// Additional global usage is local to the custom asset, so we are using a local copy of this additional data to avoid influencing the calcualtion
|
||||
// of other custom assets. Additionally we store all the addtional global usage for later copying back into the dependency data result for the final write build task.
|
||||
var globalUsage = m_GlobalUsage | additionalGlobalUsage;
|
||||
m_CustomUsage = m_CustomUsage | additionalGlobalUsage;
|
||||
if (!LoadCachedData(path, out var assetInfo, out var buildUsage, globalUsage))
|
||||
GatherAssetData(path, out assetInfo, out buildUsage, globalUsage);
|
||||
|
||||
// Local cache to reuse data from this function in the next function
|
||||
m_AssetInfo[path] = assetInfo;
|
||||
m_BuildUsage[path] = buildUsage;
|
||||
|
||||
objectIdentifiers = assetInfo.includedObjects.ToArray();
|
||||
types = BuildCacheUtility.GetSortedUniqueTypesForObjects(objectIdentifiers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds mapping and bundle information for a custom asset that contains a set of unity objects.
|
||||
/// </summary>
|
||||
/// <param name="includedObjects">Object Identifiers that belong to this custom asset</param>
|
||||
/// <param name="path">Path on disk for this custom asset</param>
|
||||
/// <param name="bundleName">Asset Bundle name where to add this custom asset</param>
|
||||
/// <param name="address">Load address to used to load this asset from the Asset Bundle</param>
|
||||
/// <param name="mainAssetType">Type of the main object for this custom asset</param>
|
||||
public void CreateAssetEntryForObjectIdentifiers(ObjectIdentifier[] includedObjects, string path, string bundleName, string address, Type mainAssetType)
|
||||
{
|
||||
AssetLoadInfo assetInfo = m_AssetInfo[path];
|
||||
BuildUsageTagSet buildUsage = m_BuildUsage[path];
|
||||
|
||||
assetInfo.asset = HashingMethods.Calculate(address).ToGUID();
|
||||
assetInfo.address = address;
|
||||
if (m_DependencyData.AssetInfo.ContainsKey(assetInfo.asset))
|
||||
throw new ArgumentException(string.Format("Custom Asset '{0}' already exists. Building duplicate asset entries is not supported.", address));
|
||||
SetOutputInformation(bundleName, assetInfo, buildUsage);
|
||||
}
|
||||
|
||||
void SetOutputInformation(string bundleName, AssetLoadInfo assetInfo, BuildUsageTagSet usageTags)
|
||||
{
|
||||
List<GUID> assets;
|
||||
m_Content.BundleLayout.GetOrAdd(bundleName, out assets);
|
||||
assets.Add(assetInfo.asset);
|
||||
|
||||
m_Content.Addresses.Add(assetInfo.asset, assetInfo.address);
|
||||
m_DependencyData.AssetInfo.Add(assetInfo.asset, assetInfo);
|
||||
m_DependencyData.AssetUsage.Add(assetInfo.asset, usageTags);
|
||||
m_CustomAssets.Assets.Add(assetInfo.asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5f0270e64b3580847a1adbb01f58852b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,266 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
#if !UNITY_2019_3_OR_NEWER
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculates the dependency data for all scenes.
|
||||
/// </summary>
|
||||
public class CalculateSceneDependencyData : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 6; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildContent m_Content;
|
||||
|
||||
[InjectContext]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext(ContextUsage.InOut, true)]
|
||||
IBuildResults m_Results;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IProgressTracker m_Tracker;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildCache m_Cache;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildLogger m_Log;
|
||||
#pragma warning restore 649
|
||||
|
||||
CacheEntry GetCacheEntry(GUID asset)
|
||||
{
|
||||
CacheEntry entry;
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
entry = m_Cache.GetCacheEntry(asset, m_Parameters.NonRecursiveDependencies ? -Version : Version);
|
||||
#else
|
||||
entry = m_Cache.GetCacheEntry(asset, Version);
|
||||
#endif
|
||||
return entry;
|
||||
}
|
||||
|
||||
CacheEntry GetCacheEntry(string asset)
|
||||
{
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
GUID guid = AssetDatabase.AssetPathToGUID_Internal(asset);
|
||||
#else
|
||||
string stringGUID = AssetDatabase.AssetPathToGUID(asset);
|
||||
if (GUID.TryParse(stringGUID, out GUID guid))
|
||||
return GetCacheEntry(guid);
|
||||
#endif
|
||||
if (!guid.Empty())
|
||||
return GetCacheEntry(guid);
|
||||
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
return m_Cache.GetCacheEntry(asset, m_Parameters.NonRecursiveDependencies ? -Version : Version);
|
||||
#else
|
||||
return m_Cache.GetCacheEntry(asset, Version);
|
||||
#endif
|
||||
}
|
||||
|
||||
CachedInfo GetCachedInfo(GUID scene, IEnumerable<ObjectIdentifier> references, SceneDependencyInfo sceneInfo, BuildUsageTagSet usageTags, IEnumerable<CacheEntry> prefabEntries, Hash128 prefabDependency)
|
||||
{
|
||||
var info = new CachedInfo();
|
||||
info.Asset = GetCacheEntry(scene);
|
||||
|
||||
#if ENABLE_TYPE_HASHING || UNITY_2020_1_OR_NEWER
|
||||
var uniqueTypes = new HashSet<System.Type>(sceneInfo.includedTypes);
|
||||
#else
|
||||
var uniqueTypes = new HashSet<System.Type>();
|
||||
#endif
|
||||
var objectTypes = new List<ObjectTypes>();
|
||||
var dependencies = new HashSet<CacheEntry>(prefabEntries);
|
||||
ExtensionMethods.ExtractCommonCacheData(m_Cache, null, references, uniqueTypes, objectTypes, dependencies);
|
||||
info.Dependencies = dependencies.ToArray();
|
||||
|
||||
info.Data = new object[] { sceneInfo, usageTags, prefabDependency, objectTypes };
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (m_Content.Scenes.IsNullOrEmpty())
|
||||
return ReturnCode.SuccessNotRun;
|
||||
|
||||
IList<CachedInfo> cachedInfo = null;
|
||||
IList<CachedInfo> uncachedInfo = null;
|
||||
if (m_Parameters.UseCache && m_Cache != null)
|
||||
{
|
||||
IList<CacheEntry> entries = m_Content.Scenes.Select(x => GetCacheEntry(x)).ToList();
|
||||
m_Cache.LoadCachedData(entries, out cachedInfo);
|
||||
|
||||
uncachedInfo = new List<CachedInfo>();
|
||||
}
|
||||
|
||||
List<CachedInfo> info = new List<CachedInfo>(m_Content.Scenes.Count);
|
||||
BuildSettings settings = m_Parameters.GetContentBuildSettings();
|
||||
for (int i = 0; i < m_Content.Scenes.Count; i++)
|
||||
{
|
||||
using (m_Log.ScopedStep(LogLevel.Info, "Calculate Scene Dependencies"))
|
||||
{
|
||||
GUID scene = m_Content.Scenes[i];
|
||||
string scenePath = AssetDatabase.GUIDToAssetPath(scene.ToString());
|
||||
|
||||
SceneDependencyInfo sceneInfo;
|
||||
BuildUsageTagSet usageTags;
|
||||
Hash128 prefabDependency = new Hash128();
|
||||
bool useUncachedScene = true;
|
||||
|
||||
if (cachedInfo != null && cachedInfo[i] != null)
|
||||
{
|
||||
info.Add(cachedInfo[i]);
|
||||
useUncachedScene = false;
|
||||
if (!m_Tracker.UpdateInfoUnchecked(string.Format("{0} (Cached)", scenePath)))
|
||||
return ReturnCode.Canceled;
|
||||
m_Log.AddEntrySafe(LogLevel.Info, $"{scene} (cached)");
|
||||
|
||||
sceneInfo = (SceneDependencyInfo)cachedInfo[i].Data[0];
|
||||
// case 1288677: Update scenePath in case scene moved, but didn't change
|
||||
sceneInfo.SetScene(scenePath);
|
||||
usageTags = cachedInfo[i].Data[1] as BuildUsageTagSet;
|
||||
prefabDependency = (Hash128)cachedInfo[i].Data[2];
|
||||
var objectTypes = cachedInfo[i].Data[3] as List<ObjectTypes>;
|
||||
if (objectTypes != null)
|
||||
{
|
||||
BuildCacheUtility.SetTypeForObjects(objectTypes);
|
||||
|
||||
foreach (var objectType in objectTypes)
|
||||
{
|
||||
//Sprite association to SpriteAtlas might have changed since last time data was cached, this might
|
||||
//imply that we have stale data in our cache, if so ensure we regenerate the data.
|
||||
if (objectType.Types[0] == typeof(UnityEngine.Sprite))
|
||||
{
|
||||
ObjectIdentifier[] filteredReferences = sceneInfo.referencedObjects.ToArray();
|
||||
ObjectIdentifier[] filteredReferencesNew = null;
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
if (m_Parameters.NonRecursiveDependencies)
|
||||
{
|
||||
var sceneInfoNew = ContentBuildInterface.CalculatePlayerDependenciesForScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache, DependencyType.ValidReferences);
|
||||
filteredReferencesNew = sceneInfoNew.referencedObjects.ToArray();
|
||||
filteredReferencesNew = ExtensionMethods.FilterReferencedObjectIDs(scene, filteredReferencesNew, m_Parameters.Target, m_Parameters.ScriptInfo, new HashSet<GUID>(m_Content.Assets));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
var sceneInfoNew = ContentBuildInterface.CalculatePlayerDependenciesForScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache);
|
||||
filteredReferencesNew = sceneInfoNew.referencedObjects.ToArray();
|
||||
}
|
||||
|
||||
if (Enumerable.SequenceEqual(filteredReferences,filteredReferencesNew) == false)
|
||||
{
|
||||
useUncachedScene = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (!useUncachedScene)
|
||||
SetOutputInformation(scene, sceneInfo, usageTags, prefabDependency);
|
||||
}
|
||||
|
||||
if(useUncachedScene)
|
||||
{
|
||||
if (!m_Tracker.UpdateInfoUnchecked(scenePath))
|
||||
return ReturnCode.Canceled;
|
||||
m_Log.AddEntrySafe(LogLevel.Info, $"{scene}");
|
||||
|
||||
usageTags = new BuildUsageTagSet();
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
if ( m_Parameters.NonRecursiveDependencies)
|
||||
{
|
||||
sceneInfo = ContentBuildInterface.CalculatePlayerDependenciesForScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache, DependencyType.ValidReferences);
|
||||
ObjectIdentifier[] filteredReferences = sceneInfo.referencedObjects.ToArray();
|
||||
filteredReferences = ExtensionMethods.FilterReferencedObjectIDs(scene, filteredReferences, m_Parameters.Target, m_Parameters.ScriptInfo, new HashSet<GUID>(m_Content.Assets));
|
||||
ContentBuildInterface.CalculateBuildUsageTags(filteredReferences, filteredReferences, sceneInfo.globalUsage, usageTags);
|
||||
sceneInfo.SetReferencedObjects(filteredReferences);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
sceneInfo = ContentBuildInterface.CalculatePlayerDependenciesForScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache);
|
||||
}
|
||||
#else
|
||||
string outputFolder = m_Parameters.TempOutputFolder;
|
||||
if (m_Parameters.UseCache && m_Cache != null)
|
||||
outputFolder = m_Cache.GetCachedArtifactsDirectory(GetSceneCacheEntry(scene, Version));
|
||||
System.IO.Directory.CreateDirectory(outputFolder);
|
||||
|
||||
sceneInfo = ContentBuildInterface.PrepareScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache, outputFolder);
|
||||
#endif
|
||||
if (uncachedInfo != null)
|
||||
{
|
||||
// We only need to gather prefab dependencies and calculate the hash if we are using caching, otherwise we can skip it
|
||||
string[] sceneDependencyPaths = AssetDatabase.GetDependencies(scenePath);
|
||||
List<CacheEntry> prefabEntries = new List<CacheEntry>();
|
||||
foreach (string assetPath in sceneDependencyPaths)
|
||||
{
|
||||
if (assetPath.EndsWith(".prefab", StringComparison.Ordinal))
|
||||
prefabEntries.Add(GetCacheEntry(assetPath));
|
||||
}
|
||||
prefabDependency = HashingMethods.Calculate(prefabEntries).ToHash128();
|
||||
var cacheInfo = GetCachedInfo(scene, sceneInfo.referencedObjects, sceneInfo, usageTags, prefabEntries, prefabDependency);
|
||||
uncachedInfo.Add(cacheInfo);
|
||||
info.Add(cacheInfo);
|
||||
}
|
||||
SetOutputInformation(scene, sceneInfo, usageTags, prefabDependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Parameters.UseCache && m_Cache != null)
|
||||
m_Cache.SaveCachedData(uncachedInfo);
|
||||
|
||||
if (info != null && m_Results != null)
|
||||
{
|
||||
foreach (CachedInfo sceneFileInfo in info)
|
||||
{
|
||||
Dictionary<ObjectIdentifier, System.Type[]> objectTypes = new Dictionary<ObjectIdentifier, System.Type[]>();
|
||||
List<ObjectTypes> types = sceneFileInfo.Data[3] as List<ObjectTypes>;
|
||||
foreach (var objectType in types)
|
||||
objectTypes.Add(objectType.ObjectID, objectType.Types);
|
||||
|
||||
AssetResultData resultData = new AssetResultData
|
||||
{
|
||||
Guid = sceneFileInfo.Asset.Guid,
|
||||
Hash = sceneFileInfo.Asset.Hash,
|
||||
IncludedObjects = new List<ObjectIdentifier>(),
|
||||
ReferencedObjects = null,
|
||||
ObjectTypes = objectTypes
|
||||
};
|
||||
m_Results.AssetResults.Add(resultData.Guid, resultData);
|
||||
}
|
||||
}
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
void SetOutputInformation(GUID asset, SceneDependencyInfo sceneInfo, BuildUsageTagSet usageTags, Hash128 prefabDependency)
|
||||
{
|
||||
// Add generated scene information to BuildDependencyData
|
||||
m_DependencyData.SceneInfo.Add(asset, sceneInfo);
|
||||
m_DependencyData.SceneUsage.Add(asset, usageTags);
|
||||
m_DependencyData.DependencyHash.Add(asset, prefabDependency);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e2d5a57757fc0cc4eb4f2fade47b59dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,158 @@
|
|||
#if UNITY_2022_2_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Pipeline.WriteTypes;
|
||||
using UnityEditor.Build.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
public interface IClusterOutput : IContextObject
|
||||
{
|
||||
Dictionary<ObjectIdentifier, Hash128> ObjectToCluster { get; }
|
||||
Dictionary<ObjectIdentifier, long> ObjectToLocalID { get; }
|
||||
}
|
||||
|
||||
public class ClusterOutput : IClusterOutput
|
||||
{
|
||||
private Dictionary<ObjectIdentifier, Hash128> m_ObjectToCluster = new Dictionary<ObjectIdentifier, Hash128>();
|
||||
private Dictionary<ObjectIdentifier, long> m_ObjectToLocalID = new Dictionary<ObjectIdentifier, long>();
|
||||
public Dictionary<ObjectIdentifier, Hash128> ObjectToCluster { get { return m_ObjectToCluster; } }
|
||||
public Dictionary<ObjectIdentifier, long> ObjectToLocalID { get { return m_ObjectToLocalID; } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build task for creating content archives based asset co-location.
|
||||
/// </summary>
|
||||
public class ClusterBuildLayout : IBuildTask
|
||||
{
|
||||
private static void GetOrAdd<TKey, TValue>(IDictionary<TKey, TValue> dictionary, TKey key, out TValue value) where TValue : new()
|
||||
{
|
||||
if (dictionary.TryGetValue(key, out value))
|
||||
return;
|
||||
|
||||
value = new TValue();
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext]
|
||||
IBundleWriteData m_WriteData;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDeterministicIdentifiers m_PackingMethod;
|
||||
|
||||
[InjectContext]
|
||||
IBuildResults m_Results;
|
||||
|
||||
[InjectContext]
|
||||
IClusterOutput m_ClusterResult;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
// Create usage maps
|
||||
Dictionary<ObjectIdentifier, HashSet<GUID>> objectToAssets = new Dictionary<ObjectIdentifier, HashSet<GUID>>();
|
||||
foreach (var pair in m_DependencyData.AssetInfo)
|
||||
{
|
||||
ExtractAssets(objectToAssets, pair.Key, pair.Value.includedObjects);
|
||||
ExtractAssets(objectToAssets, pair.Key, pair.Value.referencedObjects);
|
||||
}
|
||||
foreach (var pair in m_DependencyData.SceneInfo)
|
||||
{
|
||||
ExtractAssets(objectToAssets, pair.Key, pair.Value.referencedObjects);
|
||||
}
|
||||
|
||||
// Using usage maps, create clusters
|
||||
Dictionary<Hash128, HashSet<ObjectIdentifier>> clusterToObjects = new Dictionary<Hash128, HashSet<ObjectIdentifier>>();
|
||||
foreach (var pair in objectToAssets)
|
||||
{
|
||||
HashSet<GUID> assets = pair.Value;
|
||||
Hash128 cluster = HashingMethods.Calculate(assets.OrderBy(x => x)).ToHash128();
|
||||
GetOrAdd(clusterToObjects, cluster, out var objectIds);
|
||||
objectIds.Add(pair.Key);
|
||||
m_ClusterResult.ObjectToCluster.Add(pair.Key, cluster);
|
||||
}
|
||||
|
||||
// From clusters, create the final write data
|
||||
BuildUsageTagSet usageSet = new BuildUsageTagSet();
|
||||
foreach (var pair in m_DependencyData.AssetUsage)
|
||||
usageSet.UnionWith(pair.Value);
|
||||
foreach (var pair in m_DependencyData.SceneUsage)
|
||||
usageSet.UnionWith(pair.Value);
|
||||
|
||||
// Generates Content Archive Files from Clusters
|
||||
BuildReferenceMap referenceMap = new BuildReferenceMap();
|
||||
foreach (var pair in clusterToObjects)
|
||||
{
|
||||
var cluster = pair.Key.ToString();
|
||||
m_WriteData.FileToObjects.Add(cluster, pair.Value.ToList());
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
var op = new RawWriteOperation();
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
m_WriteData.WriteOperations.Add(op);
|
||||
|
||||
op.Command = new WriteCommand();
|
||||
op.Command.fileName = cluster;
|
||||
op.Command.internalName = cluster;
|
||||
op.Command.serializeObjects = new List<SerializationInfo>();
|
||||
foreach (var objectId in pair.Value)
|
||||
{
|
||||
var lfid = m_PackingMethod.SerializationIndexFromObjectIdentifier(objectId);
|
||||
op.Command.serializeObjects.Add(new SerializationInfo { serializationObject = objectId, serializationIndex = lfid });
|
||||
referenceMap.AddMapping(cluster, lfid, objectId);
|
||||
m_ClusterResult.ObjectToLocalID.Add(objectId, lfid);
|
||||
}
|
||||
op.ReferenceMap = referenceMap;
|
||||
op.UsageSet = usageSet;
|
||||
|
||||
m_WriteData.FileToBundle.Add(cluster, cluster);
|
||||
}
|
||||
|
||||
// Generates Content Scene Archive Files from Scene Input
|
||||
foreach (var pair in m_DependencyData.SceneInfo)
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
var op = new SceneRawWriteOperation();
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
m_WriteData.WriteOperations.Add(op);
|
||||
|
||||
op.Command = new WriteCommand();
|
||||
op.Command.fileName = pair.Key.ToString();
|
||||
op.Command.internalName = pair.Key.ToString();
|
||||
op.Command.serializeObjects = new List<SerializationInfo>();
|
||||
op.ReferenceMap = referenceMap;
|
||||
op.UsageSet = usageSet;
|
||||
op.Scene = pair.Value.scene;
|
||||
|
||||
m_WriteData.FileToBundle.Add(pair.Key.ToString(), pair.Key.ToString());
|
||||
}
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
private static void ExtractAssets(Dictionary<ObjectIdentifier, HashSet<GUID>> objectToAssets, GUID asset, IEnumerable<ObjectIdentifier> objectIds)
|
||||
{
|
||||
foreach (var objectId in objectIds)
|
||||
{
|
||||
if (objectId.filePath.Equals(CommonStrings.UnityDefaultResourcePath, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
GetOrAdd(objectToAssets, objectId, out var assets);
|
||||
assets.Add(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2fb47cf44ffdf4da8a7725b796217e67
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Optional build task that extracts Unity's built in shaders and assigns them to the specified bundle
|
||||
/// </summary>
|
||||
public class CreateBuiltInShadersBundle : IBuildTask
|
||||
{
|
||||
static readonly GUID k_BuiltInGuid = new GUID(CommonStrings.UnityBuiltInExtraGuid);
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext(ContextUsage.InOut, true)]
|
||||
IBundleExplictObjectLayout m_Layout;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <summary>
|
||||
/// Stores the name for the built-in shaders bundle.
|
||||
/// </summary>
|
||||
public string ShaderBundleName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create the built-in shaders bundle.
|
||||
/// </summary>
|
||||
/// <param name="bundleName">The name of the bundle.</param>
|
||||
public CreateBuiltInShadersBundle(string bundleName)
|
||||
{
|
||||
ShaderBundleName = bundleName;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
HashSet<ObjectIdentifier> buildInObjects = new HashSet<ObjectIdentifier>();
|
||||
foreach (AssetLoadInfo dependencyInfo in m_DependencyData.AssetInfo.Values)
|
||||
buildInObjects.UnionWith(dependencyInfo.referencedObjects.Where(x => x.guid == k_BuiltInGuid));
|
||||
|
||||
foreach (SceneDependencyInfo dependencyInfo in m_DependencyData.SceneInfo.Values)
|
||||
buildInObjects.UnionWith(dependencyInfo.referencedObjects.Where(x => x.guid == k_BuiltInGuid));
|
||||
|
||||
ObjectIdentifier[] usedSet = buildInObjects.ToArray();
|
||||
Type[] usedTypes = BuildCacheUtility.GetMainTypeForObjects(usedSet);
|
||||
|
||||
if (m_Layout == null)
|
||||
m_Layout = new BundleExplictObjectLayout();
|
||||
|
||||
Type shader = typeof(Shader);
|
||||
for (int i = 0; i < usedTypes.Length; i++)
|
||||
{
|
||||
if (usedTypes[i] != shader)
|
||||
continue;
|
||||
|
||||
m_Layout.ExplicitObjectLocation.Add(usedSet[i], ShaderBundleName);
|
||||
}
|
||||
|
||||
if (m_Layout.ExplicitObjectLocation.Count == 0)
|
||||
m_Layout = null;
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7b9ded651292a474fad227fce94f4c79
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Optional build task that extracts all referenced MonoScripts and assigns them to the specified bundle
|
||||
/// </summary>
|
||||
public class CreateMonoScriptBundle : IBuildTask
|
||||
{
|
||||
static readonly GUID k_DefaultGuid = new GUID(CommonStrings.UnityDefaultResourceGuid);
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext(ContextUsage.InOut, true)]
|
||||
IBundleExplictObjectLayout m_Layout;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <summary>
|
||||
/// Stores the name for the MonoScript bundle.
|
||||
/// </summary>
|
||||
public string MonoScriptBundleName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create the MonoScript bundle.
|
||||
/// </summary>
|
||||
/// <param name="bundleName">The name of the bundle.</param>
|
||||
public CreateMonoScriptBundle(string bundleName)
|
||||
{
|
||||
MonoScriptBundleName = bundleName;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
HashSet<ObjectIdentifier> buildInObjects = new HashSet<ObjectIdentifier>();
|
||||
foreach (AssetLoadInfo dependencyInfo in m_DependencyData.AssetInfo.Values)
|
||||
buildInObjects.UnionWith(dependencyInfo.referencedObjects);
|
||||
|
||||
foreach (SceneDependencyInfo dependencyInfo in m_DependencyData.SceneInfo.Values)
|
||||
buildInObjects.UnionWith(dependencyInfo.referencedObjects);
|
||||
|
||||
ObjectIdentifier[] usedSet = buildInObjects.ToArray();
|
||||
Type[] usedTypes = BuildCacheUtility.GetMainTypeForObjects(usedSet);
|
||||
|
||||
if (m_Layout == null)
|
||||
m_Layout = new BundleExplictObjectLayout();
|
||||
|
||||
Type monoScript = typeof(MonoScript);
|
||||
for (int i = 0; i < usedTypes.Length; i++)
|
||||
{
|
||||
if (usedTypes[i] != monoScript || usedSet[i].guid == k_DefaultGuid)
|
||||
continue;
|
||||
|
||||
m_Layout.ExplicitObjectLocation.Add(usedSet[i], MonoScriptBundleName);
|
||||
}
|
||||
|
||||
if (m_Layout.ExplicitObjectLocation.Count == 0)
|
||||
m_Layout = null;
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 96b169e370585d7489d37bc46ef5e3bf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,317 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Pipeline.WriteTypes;
|
||||
using UnityEditor.Build.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates bundle commands for assets and scenes.
|
||||
/// </summary>
|
||||
public class GenerateBundleCommands : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBundleBuildContent m_BuildContent;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext]
|
||||
IBundleWriteData m_WriteData;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDeterministicIdentifiers m_PackingMethod;
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
ICustomAssets m_CustomAssets;
|
||||
#endif
|
||||
#pragma warning restore 649
|
||||
|
||||
static bool ValidAssetBundle(List<GUID> assets, HashSet<GUID> customAssets)
|
||||
{
|
||||
// Custom Valid Asset Bundle function that tests if every asset is known by the asset database, is an asset (not a scene), or is a user driven custom asset
|
||||
return assets.All(x => ValidationMethods.ValidAsset(x) == ValidationMethods.Status.Asset || customAssets.Contains(x));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
HashSet<GUID> customAssets = new HashSet<GUID>();
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
if (m_CustomAssets != null)
|
||||
customAssets.UnionWith(m_CustomAssets.Assets);
|
||||
#endif
|
||||
Dictionary<GUID, string> assetToMainFile = new Dictionary<GUID, string>();
|
||||
foreach (var pair in m_WriteData.AssetToFiles)
|
||||
assetToMainFile.Add(pair.Key, pair.Value[0]);
|
||||
|
||||
foreach (var bundlePair in m_BuildContent.BundleLayout)
|
||||
{
|
||||
if (ValidAssetBundle(bundlePair.Value, customAssets))
|
||||
{
|
||||
// Use generated internalName here as we could have an empty asset bundle used for raw object storage (See CreateStandardShadersBundle)
|
||||
var internalName = string.Format(CommonStrings.AssetBundleNameFormat, m_PackingMethod.GenerateInternalFileName(bundlePair.Key));
|
||||
CreateAssetBundleCommand(bundlePair.Key, internalName, bundlePair.Value);
|
||||
}
|
||||
else if (ValidationMethods.ValidSceneBundle(bundlePair.Value))
|
||||
{
|
||||
var firstScene = bundlePair.Value[0];
|
||||
CreateSceneBundleCommand(bundlePair.Key, assetToMainFile[firstScene], firstScene, bundlePair.Value, assetToMainFile);
|
||||
for (int i = 1; i < bundlePair.Value.Count; ++i)
|
||||
{
|
||||
var additionalScene = bundlePair.Value[i];
|
||||
CreateSceneDataCommand(assetToMainFile[additionalScene], additionalScene);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
internal static WriteCommand CreateWriteCommand(string internalName, List<ObjectIdentifier> objects, IDeterministicIdentifiers packingMethod)
|
||||
{
|
||||
var command = new WriteCommand();
|
||||
command.internalName = internalName;
|
||||
command.fileName = Path.GetFileName(internalName);
|
||||
|
||||
command.serializeObjects = new List<SerializationInfo>();
|
||||
var consumedIds = new Dictionary<long, ObjectIdentifier>();
|
||||
foreach (var obj in objects)
|
||||
{
|
||||
var serializationInfo = new SerializationInfo
|
||||
{
|
||||
serializationObject = obj,
|
||||
serializationIndex = packingMethod.SerializationIndexFromObjectIdentifier(obj)
|
||||
};
|
||||
|
||||
if (consumedIds.TryGetValue(serializationInfo.serializationIndex, out var priorObject))
|
||||
{
|
||||
string msg = string.Format(@"File '{0}' contains a file identifier collision between {1} ({2}) and {3} ({4}) at id {5}. Objects will be missing from the bundle!
|
||||
You can work around this issue by changing the 'FileID Generator Seed' found in the Scriptable Build Pipeline Preferences window.",
|
||||
internalName, obj, BuildCacheUtility.GetMainTypeForObject(obj), priorObject, BuildCacheUtility.GetMainTypeForObject(priorObject), serializationInfo.serializationIndex);
|
||||
throw new BuildFailedException(msg);
|
||||
}
|
||||
consumedIds.Add(serializationInfo.serializationIndex, obj);
|
||||
command.serializeObjects.Add(serializationInfo);
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
// Sort function to ensure Asset Bundle's path container is ordered deterministically everytime
|
||||
internal static int AssetLoadInfoCompare(AssetLoadInfo x, AssetLoadInfo y)
|
||||
{
|
||||
if (x.asset != y.asset)
|
||||
return x.asset.CompareTo(y.asset);
|
||||
if (x.includedObjects.IsNullOrEmpty() && !y.includedObjects.IsNullOrEmpty())
|
||||
return -1;
|
||||
if (!x.includedObjects.IsNullOrEmpty() && y.includedObjects.IsNullOrEmpty())
|
||||
return 1;
|
||||
if (!x.includedObjects.IsNullOrEmpty() && !y.includedObjects.IsNullOrEmpty())
|
||||
{
|
||||
if (x.includedObjects[0] < y.includedObjects[0])
|
||||
return -1;
|
||||
if (x.includedObjects[0] > y.includedObjects[0])
|
||||
return 1;
|
||||
}
|
||||
if (string.IsNullOrEmpty(x.address) && !string.IsNullOrEmpty(y.address))
|
||||
return -1;
|
||||
if (!string.IsNullOrEmpty(x.address) && string.IsNullOrEmpty(y.address))
|
||||
return 1;
|
||||
if (!string.IsNullOrEmpty(x.address) && !string.IsNullOrEmpty(y.address))
|
||||
return x.address.CompareTo(y.address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CreateAssetBundleCommand(string bundleName, string internalName, List<GUID> assets)
|
||||
{
|
||||
var command = CreateWriteCommand(internalName, m_WriteData.FileToObjects[internalName], m_PackingMethod);
|
||||
var usageSet = new BuildUsageTagSet();
|
||||
var referenceMap = new BuildReferenceMap();
|
||||
var dependencyHashes = new List<Hash128>();
|
||||
var bundleAssets = new List<AssetLoadInfo>();
|
||||
|
||||
|
||||
referenceMap.AddMappings(command.internalName, command.serializeObjects.ToArray());
|
||||
foreach (var asset in assets)
|
||||
{
|
||||
usageSet.UnionWith(m_DependencyData.AssetUsage[asset]);
|
||||
if (m_DependencyData.DependencyHash.TryGetValue(asset, out var hash))
|
||||
dependencyHashes.Add(hash);
|
||||
AssetLoadInfo assetInfo = m_DependencyData.AssetInfo[asset];
|
||||
assetInfo.address = m_BuildContent.Addresses[asset];
|
||||
bundleAssets.Add(assetInfo);
|
||||
}
|
||||
bundleAssets.Sort(AssetLoadInfoCompare);
|
||||
|
||||
|
||||
var operation = new AssetBundleWriteOperation();
|
||||
operation.Command = command;
|
||||
operation.UsageSet = usageSet;
|
||||
operation.ReferenceMap = referenceMap;
|
||||
operation.DependencyHash = !dependencyHashes.IsNullOrEmpty() ? HashingMethods.Calculate(dependencyHashes).ToHash128() : new Hash128();
|
||||
operation.Info = new AssetBundleInfo();
|
||||
operation.Info.bundleName = bundleName;
|
||||
operation.Info.bundleAssets = bundleAssets;
|
||||
|
||||
|
||||
m_WriteData.WriteOperations.Add(operation);
|
||||
m_WriteData.FileToUsageSet.Add(command.internalName, usageSet);
|
||||
m_WriteData.FileToReferenceMap.Add(command.internalName, referenceMap);
|
||||
}
|
||||
|
||||
#if !UNITY_2019_1_OR_NEWER || NONRECURSIVE_DEPENDENCY_DATA
|
||||
static int GetSortIndex(System.Type type)
|
||||
{
|
||||
// Closely matches CalculateSortIndex in C++, not 100% as the same info is not available to C#, doesn't need to be 100%
|
||||
if (type == null)
|
||||
return int.MaxValue - 5;
|
||||
if (type == typeof(MonoScript))
|
||||
return int.MinValue;
|
||||
if (typeof(ScriptableObject).IsAssignableFrom(type))
|
||||
return int.MaxValue - 4;
|
||||
if (typeof(MonoBehaviour).IsAssignableFrom(type))
|
||||
return int.MaxValue - 3;
|
||||
if (typeof(TerrainData).IsAssignableFrom(type))
|
||||
return int.MaxValue - 2;
|
||||
return System.BitConverter.ToInt32(HashingMethods.Calculate(type.Name).ToBytes(), 0);
|
||||
}
|
||||
|
||||
struct SortObject
|
||||
{
|
||||
public ObjectIdentifier objectId;
|
||||
public int sortIndex;
|
||||
}
|
||||
|
||||
internal static List<ObjectIdentifier> GetSortedSceneObjectIdentifiers(List<ObjectIdentifier> objects)
|
||||
{
|
||||
var types = new List<System.Type>(BuildCacheUtility.GetMainTypeForObjects(objects));
|
||||
var sortedObjects = new List<SortObject>();
|
||||
for (int i = 0; i < objects.Count; i++)
|
||||
sortedObjects.Add(new SortObject { sortIndex = GetSortIndex(types[i]), objectId = objects[i] });
|
||||
return sortedObjects.OrderBy(x => x.sortIndex).Select(x => x.objectId).ToList();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
List<ObjectIdentifier> GetFileObjectsForScene(string internalName)
|
||||
{
|
||||
var fileObjects = m_WriteData.FileToObjects[internalName];
|
||||
#if !UNITY_2019_1_OR_NEWER || NONRECURSIVE_DEPENDENCY_DATA
|
||||
// ContentBuildInterface.PrepareScene was not returning stable sorted references, causing a indeterminism and loading errors in some cases
|
||||
// Add correct sorting here until patch lands to fix the API.
|
||||
// Additionally, if we are using Non-Recursive build mode, we still need to sort by type.
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
if (m_Parameters.NonRecursiveDependencies)
|
||||
#endif
|
||||
{
|
||||
fileObjects = GetSortedSceneObjectIdentifiers(fileObjects);
|
||||
}
|
||||
#endif
|
||||
return fileObjects;
|
||||
}
|
||||
|
||||
void CreateSceneBundleCommand(string bundleName, string internalName, GUID scene, List<GUID> bundledScenes, Dictionary<GUID, string> assetToMainFile)
|
||||
{
|
||||
var fileObjects = GetFileObjectsForScene(internalName);
|
||||
var command = CreateWriteCommand(internalName, fileObjects, new LinearPackedIdentifiers(3)); // Start at 3: PreloadData = 1, AssetBundle = 2
|
||||
var usageSet = new BuildUsageTagSet();
|
||||
var referenceMap = new BuildReferenceMap();
|
||||
var preloadObjects = new List<ObjectIdentifier>();
|
||||
var bundleScenes = new List<SceneLoadInfo>();
|
||||
var dependencyInfo = m_DependencyData.SceneInfo[scene];
|
||||
var fileObjectSet = new HashSet<ObjectIdentifier>(fileObjects);
|
||||
|
||||
|
||||
usageSet.UnionWith(m_DependencyData.SceneUsage[scene]);
|
||||
referenceMap.AddMappings(command.internalName, command.serializeObjects.ToArray());
|
||||
foreach (var referencedObject in dependencyInfo.referencedObjects)
|
||||
{
|
||||
if (fileObjectSet.Contains(referencedObject))
|
||||
continue;
|
||||
preloadObjects.Add(referencedObject);
|
||||
}
|
||||
foreach (var bundledScene in bundledScenes)
|
||||
{
|
||||
var loadInfo = new SceneLoadInfo();
|
||||
loadInfo.asset = bundledScene;
|
||||
loadInfo.internalName = Path.GetFileNameWithoutExtension(assetToMainFile[bundledScene]);
|
||||
loadInfo.address = m_BuildContent.Addresses[bundledScene];
|
||||
bundleScenes.Add(loadInfo);
|
||||
}
|
||||
|
||||
|
||||
var operation = new SceneBundleWriteOperation();
|
||||
operation.Command = command;
|
||||
operation.UsageSet = usageSet;
|
||||
operation.ReferenceMap = referenceMap;
|
||||
operation.DependencyHash = m_DependencyData.DependencyHash.TryGetValue(scene, out var hash) ? hash : new Hash128();
|
||||
operation.Scene = dependencyInfo.scene;
|
||||
#if !UNITY_2019_3_OR_NEWER
|
||||
operation.ProcessedScene = dependencyInfo.processedScene;
|
||||
#endif
|
||||
operation.PreloadInfo = new PreloadInfo();
|
||||
operation.PreloadInfo.preloadObjects = preloadObjects;
|
||||
operation.Info = new SceneBundleInfo();
|
||||
operation.Info.bundleName = bundleName;
|
||||
operation.Info.bundleScenes = bundleScenes;
|
||||
|
||||
|
||||
m_WriteData.WriteOperations.Add(operation);
|
||||
m_WriteData.FileToUsageSet.Add(command.internalName, usageSet);
|
||||
m_WriteData.FileToReferenceMap.Add(command.internalName, referenceMap);
|
||||
}
|
||||
|
||||
void CreateSceneDataCommand(string internalName, GUID scene)
|
||||
{
|
||||
var fileObjects = GetFileObjectsForScene(internalName);
|
||||
var command = CreateWriteCommand(internalName, fileObjects, new LinearPackedIdentifiers(2)); // Start at 3: PreloadData = 1
|
||||
var usageSet = new BuildUsageTagSet();
|
||||
var referenceMap = new BuildReferenceMap();
|
||||
var preloadObjects = new List<ObjectIdentifier>();
|
||||
var dependencyInfo = m_DependencyData.SceneInfo[scene];
|
||||
var fileObjectSet = new HashSet<ObjectIdentifier>(fileObjects);
|
||||
|
||||
|
||||
usageSet.UnionWith(m_DependencyData.SceneUsage[scene]);
|
||||
referenceMap.AddMappings(command.internalName, command.serializeObjects.ToArray());
|
||||
foreach (var referencedObject in dependencyInfo.referencedObjects)
|
||||
{
|
||||
if (fileObjectSet.Contains(referencedObject))
|
||||
continue;
|
||||
preloadObjects.Add(referencedObject);
|
||||
}
|
||||
|
||||
|
||||
var operation = new SceneDataWriteOperation();
|
||||
operation.Command = command;
|
||||
operation.UsageSet = usageSet;
|
||||
operation.ReferenceMap = referenceMap;
|
||||
operation.DependencyHash = m_DependencyData.DependencyHash.TryGetValue(scene, out var hash) ? hash : new Hash128();
|
||||
operation.Scene = dependencyInfo.scene;
|
||||
#if !UNITY_2019_3_OR_NEWER
|
||||
operation.ProcessedScene = dependencyInfo.processedScene;
|
||||
#endif
|
||||
operation.PreloadInfo = new PreloadInfo();
|
||||
operation.PreloadInfo.preloadObjects = preloadObjects;
|
||||
|
||||
|
||||
m_WriteData.FileToReferenceMap.Add(command.internalName, referenceMap);
|
||||
m_WriteData.FileToUsageSet.Add(command.internalName, usageSet);
|
||||
m_WriteData.WriteOperations.Add(operation);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f8f85552081e62e47abaaba497a138d7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,124 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates reference maps and usage sets for asset bundles.
|
||||
/// </summary>
|
||||
public class GenerateBundleMaps : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext]
|
||||
IBundleWriteData m_WriteData;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildLogger m_Log;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
Dictionary<string, WriteCommand> fileToCommand;
|
||||
Dictionary<string, HashSet<ObjectIdentifier>> forwardObjectDependencies;
|
||||
Dictionary<string, HashSet<string>> forwardFileDependencies;
|
||||
Dictionary<string, HashSet<GUID>> reverseAssetDependencies;
|
||||
|
||||
// BuildReferenceMap details what objects exist in other bundles that objects in a source bundle depend upon (forward dependencies)
|
||||
// BuildUsageTagSet details the conditional data needed to be written by objects in a source bundle that is in used by objects in other bundles (reverse dependencies)
|
||||
using (m_Log.ScopedStep(LogLevel.Info, $"Temporary Map Creations"))
|
||||
{
|
||||
fileToCommand = m_WriteData.WriteOperations.ToDictionary(x => x.Command.internalName, x => x.Command);
|
||||
forwardObjectDependencies = new Dictionary<string, HashSet<ObjectIdentifier>>();
|
||||
forwardFileDependencies = new Dictionary<string, HashSet<string>>();
|
||||
reverseAssetDependencies = new Dictionary<string, HashSet<GUID>>();
|
||||
foreach (var pair in m_WriteData.AssetToFiles)
|
||||
{
|
||||
GUID asset = pair.Key;
|
||||
List<string> files = pair.Value;
|
||||
|
||||
// The includes for an asset live in the first file, references could live in any file
|
||||
forwardObjectDependencies.GetOrAdd(files[0], out HashSet<ObjectIdentifier> objectDependencies);
|
||||
forwardFileDependencies.GetOrAdd(files[0], out HashSet<string> fileDependencies);
|
||||
|
||||
// Grab the list of object references for the asset or scene and add them to the forward dependencies hash set for this file (write command)
|
||||
if (m_DependencyData.AssetInfo.TryGetValue(asset, out AssetLoadInfo assetInfo))
|
||||
objectDependencies.UnionWith(assetInfo.referencedObjects);
|
||||
if (m_DependencyData.SceneInfo.TryGetValue(asset, out SceneDependencyInfo sceneInfo))
|
||||
objectDependencies.UnionWith(sceneInfo.referencedObjects);
|
||||
|
||||
// Grab the list of file references for the asset or scene and add them to the forward dependencies hash set for this file (write command)
|
||||
// While doing so, also add the asset to the reverse dependencies hash set for all the other files it depends upon.
|
||||
// We already ensure BuildReferenceMap & BuildUsageTagSet contain the objects in this write command in GenerateBundleCommands. So skip over the first file (self)
|
||||
for (int i = 1; i < files.Count; i++)
|
||||
{
|
||||
fileDependencies.Add(files[i]);
|
||||
reverseAssetDependencies.GetOrAdd(files[i], out HashSet<GUID> reverseDependencies);
|
||||
reverseDependencies.Add(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Using the previously generated forward dependency maps, update the BuildReferenceMap per WriteCommand to contain just the references that we care about
|
||||
using (m_Log.ScopedStep(LogLevel.Info, $"Populate BuildReferenceMaps"))
|
||||
{
|
||||
foreach (var operation in m_WriteData.WriteOperations)
|
||||
{
|
||||
var internalName = operation.Command.internalName;
|
||||
|
||||
BuildReferenceMap referenceMap = m_WriteData.FileToReferenceMap[internalName];
|
||||
if (!forwardObjectDependencies.TryGetValue(internalName, out var objectDependencies))
|
||||
continue; // this bundle has no external dependencies
|
||||
if (!forwardFileDependencies.TryGetValue(internalName, out var fileDependencies))
|
||||
continue; // this bundle has no external dependencies
|
||||
foreach (string file in fileDependencies)
|
||||
{
|
||||
WriteCommand dependentCommand = fileToCommand[file];
|
||||
foreach (var serializedObject in dependentCommand.serializeObjects)
|
||||
{
|
||||
// Only add objects we are referencing. This ensures that new/removed objects to files we depend upon will not cause a rebuild
|
||||
// of this file, unless are referencing the new/removed objects.
|
||||
if (!objectDependencies.Contains(serializedObject.serializationObject))
|
||||
continue;
|
||||
|
||||
referenceMap.AddMapping(file, serializedObject.serializationIndex, serializedObject.serializationObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Using the previously generate reverse dependency map, create the BuildUsageTagSet per WriteCommand to contain just the data that we care about
|
||||
using (m_Log.ScopedStep(LogLevel.Info, $"Populate BuildUsageTagSet"))
|
||||
{
|
||||
foreach (var operation in m_WriteData.WriteOperations)
|
||||
{
|
||||
var internalName = operation.Command.internalName;
|
||||
BuildUsageTagSet fileUsage = m_WriteData.FileToUsageSet[internalName];
|
||||
if (reverseAssetDependencies.TryGetValue(internalName, out var assetDependencies))
|
||||
{
|
||||
foreach (GUID asset in assetDependencies)
|
||||
{
|
||||
if (m_DependencyData.AssetUsage.TryGetValue(asset, out var assetUsage))
|
||||
fileUsage.UnionWith(assetUsage);
|
||||
if (m_DependencyData.SceneUsage.TryGetValue(asset, out var sceneUsage))
|
||||
fileUsage.UnionWith(sceneUsage);
|
||||
}
|
||||
}
|
||||
if (ReflectionExtensions.SupportsFilterToSubset)
|
||||
fileUsage.FilterToSubset(m_WriteData.FileToObjects[internalName].ToArray());
|
||||
}
|
||||
}
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9d24a7995f0e1ed4c81c185bcc48a695
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,223 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Packs each asset bundle and calculates the asset load file dependency list.
|
||||
/// </summary>
|
||||
public class GenerateBundlePacking : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBundleBuildContent m_BuildContent;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext]
|
||||
IBundleWriteData m_WriteData;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDeterministicIdentifiers m_PackingMethod;
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
ICustomAssets m_CustomAssets;
|
||||
#endif
|
||||
#pragma warning restore 649
|
||||
|
||||
static bool ValidAssetBundle(List<GUID> assets, HashSet<GUID> customAssets)
|
||||
{
|
||||
// Custom Valid Asset Bundle function that tests if every asset is known by the asset database, is an asset (not a scene), or is a user driven custom asset
|
||||
return assets.All(x => ValidationMethods.ValidAsset(x) == ValidationMethods.Status.Asset || customAssets.Contains(x));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
Dictionary<GUID, List<GUID>> assetToReferences = new Dictionary<GUID, List<GUID>>();
|
||||
HashSet<GUID> customAssets = new HashSet<GUID>();
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
if (m_CustomAssets != null)
|
||||
customAssets.UnionWith(m_CustomAssets.Assets);
|
||||
#endif
|
||||
|
||||
// Pack each asset bundle
|
||||
foreach (var bundle in m_BuildContent.BundleLayout)
|
||||
{
|
||||
if (ValidAssetBundle(bundle.Value, customAssets))
|
||||
PackAssetBundle(bundle.Key, bundle.Value, assetToReferences);
|
||||
else if (ValidationMethods.ValidSceneBundle(bundle.Value))
|
||||
PackSceneBundle(bundle.Key, bundle.Value, assetToReferences);
|
||||
}
|
||||
|
||||
// Calculate Asset file load dependency list
|
||||
foreach (var bundle in m_BuildContent.BundleLayout)
|
||||
{
|
||||
foreach (var asset in bundle.Value)
|
||||
{
|
||||
List<string> files = m_WriteData.AssetToFiles[asset];
|
||||
List<GUID> references = assetToReferences[asset];
|
||||
foreach (var reference in references)
|
||||
{
|
||||
List<string> referenceFiles = m_WriteData.AssetToFiles[reference];
|
||||
if (!files.Contains(referenceFiles[0]))
|
||||
files.Add(referenceFiles[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
void PackAssetBundle(string bundleName, List<GUID> includedAssets, Dictionary<GUID, List<GUID>> assetToReferences)
|
||||
{
|
||||
var internalName = string.Format(CommonStrings.AssetBundleNameFormat, m_PackingMethod.GenerateInternalFileName(bundleName));
|
||||
|
||||
var allObjects = new HashSet<ObjectIdentifier>();
|
||||
Dictionary<GUID, HashSet<ObjectIdentifier>> assetObjectIdentifierHashSets = new Dictionary<GUID, HashSet<ObjectIdentifier>>();
|
||||
foreach (var asset in includedAssets)
|
||||
{
|
||||
AssetLoadInfo assetInfo = m_DependencyData.AssetInfo[asset];
|
||||
allObjects.UnionWith(assetInfo.includedObjects);
|
||||
|
||||
var references = new List<ObjectIdentifier>();
|
||||
references.AddRange(assetInfo.referencedObjects);
|
||||
assetToReferences[asset] = FilterReferencesForAsset(m_DependencyData, asset, references, null, null, assetObjectIdentifierHashSets);
|
||||
|
||||
allObjects.UnionWith(references);
|
||||
m_WriteData.AssetToFiles[asset] = new List<string> { internalName };
|
||||
}
|
||||
|
||||
m_WriteData.FileToBundle.Add(internalName, bundleName);
|
||||
m_WriteData.FileToObjects.Add(internalName, allObjects.ToList());
|
||||
}
|
||||
|
||||
void PackSceneBundle(string bundleName, List<GUID> includedScenes, Dictionary<GUID, List<GUID>> assetToReferences)
|
||||
{
|
||||
if (includedScenes.IsNullOrEmpty())
|
||||
return;
|
||||
|
||||
string firstFileName = "";
|
||||
HashSet<ObjectIdentifier> previousSceneObjects = new HashSet<ObjectIdentifier>();
|
||||
HashSet<GUID> previousSceneAssets = new HashSet<GUID>();
|
||||
List<string> sceneInternalNames = new List<string>();
|
||||
Dictionary<GUID, HashSet<ObjectIdentifier>> assetObjectIdentifierHashSets = new Dictionary<GUID, HashSet<ObjectIdentifier>>();
|
||||
foreach (var scene in includedScenes)
|
||||
{
|
||||
var scenePath = AssetDatabase.GUIDToAssetPath(scene.ToString());
|
||||
var internalSceneName = m_PackingMethod.GenerateInternalFileName(scenePath);
|
||||
if (string.IsNullOrEmpty(firstFileName))
|
||||
firstFileName = internalSceneName;
|
||||
var internalName = string.Format(CommonStrings.SceneBundleNameFormat, firstFileName, internalSceneName);
|
||||
|
||||
SceneDependencyInfo sceneInfo = m_DependencyData.SceneInfo[scene];
|
||||
|
||||
var references = new List<ObjectIdentifier>();
|
||||
references.AddRange(sceneInfo.referencedObjects);
|
||||
assetToReferences[scene] = FilterReferencesForAsset(m_DependencyData, scene, references, previousSceneObjects, previousSceneAssets, assetObjectIdentifierHashSets);
|
||||
previousSceneObjects.UnionWith(references);
|
||||
previousSceneAssets.UnionWith(assetToReferences[scene]);
|
||||
|
||||
m_WriteData.FileToObjects.Add(internalName, references);
|
||||
m_WriteData.FileToBundle.Add(internalName, bundleName);
|
||||
|
||||
var files = new List<string> { internalName };
|
||||
files.AddRange(sceneInternalNames);
|
||||
m_WriteData.AssetToFiles[scene] = files;
|
||||
|
||||
sceneInternalNames.Add(internalName);
|
||||
}
|
||||
}
|
||||
|
||||
static HashSet<ObjectIdentifier> GetRefObjectIdLookup(AssetLoadInfo referencedAsset, Dictionary<GUID, HashSet<ObjectIdentifier>> assetObjectIdentifierHashSets)
|
||||
{
|
||||
HashSet<ObjectIdentifier> refObjectIdLookup;
|
||||
if ((assetObjectIdentifierHashSets == null) || (!assetObjectIdentifierHashSets.TryGetValue(referencedAsset.asset, out refObjectIdLookup)))
|
||||
{
|
||||
refObjectIdLookup = new HashSet<ObjectIdentifier>(referencedAsset.referencedObjects);
|
||||
assetObjectIdentifierHashSets?.Add(referencedAsset.asset, refObjectIdLookup);
|
||||
}
|
||||
return refObjectIdLookup;
|
||||
}
|
||||
|
||||
internal static List<GUID> FilterReferencesForAsset(IDependencyData dependencyData, GUID asset, List<ObjectIdentifier> references, HashSet<ObjectIdentifier> previousSceneObjects = null, HashSet<GUID> previousSceneReferences = null, Dictionary<GUID, HashSet<ObjectIdentifier>> assetObjectIdentifierHashSets = null)
|
||||
{
|
||||
var referencedAssets = new HashSet<AssetLoadInfo>();
|
||||
var referencedAssetsGuids = new List<GUID>(referencedAssets.Count);
|
||||
var referencesPruned = new List<ObjectIdentifier>(references.Count);
|
||||
// Remove Default Resources and Includes for Assets assigned to Bundles
|
||||
foreach (ObjectIdentifier reference in references)
|
||||
{
|
||||
if (reference.filePath.Equals(CommonStrings.UnityDefaultResourcePath, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
if (dependencyData.AssetInfo.TryGetValue(reference.guid, out AssetLoadInfo referenceInfo))
|
||||
{
|
||||
if (referencedAssets.Add(referenceInfo))
|
||||
referencedAssetsGuids.Add(referenceInfo.asset);
|
||||
continue;
|
||||
}
|
||||
referencesPruned.Add(reference);
|
||||
}
|
||||
references.Clear();
|
||||
references.AddRange(referencesPruned);
|
||||
|
||||
// Remove References also included by non-circular Referenced Assets
|
||||
// Remove References also included by circular Referenced Assets if Asset's GUID is higher than Referenced Asset's GUID
|
||||
foreach (AssetLoadInfo referencedAsset in referencedAssets)
|
||||
{
|
||||
if ((asset > referencedAsset.asset) || (asset == referencedAsset.asset))
|
||||
{
|
||||
references.RemoveAll(GetRefObjectIdLookup(referencedAsset, assetObjectIdentifierHashSets).Contains);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool exists = false;
|
||||
foreach (ObjectIdentifier referencedObject in referencedAsset.referencedObjects)
|
||||
{
|
||||
if (referencedObject.guid == asset)
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exists)
|
||||
{
|
||||
references.RemoveAll(GetRefObjectIdLookup(referencedAsset, assetObjectIdentifierHashSets).Contains);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special path for scenes, they can reference the same assets previously references
|
||||
if (!previousSceneReferences.IsNullOrEmpty())
|
||||
{
|
||||
foreach (GUID reference in previousSceneReferences)
|
||||
{
|
||||
if (!dependencyData.AssetInfo.TryGetValue(reference, out AssetLoadInfo referencedAsset))
|
||||
continue;
|
||||
|
||||
var refObjectIdLookup = GetRefObjectIdLookup(referencedAsset, assetObjectIdentifierHashSets);
|
||||
// NOTE: It's impossible for an asset to depend on a scene, thus no need for circular reference checks
|
||||
// So just remove and add a dependency on the asset if there is a need to depend upon it.
|
||||
if (references.RemoveAll(refObjectIdLookup.Contains) > 0)
|
||||
referencedAssetsGuids.Add(referencedAsset.asset);
|
||||
}
|
||||
}
|
||||
|
||||
// Special path for scenes, they can use data from previous sharedAssets in the same bundle
|
||||
if (!previousSceneObjects.IsNullOrEmpty())
|
||||
references.RemoveAll(previousSceneObjects.Contains);
|
||||
return referencedAssetsGuids;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8de0232a33280c9479a3db23d266ef17
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,49 @@
|
|||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a link.xml file in the output folder to use with Unity managed code stripping.
|
||||
/// </summary>
|
||||
public class GenerateLinkXml : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildResults m_Results;
|
||||
#pragma warning restore 649
|
||||
|
||||
const string k_LinkXml = "link.xml";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (!m_Parameters.WriteLinkXML)
|
||||
return ReturnCode.SuccessNotRun;
|
||||
|
||||
var linker = LinkXmlGenerator.CreateDefault();
|
||||
foreach (var writeResult in m_Results.WriteResults)
|
||||
{
|
||||
linker.AddTypes(writeResult.Value.includedTypes);
|
||||
#if UNITY_2021_1_OR_NEWER
|
||||
linker.AddSerializedClass(writeResult.Value.includedSerializeReferenceFQN);
|
||||
#else
|
||||
if (writeResult.Value.GetType().GetProperty("includedSerializeReferenceFQN") != null)
|
||||
linker.AddSerializedClass(writeResult.Value.GetType().GetProperty("includedSerializeReferenceFQN").GetValue(writeResult.Value) as System.Collections.Generic.IEnumerable<string>);
|
||||
#endif
|
||||
}
|
||||
|
||||
var linkPath = m_Parameters.GetOutputFilePathForIdentifier(k_LinkXml);
|
||||
linker.Save(linkPath);
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f39ee2ccb61c17549b2f6551af68ab88
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,67 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Pipeline.WriteTypes;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates sub asset load information.
|
||||
/// </summary>
|
||||
public class GenerateSubAssetPathMaps : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext]
|
||||
IBundleWriteData m_WriteData;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildExtendedAssetData m_ExtendedAssetData;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (m_ExtendedAssetData == null || m_ExtendedAssetData.ExtendedData.IsNullOrEmpty())
|
||||
return ReturnCode.SuccessNotRun;
|
||||
|
||||
Dictionary<string, IWriteOperation> fileToOperation = m_WriteData.WriteOperations.ToDictionary(x => x.Command.internalName, x => x);
|
||||
foreach (var pair in m_ExtendedAssetData.ExtendedData)
|
||||
{
|
||||
GUID asset = pair.Key;
|
||||
string mainFile = m_WriteData.AssetToFiles[asset][0];
|
||||
var abOp = fileToOperation[mainFile] as AssetBundleWriteOperation;
|
||||
|
||||
int assetInfoIndex = abOp.Info.bundleAssets.FindIndex(x => x.asset == asset);
|
||||
AssetLoadInfo assetInfo = abOp.Info.bundleAssets[assetInfoIndex];
|
||||
int offset = 1;
|
||||
foreach (var subAsset in pair.Value.Representations)
|
||||
{
|
||||
var secondaryAssetInfo = CreateSubAssetLoadInfo(assetInfo, subAsset);
|
||||
abOp.Info.bundleAssets.Insert(assetInfoIndex + offset, secondaryAssetInfo);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
static AssetLoadInfo CreateSubAssetLoadInfo(AssetLoadInfo assetInfo, ObjectIdentifier subAsset)
|
||||
{
|
||||
var subAssetLoadInfo = new AssetLoadInfo();
|
||||
subAssetLoadInfo.asset = assetInfo.asset;
|
||||
subAssetLoadInfo.address = assetInfo.address;
|
||||
subAssetLoadInfo.referencedObjects = new List<ObjectIdentifier>(assetInfo.referencedObjects);
|
||||
subAssetLoadInfo.includedObjects = new List<ObjectIdentifier>(assetInfo.includedObjects);
|
||||
|
||||
var index = subAssetLoadInfo.includedObjects.IndexOf(subAsset);
|
||||
subAssetLoadInfo.includedObjects.Swap(0, index);
|
||||
return subAssetLoadInfo;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa9edcd7497f45242bddd18f8e0582d4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,31 @@
|
|||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes all callbacks after the dependency calculation task.
|
||||
/// </summary>
|
||||
public class PostDependencyCallback : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDependencyCallback m_Callback;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
return m_Callback.PostDependency(m_Parameters, m_DependencyData);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 225da2e71801378408ef9f717020c323
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,34 @@
|
|||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes all callbacks after the bundle packing task.
|
||||
/// </summary>
|
||||
public class PostPackingCallback : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext]
|
||||
IWriteData m_WriteData;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IPackingCallback m_Callback;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
return m_Callback.PostPacking(m_Parameters, m_DependencyData, m_WriteData);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1f0e09841d3888f46a1a3f84af21a639
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,31 @@
|
|||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes all callbacks after the script building task.
|
||||
/// </summary>
|
||||
public class PostScriptsCallback : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext]
|
||||
IBuildResults m_Results;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IScriptsCallback m_Callback;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
return m_Callback.PostScripts(m_Parameters, m_Results);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3ed24626228f71246a5f32ebe0fb61e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,37 @@
|
|||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes all callbacks after the writing task.
|
||||
/// </summary>
|
||||
public class PostWritingCallback : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext]
|
||||
IWriteData m_WriteData;
|
||||
|
||||
[InjectContext]
|
||||
IBuildResults m_Results;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IWritingCallback m_Callback;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
return m_Callback.PostWriting(m_Parameters, m_DependencyData, m_WriteData, m_Results);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0f2109e178c64897a911d0c8471401d7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,126 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates scene dependency data and stores it in the cache.
|
||||
/// </summary>
|
||||
public class PreviewSceneDependencyData : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildContent m_Content;
|
||||
|
||||
[InjectContext]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IProgressTracker m_Tracker;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildCache m_Cache;
|
||||
#pragma warning restore 649
|
||||
|
||||
CachedInfo GetCachedInfo(GUID scene, IEnumerable<ObjectIdentifier> references, SceneDependencyInfo sceneInfo, BuildUsageTagSet usageTags)
|
||||
{
|
||||
var info = new CachedInfo();
|
||||
info.Asset = m_Cache.GetCacheEntry(scene, Version);
|
||||
|
||||
var dependencies = new HashSet<CacheEntry>();
|
||||
foreach (ObjectIdentifier reference in references)
|
||||
dependencies.Add(m_Cache.GetCacheEntry(reference));
|
||||
info.Dependencies = dependencies.ToArray();
|
||||
|
||||
info.Data = new object[] { sceneInfo, usageTags };
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
IList<CachedInfo> cachedInfo = null;
|
||||
IList<CachedInfo> uncachedInfo = null;
|
||||
if (m_Parameters.UseCache && m_Cache != null)
|
||||
{
|
||||
IList<CacheEntry> entries = m_Content.Scenes.Select(x => m_Cache.GetCacheEntry(x, Version)).ToList();
|
||||
m_Cache.LoadCachedData(entries, out cachedInfo);
|
||||
|
||||
uncachedInfo = new List<CachedInfo>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_Content.Scenes.Count; i++)
|
||||
{
|
||||
GUID scene = m_Content.Scenes[i];
|
||||
string scenePath = AssetDatabase.GUIDToAssetPath(scene.ToString());
|
||||
|
||||
SceneDependencyInfo sceneInfo;
|
||||
BuildUsageTagSet usageTags;
|
||||
|
||||
if (cachedInfo != null && cachedInfo[i] != null)
|
||||
{
|
||||
if (!m_Tracker.UpdateInfoUnchecked(string.Format("{0} (Cached)", scenePath)))
|
||||
return ReturnCode.Canceled;
|
||||
|
||||
sceneInfo = (SceneDependencyInfo)cachedInfo[i].Data[0];
|
||||
usageTags = cachedInfo[i].Data[1] as BuildUsageTagSet;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_Tracker.UpdateInfoUnchecked(scenePath))
|
||||
return ReturnCode.Canceled;
|
||||
|
||||
var references = new HashSet<ObjectIdentifier>();
|
||||
string[] dependencies = AssetDatabase.GetDependencies(scenePath);
|
||||
foreach (var assetPath in dependencies)
|
||||
{
|
||||
var assetGuid = new GUID(AssetDatabase.AssetPathToGUID(assetPath));
|
||||
if (ValidationMethods.ValidAsset(assetGuid) != ValidationMethods.Status.Asset)
|
||||
continue;
|
||||
|
||||
// TODO: Use Cache to speed this up?
|
||||
var assetIncludes = ContentBuildInterface.GetPlayerObjectIdentifiersInAsset(assetGuid, m_Parameters.Target);
|
||||
var assetReferences = ContentBuildInterface.GetPlayerDependenciesForObjects(assetIncludes, m_Parameters.Target, m_Parameters.ScriptInfo);
|
||||
references.UnionWith(assetIncludes);
|
||||
references.UnionWith(assetReferences);
|
||||
}
|
||||
|
||||
sceneInfo = new SceneDependencyInfo();
|
||||
usageTags = new BuildUsageTagSet();
|
||||
|
||||
sceneInfo.SetScene(scenePath);
|
||||
sceneInfo.SetProcessedScene(scenePath);
|
||||
sceneInfo.SetReferencedObjects(references.ToArray());
|
||||
|
||||
if (uncachedInfo != null)
|
||||
uncachedInfo.Add(GetCachedInfo(scene, sceneInfo.referencedObjects, sceneInfo, usageTags));
|
||||
}
|
||||
|
||||
SetOutputInformation(scene, sceneInfo, usageTags);
|
||||
}
|
||||
|
||||
if (m_Parameters.UseCache && m_Cache != null)
|
||||
m_Cache.SaveCachedData(uncachedInfo);
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
void SetOutputInformation(GUID asset, SceneDependencyInfo sceneInfo, BuildUsageTagSet usageTags)
|
||||
{
|
||||
// Add generated scene information to BuildDependencyData
|
||||
m_DependencyData.SceneInfo.Add(asset, sceneInfo);
|
||||
m_DependencyData.SceneUsage.Add(asset, usageTags);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 46ff9bb9c11e4daa9d9424fa410fcc30
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,32 @@
|
|||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Sprites;
|
||||
using UnityEditor.U2D;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds the cache data for all sprite atlases.
|
||||
/// </summary>
|
||||
public class RebuildSpriteAtlasCache : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
// TODO: Need a return value if this ever can fail
|
||||
#if !UNITY_2020_1_OR_NEWER
|
||||
Packer.RebuildAtlasCacheIfNeeded(m_Parameters.Target, true, Packer.Execution.Normal);
|
||||
#endif
|
||||
SpriteAtlasUtility.PackAllAtlases(m_Parameters.Target);
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 49d4a1540f2adfc418fd2e5dd536420b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,72 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Removes all unusued sprite source data from asset references and scene references.
|
||||
/// </summary>
|
||||
public class StripUnusedSpriteSources : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 2; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildSpriteData m_SpriteData;
|
||||
|
||||
[InjectContext(ContextUsage.InOut, true)]
|
||||
IBuildExtendedAssetData m_ExtendedAssetData;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (m_SpriteData == null || m_SpriteData.ImporterData.Count == 0)
|
||||
return ReturnCode.SuccessNotRun;
|
||||
|
||||
if (EditorSettings.spritePackerMode == SpritePackerMode.Disabled)
|
||||
return ReturnCode.SuccessNotRun;
|
||||
|
||||
var unusedSources = new HashSet<ObjectIdentifier>();
|
||||
var textures = m_SpriteData.ImporterData.Values.Where(x => x.PackedSprite).Select(x => x.SourceTexture);
|
||||
unusedSources.UnionWith(textures);
|
||||
|
||||
// Count refs from assets
|
||||
var assetRefs = m_DependencyData.AssetInfo.SelectMany(x => x.Value.referencedObjects);
|
||||
foreach (ObjectIdentifier reference in assetRefs)
|
||||
unusedSources.Remove(reference);
|
||||
|
||||
// Count refs from scenes
|
||||
var sceneRefs = m_DependencyData.SceneInfo.SelectMany(x => x.Value.referencedObjects);
|
||||
foreach (ObjectIdentifier reference in sceneRefs)
|
||||
unusedSources.Remove(reference);
|
||||
|
||||
SetOutputInformation(unusedSources);
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
void SetOutputInformation(HashSet<ObjectIdentifier> unusedSources)
|
||||
{
|
||||
foreach (var source in unusedSources)
|
||||
{
|
||||
var assetInfo = m_DependencyData.AssetInfo[source.guid];
|
||||
assetInfo.includedObjects.RemoveAt(0);
|
||||
|
||||
ExtendedAssetData extendedData;
|
||||
if (m_ExtendedAssetData != null && m_ExtendedAssetData.ExtendedData.TryGetValue(source.guid, out extendedData))
|
||||
{
|
||||
extendedData.Representations.Remove(source);
|
||||
if (extendedData.Representations.Count == 1)
|
||||
m_ExtendedAssetData.ExtendedData.Remove(source.guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: db8e822ddcadee542b625284a3d0aa16
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,35 @@
|
|||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the target build platform based on the build parameters.
|
||||
/// </summary>
|
||||
public class SwitchToBuildPlatform : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IEditorBuildCallbacks m_InterfaceWrapper;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (EditorUserBuildSettings.SwitchActiveBuildTarget(m_Parameters.Group, m_Parameters.Target))
|
||||
{
|
||||
if (m_InterfaceWrapper != null)
|
||||
m_InterfaceWrapper.InitializeCallbacks();
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
return ReturnCode.Error;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8195792273a50ed4982b1717d1203dbf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,143 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the layout for bundle objects.
|
||||
/// </summary>
|
||||
public class UpdateBundleObjectLayout : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBundleExplictObjectLayout m_Layout;
|
||||
|
||||
[InjectContext]
|
||||
IBundleBuildContent m_Content;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext]
|
||||
IBundleWriteData m_WriteData;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDeterministicIdentifiers m_PackingMethod;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildLogger m_Log;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (m_Layout == null || m_Layout.ExplicitObjectLocation.IsNullOrEmpty())
|
||||
return ReturnCode.SuccessNotRun;
|
||||
|
||||
var ObjectToAssetReferences = new Dictionary<ObjectIdentifier, List<GUID>>();
|
||||
var ObjectToFiles = new Dictionary<ObjectIdentifier, List<string>>();
|
||||
|
||||
using (m_Log.ScopedStep(LogLevel.Info, "PopulateReferencesMaps", true))
|
||||
{
|
||||
var task = Task.Run(() =>
|
||||
{
|
||||
using (m_Log.ScopedStep(LogLevel.Info, "Populate Assets Map", $"Count={m_DependencyData.AssetInfo.Count}"))
|
||||
{
|
||||
foreach (KeyValuePair<GUID, AssetLoadInfo> dependencyPair in m_DependencyData.AssetInfo)
|
||||
{
|
||||
PopulateReferencesMap(dependencyPair.Key, dependencyPair.Value.includedObjects, ObjectToAssetReferences);
|
||||
PopulateReferencesMap(dependencyPair.Key, dependencyPair.Value.referencedObjects, ObjectToAssetReferences);
|
||||
}
|
||||
}
|
||||
using (m_Log.ScopedStep(LogLevel.Info, "Populate Scenes Map", $"Count={m_DependencyData.SceneInfo.Count}"))
|
||||
{
|
||||
foreach (KeyValuePair<GUID, SceneDependencyInfo> dependencyPair in m_DependencyData.SceneInfo)
|
||||
PopulateReferencesMap(dependencyPair.Key, dependencyPair.Value.referencedObjects, ObjectToAssetReferences);
|
||||
}
|
||||
});
|
||||
|
||||
using (m_Log.ScopedStep(LogLevel.Info, "Populate Files Map", $"Count={m_WriteData.FileToObjects.Count}"))
|
||||
{
|
||||
foreach (KeyValuePair<string, List<ObjectIdentifier>> filePair in m_WriteData.FileToObjects)
|
||||
PopulateReferencesMap(filePair.Key, filePair.Value, ObjectToFiles);
|
||||
}
|
||||
task.Wait();
|
||||
}
|
||||
|
||||
using (m_Log.ScopedStep(LogLevel.Info, "UpdateWriteData"))
|
||||
{
|
||||
foreach (var group in m_Layout.ExplicitObjectLocation.GroupBy(s => s.Value))
|
||||
{
|
||||
IEnumerable<ObjectIdentifier> objectIDs = group.Select(s => s.Key);
|
||||
string bundleName = group.Key;
|
||||
string internalName = string.Format(CommonStrings.AssetBundleNameFormat, m_PackingMethod.GenerateInternalFileName(bundleName));
|
||||
|
||||
foreach (var objectID in objectIDs)
|
||||
{
|
||||
UpdateAssetToFilesMap(internalName, ObjectToAssetReferences[objectID], m_WriteData.AssetToFiles);
|
||||
RemoveObjectIDFromFiles(objectID, ObjectToFiles[objectID], m_WriteData.FileToObjects);
|
||||
}
|
||||
|
||||
// Add new mapping for File to Bundle
|
||||
UpdateFileToBundleMap(bundleName, internalName, m_WriteData.FileToBundle, m_Content.BundleLayout);
|
||||
|
||||
// Update File to Object map
|
||||
UpdateFileToObjectMap(internalName, objectIDs, m_WriteData.FileToObjects);
|
||||
}
|
||||
}
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
internal static void PopulateReferencesMap<T>(T key, IList<ObjectIdentifier> objects, Dictionary<ObjectIdentifier, List<T>> map)
|
||||
{
|
||||
foreach (var obj in objects)
|
||||
{
|
||||
map.GetOrAdd(obj, out var set);
|
||||
set.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void UpdateAssetToFilesMap(string file, List<GUID> assetsToUpdate, Dictionary<GUID, List<string>> AssetToFiles)
|
||||
{
|
||||
foreach (var asset in assetsToUpdate)
|
||||
{
|
||||
var assetFiles = AssetToFiles[asset];
|
||||
if (!assetFiles.Contains(file))
|
||||
assetFiles.Add(file);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RemoveObjectIDFromFiles(ObjectIdentifier objectID, List<string> files, Dictionary<string, List<ObjectIdentifier>> FileToObjects)
|
||||
{
|
||||
foreach (var file in files)
|
||||
FileToObjects[file].Remove(objectID);
|
||||
}
|
||||
|
||||
internal static void UpdateFileToBundleMap(string bundleName, string file, Dictionary<string, string> FileToBundle, Dictionary<string, List<GUID>> BundleLayout)
|
||||
{
|
||||
if (!FileToBundle.ContainsKey(file))
|
||||
{
|
||||
FileToBundle.Add(file, bundleName);
|
||||
// NOTE: We want the output result to know about the new bundle, but since we are only
|
||||
// assigning individual objects to this bundle and not full assets, the asset list will be empty
|
||||
BundleLayout.Add(bundleName, new List<GUID>());
|
||||
}
|
||||
}
|
||||
|
||||
internal static void UpdateFileToObjectMap(string file, IEnumerable<ObjectIdentifier> newObjectIDs, Dictionary<string, List<ObjectIdentifier>> FileToObjects)
|
||||
{
|
||||
// This is called after remove, thus we can just AddRange as we already know these objects are not in any file
|
||||
FileToObjects.GetOrAdd(file, out var objectIDs);
|
||||
objectIDs.AddRange(newObjectIDs);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 69a3d9bdf64896044a9fdb61df07a1f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,205 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEngine;
|
||||
using static UnityEditor.Build.Pipeline.Utilities.TaskCachingUtility;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializes all cache data.
|
||||
/// </summary>
|
||||
public class WriteSerializedFiles : IBuildTask, IRunCachedCallbacks<WriteSerializedFiles.Item>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 4; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IDependencyData m_DependencyData;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IWriteData m_WriteData;
|
||||
|
||||
[InjectContext]
|
||||
IBuildResults m_Results;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IProgressTracker m_Tracker;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildCache m_Cache;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildLogger m_Log;
|
||||
#pragma warning restore 649
|
||||
|
||||
static Hash128 GetPlayerSettingsHash128(BuildTarget target)
|
||||
{
|
||||
return HashingMethods.Calculate(
|
||||
PlayerSettings.stripUnusedMeshComponents,
|
||||
PlayerSettings.bakeCollisionMeshes
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
, PlayerSettings.mipStripping ? PlayerSettingsApi.GetNumberOfMipsStripped() : 0
|
||||
#endif
|
||||
, PlayerSettings.GetGraphicsAPIs(target)
|
||||
).ToHash128();
|
||||
}
|
||||
|
||||
CacheEntry GetCacheEntry(IWriteOperation operation, BuildSettings settings, BuildUsageTagGlobal globalUsage, bool onlySaveFirstSerializedObject)
|
||||
{
|
||||
using (m_Log.ScopedStep(LogLevel.Verbose, "GetCacheEntry", operation.Command.fileName))
|
||||
{
|
||||
var entry = new CacheEntry();
|
||||
entry.Type = CacheEntry.EntryType.Data;
|
||||
entry.Guid = HashingMethods.Calculate("WriteSerializedFiles", operation.Command.fileName).ToGUID();
|
||||
entry.Hash = HashingMethods.Calculate(Version, operation.GetHash128(m_Log), settings.GetHash128(), globalUsage, onlySaveFirstSerializedObject, GetPlayerSettingsHash128(settings.target)).ToHash128();
|
||||
entry.Version = Version;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
static void SlimifySerializedObjects(ref WriteResult result)
|
||||
{
|
||||
var fileOffsets = new List<ObjectSerializedInfo>();
|
||||
foreach (ResourceFile serializedFile in result.resourceFiles)
|
||||
{
|
||||
if (!serializedFile.serializedFile)
|
||||
continue;
|
||||
fileOffsets.Add(result.serializedObjects.First(x => x.header.fileName == serializedFile.fileAlias));
|
||||
}
|
||||
|
||||
result.SetSerializedObjects(fileOffsets.ToArray());
|
||||
}
|
||||
|
||||
CachedInfo GetCachedInfo(CacheEntry entry, WriteResult result, SerializedFileMetaData metaData)
|
||||
{
|
||||
var info = new CachedInfo();
|
||||
info.Asset = entry;
|
||||
info.Data = new object[] { result, metaData };
|
||||
info.Dependencies = new CacheEntry[0];
|
||||
return info;
|
||||
}
|
||||
|
||||
class Item
|
||||
{
|
||||
public WriteResult Result;
|
||||
public SerializedFileMetaData MetaData;
|
||||
}
|
||||
|
||||
BuildSettings m_BuildSettings;
|
||||
BuildUsageTagGlobal m_GlobalUsage;
|
||||
IBuildCache m_UseCache;
|
||||
|
||||
internal void SetupTaskContext()
|
||||
{
|
||||
m_GlobalUsage = m_DependencyData.GlobalUsage;
|
||||
foreach (var sceneInfo in m_DependencyData.SceneInfo)
|
||||
m_GlobalUsage |= sceneInfo.Value.globalUsage;
|
||||
|
||||
m_BuildSettings = m_Parameters.GetContentBuildSettings();
|
||||
m_UseCache = m_Parameters.UseCache ? m_Cache : null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
SetupTaskContext();
|
||||
|
||||
List<WorkItem<Item>> workItems = m_WriteData.WriteOperations.Select(
|
||||
i => new WorkItem<Item>(new Item(), i.Command.internalName)
|
||||
).ToList();
|
||||
|
||||
return TaskCachingUtility.RunCachedOperation<Item>(
|
||||
m_UseCache,
|
||||
m_Log,
|
||||
m_Tracker,
|
||||
workItems,
|
||||
this);
|
||||
}
|
||||
|
||||
internal static SerializedFileMetaData CalculateFileMetadata(ref WriteResult result)
|
||||
{
|
||||
List<RawHash> contentHashObjects = new List<RawHash>();
|
||||
List<RawHash> fullHashObjects = new List<RawHash>();
|
||||
foreach (ResourceFile file in result.resourceFiles)
|
||||
{
|
||||
RawHash fileHash = HashingMethods.CalculateFile(file.fileName);
|
||||
RawHash contentHash = fileHash;
|
||||
fullHashObjects.Add(fileHash);
|
||||
if (file.serializedFile && result.serializedObjects.Count > 0)
|
||||
{
|
||||
ObjectSerializedInfo firstObj = result.serializedObjects.First(x => x.header.fileName == file.fileAlias);
|
||||
using (var stream = new FileStream(file.fileName, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
stream.Position = (long)firstObj.header.offset;
|
||||
contentHash = HashingMethods.CalculateStream(stream);
|
||||
}
|
||||
}
|
||||
contentHashObjects.Add(contentHash);
|
||||
}
|
||||
SerializedFileMetaData data = new SerializedFileMetaData();
|
||||
data.RawFileHash = HashingMethods.Calculate(fullHashObjects).ToHash128();
|
||||
data.ContentHash = HashingMethods.Calculate(contentHashObjects).ToHash128();
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
CacheEntry IRunCachedCallbacks<Item>.CreateCacheEntry(WorkItem<Item> item)
|
||||
{
|
||||
return GetCacheEntry(m_WriteData.WriteOperations[item.Index], m_BuildSettings, m_GlobalUsage, ScriptableBuildPipeline.slimWriteResults);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IRunCachedCallbacks<Item>.ProcessUncached(WorkItem<Item> item)
|
||||
{
|
||||
IWriteOperation op = m_WriteData.WriteOperations[item.Index];
|
||||
|
||||
string targetDir = m_UseCache != null ? m_UseCache.GetCachedArtifactsDirectory(item.entry) : m_Parameters.TempOutputFolder;
|
||||
Directory.CreateDirectory(targetDir);
|
||||
|
||||
using (m_Log.ScopedStep(LogLevel.Info, $"Writing {op.GetType().Name}", op.Command.fileName))
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER || ENABLE_DETAILED_PROFILE_CAPTURING
|
||||
using (new ProfileCaptureScope(m_Log, ProfileCaptureOptions.None))
|
||||
item.Context.Result = op.Write(targetDir, m_BuildSettings, m_GlobalUsage);
|
||||
#else
|
||||
item.Context.Result = op.Write(targetDir, m_BuildSettings, m_GlobalUsage);
|
||||
#endif
|
||||
}
|
||||
|
||||
item.Context.MetaData = CalculateFileMetadata(ref item.Context.Result);
|
||||
|
||||
if (ScriptableBuildPipeline.slimWriteResults)
|
||||
SlimifySerializedObjects(ref item.Context.Result);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IRunCachedCallbacks<Item>.ProcessCached(WorkItem<Item> item, CachedInfo info)
|
||||
{
|
||||
item.Context.Result = (WriteResult)info.Data[0];
|
||||
item.Context.MetaData = (SerializedFileMetaData)info.Data[1];
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IRunCachedCallbacks<Item>.PostProcess(WorkItem<Item> item)
|
||||
{
|
||||
IWriteOperation op = m_WriteData.WriteOperations[item.Index];
|
||||
m_Results.WriteResults.Add(op.Command.internalName, item.Context.Result);
|
||||
m_Results.WriteResultsMetaData.Add(op.Command.internalName, item.Context.MetaData);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
CachedInfo IRunCachedCallbacks<Item>.CreateCachedInfo(WorkItem<Item> item)
|
||||
{
|
||||
return GetCachedInfo(item.entry, item.Context.Result, item.Context.MetaData);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4d29a4991c6c8884aa7a81dc6d2e1cc5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue