ZoeAppClass/Library/PackageCache/com.unity.scriptablebuildpi.../Editor/Tasks/ArchiveAndCompressBundles.cs

203 lines
8.5 KiB
C#

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 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
public class ArchiveAndCompressBundles : IBuildTask
{
public int Version { get { return 1; } }
#pragma warning disable 649
[InjectContext(ContextUsage.In)]
IBuildParameters m_Parameters;
[InjectContext(ContextUsage.In)]
IBundleWriteData m_WriteData;
[InjectContext]
IBundleBuildResults m_Results;
[InjectContext(ContextUsage.In, true)]
IProgressTracker m_Tracker;
[InjectContext(ContextUsage.In, true)]
IBuildCache m_Cache;
#pragma warning restore 649
CacheEntry GetCacheEntry(string bundleName, IEnumerable<ResourceFile> resources, BuildCompression compression)
{
var entry = new CacheEntry();
entry.Type = CacheEntry.EntryType.Data;
entry.Guid = HashingMethods.Calculate("ArchiveAndCompressBundles", bundleName).ToGUID();
entry.Hash = HashingMethods.Calculate(Version, resources, compression).ToHash128();
entry.Version = Version;
return entry;
}
static CachedInfo GetCachedInfo(IBuildCache cache, CacheEntry entry, IEnumerable<ResourceFile> resources, BundleDetails details)
{
var info = new CachedInfo();
info.Asset = entry;
var dependencies = new HashSet<CacheEntry>();
foreach (var resource in resources)
dependencies.Add(cache.GetCacheEntry(resource.fileName));
info.Dependencies = dependencies.ToArray();
info.Data = new object[] { details };
return info;
}
static Hash128 CalculateHashVersion(Dictionary<string, ulong> fileOffsets, ResourceFile[] resourceFiles)
{
List<RawHash> hashes = new List<RawHash>();
foreach (ResourceFile file in resourceFiles)
{
if (file.serializedFile)
{
// For serialized files, we ignore the header for the hash value.
// This leaves us with a hash value of just the written object data.
using (var stream = new FileStream(file.fileName, FileMode.Open, FileAccess.Read))
{
stream.Position = (long)fileOffsets[file.fileName];
hashes.Add(HashingMethods.CalculateStream(stream));
}
}
else
hashes.Add(HashingMethods.CalculateFile(file.fileName));
}
return HashingMethods.Calculate(hashes).ToHash128();
}
public ReturnCode Run()
{
Dictionary<string, ulong> fileOffsets = new Dictionary<string, ulong>();
List<KeyValuePair<string, List<ResourceFile>>> bundleResources;
{
Dictionary<string, List<ResourceFile>> bundleToResources = new Dictionary<string, List<ResourceFile>>();
foreach (var pair in m_Results.WriteResults)
{
string bundle = m_WriteData.FileToBundle[pair.Key];
List<ResourceFile> resourceFiles;
bundleToResources.GetOrAdd(bundle, out resourceFiles);
resourceFiles.AddRange(pair.Value.resourceFiles);
foreach (ResourceFile serializedFile in pair.Value.resourceFiles)
{
if (!serializedFile.serializedFile)
continue;
ObjectSerializedInfo firstObject = pair.Value.serializedObjects.First(x => x.header.fileName == serializedFile.fileAlias);
fileOffsets[serializedFile.fileName] = firstObject.header.offset;
}
}
bundleResources = bundleToResources.ToList();
}
Dictionary<string, HashSet<string>> bundleDependencies = new Dictionary<string, HashSet<string>>();
foreach (var files in m_WriteData.AssetToFiles.Values)
{
if (files.IsNullOrEmpty())
continue;
string bundle = m_WriteData.FileToBundle[files.First()];
HashSet<string> dependencies;
bundleDependencies.GetOrAdd(bundle, out dependencies);
dependencies.UnionWith(files.Select(x => m_WriteData.FileToBundle[x]));
dependencies.Remove(bundle);
}
IList<CacheEntry> entries = bundleResources.Select(x => GetCacheEntry(x.Key, x.Value, m_Parameters.GetCompressionForIdentifier(x.Key))).ToList();
IList<CachedInfo> cachedInfo = null;
IList<CachedInfo> uncachedInfo = null;
if (m_Parameters.UseCache && m_Cache != null)
{
m_Cache.LoadCachedData(entries, out cachedInfo);
uncachedInfo = new List<CachedInfo>();
}
for (int i = 0; i < bundleResources.Count; i++)
{
string bundleName = bundleResources[i].Key;
ResourceFile[] resourceFiles = bundleResources[i].Value.ToArray();
BuildCompression compression = m_Parameters.GetCompressionForIdentifier(bundleName);
string writePath;
BundleDetails details;
if (cachedInfo != null && cachedInfo[i] != null)
{
if (!m_Tracker.UpdateInfoUnchecked(string.Format("{0} (Cached)", bundleName)))
return ReturnCode.Canceled;
details = (BundleDetails)cachedInfo[i].Data[0];
details.FileName = m_Parameters.GetOutputFilePathForIdentifier(bundleName);
HashSet<string> dependencies;
if (bundleDependencies.TryGetValue(bundleName, out dependencies))
details.Dependencies = dependencies.ToArray();
else
details.Dependencies = new string[0];
writePath = string.Format("{0}/{1}", m_Cache.GetCachedArtifactsDirectory(entries[i]), bundleName);
}
else
{
if (!m_Tracker.UpdateInfoUnchecked(bundleName))
return ReturnCode.Canceled;
details = new BundleDetails();
writePath = string.Format("{0}/{1}", m_Parameters.TempOutputFolder, bundleName);
if (m_Parameters.UseCache && m_Cache != null)
writePath = string.Format("{0}/{1}", m_Cache.GetCachedArtifactsDirectory(entries[i]), bundleName);
Directory.CreateDirectory(Path.GetDirectoryName(writePath));
details.FileName = m_Parameters.GetOutputFilePathForIdentifier(bundleName);
details.Crc = ContentBuildInterface.ArchiveAndCompress(resourceFiles, writePath, compression);
details.Hash = CalculateHashVersion(fileOffsets, resourceFiles);
HashSet<string> dependencies;
if (bundleDependencies.TryGetValue(bundleName, out dependencies))
details.Dependencies = dependencies.ToArray();
else
details.Dependencies = new string[0];
if (uncachedInfo != null)
uncachedInfo.Add(GetCachedInfo(m_Cache, entries[i], resourceFiles, details));
}
SetOutputInformation(writePath, details.FileName, bundleName, details);
}
if (m_Parameters.UseCache && m_Cache != null)
m_Cache.SaveCachedData(uncachedInfo);
return ReturnCode.Success;
}
void SetOutputInformation(string writePath, string finalPath, string bundleName, BundleDetails details)
{
if (finalPath != writePath)
{
var directory = Path.GetDirectoryName(finalPath);
Directory.CreateDirectory(directory);
File.Copy(writePath, finalPath, true);
}
m_Results.BundleInfos.Add(bundleName, details);
}
}
}