void DumpToText.ICustomDumper.CustomDumper(DumpToText dumpToText, object value) { BuildUsageTagSet buildUsageTagSet = (BuildUsageTagSet)value; ObjectIdentifier[] objectIdentifiers = buildUsageTagSet.GetObjectIdentifiers(); dumpToText.Indent(); if (objectIdentifiers != null) { dumpToText.Add("ObjectIdentifier[]", "objectIdentifiers", $"ObjectIdentifier[{objectIdentifiers.Length}]"); dumpToText.Indent(); for (int objectIdentifierIndex = 0; objectIdentifierIndex < objectIdentifiers.Length; objectIdentifierIndex++) { dumpToText.Add("ObjectIdentifier", $"[{objectIdentifierIndex}]"); dumpToText.Indent(); dumpToText.Dump("ObjectIdentifier", objectIdentifiers[objectIdentifierIndex]); dumpToText.Undent(); } dumpToText.Undent(); } else { dumpToText.Add("ObjectIdentifier[]", "objectIdentifiers", "null"); } dumpToText.Undent(); }
public void OneTimeSetUp() { WriteOperations = new IWriteOperation[5]; WriteOperations[0] = new AssetBundleWriteOperation(); #pragma warning disable CS0618 // Type or member is obsolete WriteOperations[1] = new RawWriteOperation(); #pragma warning restore CS0618 // Type or member is obsolete WriteOperations[2] = new SceneBundleWriteOperation(); WriteOperations[3] = new SceneDataWriteOperation(); #pragma warning disable CS0618 // Type or member is obsolete WriteOperations[4] = new SceneRawWriteOperation(); #pragma warning restore CS0618 // Type or member is obsolete var command = new WriteCommand { fileName = GUID.Generate().ToString(), internalName = GUID.Generate().ToString() }; var usageSet = new BuildUsageTagSet(); var referenceMap = new BuildReferenceMap(); for (int i = 0; i < WriteOperations.Length; i++) { WriteOperations[i].Command = command; WriteOperations[i].UsageSet = usageSet; WriteOperations[i].ReferenceMap = referenceMap; } }
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 <KeyValuePair <ObjectIdentifier, Type[]> >)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 CreateSceneBundleCommand(string bundleName, string internalName, GUID scene, List <GUID> bundledScenes, Dictionary <GUID, string> assetToMainFile) { var fileObjects = m_WriteData.FileToObjects[internalName]; #if !UNITY_2019_1_OR_NEWER // 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. fileObjects = GetSortedSceneObjectIdentifiers(fileObjects); #endif 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); }
private void WriteSerialziedFiles(string bundleName, IWriteOperation op, List <WriteCommand> allCommands, BuildSettings settings, BuildUsageTagGlobal globalUsage, ref List <WriteResult> outResults) { WriteResult result; var dependencies = op.CalculateDependencies(allCommands); var objectIDs = op.command.serializeObjects.Select(x => x.serializationObject).ToArray(); var dependentIDs = dependencies.SelectMany(x => x.serializeObjects.Select(y => y.serializationObject)).ToArray(); BuildUsageTagSet buildUsage = new BuildUsageTagSet(); BundleBuildInterface.CalculateBuildUsageTags(objectIDs, dependentIDs, globalUsage, buildUsage); Hash128 hash = CalculateInputHash(op, dependencies, settings, globalUsage, buildUsage); if (UseCache && BuildCache.TryLoadCachedResults(hash, out result)) { outResults.Add(result); return; } result = op.Write(GetBuildPath(hash), dependencies, settings, globalUsage, buildUsage); outResults.Add(result); if (UseCache && !BuildCache.SaveCachedResults(hash, result)) { BuildLogger.LogWarning("Unable to cache CommandSetWriter results for command '{0}'.", op.command.internalName); } }
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); }
public void CreateAssetEntryForObjectIdentifiers(ObjectIdentifier[] includedObjects, string path, string bundleName, string address, Type mainAssetType) { AssetLoadInfo assetInfo = new AssetLoadInfo(); BuildUsageTagSet usageTags = new BuildUsageTagSet(); assetInfo.asset = HashingMethods.Calculate(address).ToGUID(); 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)); } assetInfo.includedObjects = new List <ObjectIdentifier>(includedObjects); var referencedObjects = ContentBuildInterface.GetPlayerDependenciesForObjects(includedObjects, m_Parameters.Target, m_Parameters.ScriptInfo); assetInfo.referencedObjects = new List <ObjectIdentifier>(referencedObjects); ContentBuildInterface.CalculateBuildUsageTags(referencedObjects, includedObjects, m_GlobalUsage, usageTags, m_DependencyData.DependencyUsageCache); List <GUID> assets; m_Content.BundleLayout.GetOrAdd(bundleName, out assets); assets.Add(assetInfo.asset); m_Content.Addresses[assetInfo.asset] = address; m_Content.FakeAssets[assetInfo.asset] = path; SetOutputInformation(assetInfo.asset, assetInfo, usageTags); }
public SceneDataWriteOperation(SceneDataWriteOperation other) : base(other) { // Notes: May want to switch to MemberwiseClone, for now those this is fine scene = other.scene; processedScene = other.processedScene; preloadInfo = other.preloadInfo; usageTags = other.usageTags; }
void ICustomSerializer.USerializer(Serializer serializer, object value) { BuildUsageTagSet buildUsageTagSet = (BuildUsageTagSet)value; if (serializer.WriteNullFlag(buildUsageTagSet)) #if UNITY_2019_4_OR_NEWER { serializer.WriteBytes(buildUsageTagSet.SerializeToBinary()); } #else { serializer.WriteBytes((byte[])m_SerializeToBinary.Invoke(buildUsageTagSet, null)); } #endif }
void SetOutputInformation(GUID asset, AssetLoadInfo assetInfo, BuildUsageTagSet usageTags, SpriteImporterData importerData) { // Add generated asset information to IDependencyData m_DependencyData.AssetInfo.Add(asset, assetInfo); m_DependencyData.AssetUsage.Add(asset, usageTags); // Add generated importer data to IBuildSpriteData if (importerData != null) { m_SpriteData.ImporterData.Add(asset, importerData); } }
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); }
/// <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 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); }
static BuildUsageTagSet CreateSyntheticBuildUsageTagSet() { // JSON for a BuildUsageTagSet instance. There is no API to create this programatically so this was captured from a real project to be used in these tests string buildUsageTagSetJsonData = "{\"m_objToUsage\":[{\"first\":{\"filePath\":\"\",\"fileType\":3,\"guid\":\"822642a2b47082c49966f0c54db535a4\",\"localIdentifierInFile\":-7728386467694932768},\"second\":{\"forceTextureReadable\":false,\"maxBonesPerVertex\":4,\"meshSupportedChannels\":12799,\"meshUsageFlags\":1,\"shaderIncludeInstancingVariants\":false,\"shaderUsageKeywordNames\":[],\"strippedPrefabObject\":false}},{\"first\":{\"filePath\":\"\",\"fileType\":3,\"guid\":\"90b695013db7b334cbcf925848031399\",\"localIdentifierInFile\":-1848259448780025149},\"second\":{\"forceTextureReadable\":false,\"maxBonesPerVertex\":0,\"meshSupportedChannels\":383,\"meshUsageFlags\":0,\"shaderIncludeInstancingVariants\":false,\"shaderUsageKeywordNames\":[],\"strippedPrefabObject\":false}},{\"first\":{\"filePath\":\"\",\"fileType\":3,\"guid\":\"db9aadf200fd84e4591cc30ea4d1358c\",\"localIdentifierInFile\":3883874861523733925},\"second\":{\"forceTextureReadable\":false,\"maxBonesPerVertex\":0,\"meshSupportedChannels\":383,\"meshUsageFlags\":0,\"shaderIncludeInstancingVariants\":false,\"shaderUsageKeywordNames\":[],\"strippedPrefabObject\":false}}]}"; BuildUsageTagSet buildUsageTagSet = new BuildUsageTagSet(); #if UNITY_2019_4_OR_NEWER buildUsageTagSet.DeserializeFromJson(buildUsageTagSetJsonData); #else typeof(BuildUsageTagSet).GetMethod("DeserializeFromJson", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(buildUsageTagSet, new object[] { buildUsageTagSetJsonData }); #endif return(buildUsageTagSet); }
object ICustomSerializer.UDeSerializer(DeSerializer deserializer) { BuildUsageTagSet tagSet = null; if (deserializer.ReadNullFlag()) { tagSet = new BuildUsageTagSet(); byte[] bytes = deserializer.ReadBytes(); #if UNITY_2019_4_OR_NEWER tagSet.DeserializeFromBinary(bytes); #else m_DeserializeFromBinary.Invoke(tagSet, new object[] { bytes }); #endif } return(tagSet); }
CachedInfo GetCachedInfo(CacheEntry entry, AssetLoadInfo assetInfo, BuildUsageTagSet usageTags) { var info = new CachedInfo(); info.Asset = entry; var uniqueTypes = new HashSet <Type>(); var objectTypes = new List <KeyValuePair <ObjectIdentifier, Type[]> >(); 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); }
#pragma warning restore 649 CachedInfo GetCachedInfo(GUID asset, AssetLoadInfo assetInfo, BuildUsageTagSet usageTags, SpriteImporterData importerData) { var info = new CachedInfo(); info.Asset = m_Cache.GetCacheEntry(asset); var dependencies = new HashSet <CacheEntry>(); foreach (var reference in assetInfo.referencedObjects) { dependencies.Add(m_Cache.GetCacheEntry(reference)); } info.Dependencies = dependencies.ToArray(); info.Data = new object[] { assetInfo, usageTags, importerData }; return(info); }
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); }
void AddUsageSetForFiles(GUID asset, IList <string> files) { BuildUsageTagSet assetUsage; if (!m_DependencyData.AssetUsage.TryGetValue(asset, out assetUsage)) { if (!m_DependencyData.SceneUsage.TryGetValue(asset, out assetUsage)) { return; } } foreach (var file in files) { BuildUsageTagSet fileUsage; if (!m_WriteData.FileToUsageSet.TryGetValue(file, out fileUsage)) { fileUsage = new BuildUsageTagSet(); m_WriteData.FileToUsageSet.Add(file, fileUsage); } fileUsage.UnionWith(assetUsage); } }
public virtual WriteResult Write(string outputFolder, List <WriteCommand> dependencies, BuildSettings settings, BuildUsageTagGlobal globalUsage, BuildUsageTagSet buildUsage) { return(BundleBuildInterface.WriteSerializedFile(outputFolder, command, dependencies, settings, globalUsage, buildUsage)); }
private Hash128 CalculateInputHash(IWriteOperation operation, List <WriteCommand> dependencies, BuildSettings settings, BuildUsageTagGlobal globalUsage, BuildUsageTagSet buildUsage) { if (!UseCache) { return(new Hash128()); } var empty = new GUID(); var assets = new HashSet <GUID>(); var assetHashes = new List <Hash128>(); foreach (var objectId in operation.command.serializeObjects) { var guid = objectId.serializationObject.guid; if (guid == empty || !assets.Add(guid)) { continue; } var path = AssetDatabase.GUIDToAssetPath(guid.ToString()); assetHashes.Add(AssetDatabase.GetAssetDependencyHash(path)); } var sceneOp = operation as SceneDataWriteOperation; if (sceneOp != null) { assetHashes.Add(HashingMethods.CalculateFileMD5Hash(sceneOp.processedScene)); } return(HashingMethods.CalculateMD5Hash(Version, operation, assetHashes, dependencies, globalUsage, buildUsage, settings)); }
/// <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); }
#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() { 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 => m_Cache.GetCacheEntry(x, Version)).ToList(); m_Cache.LoadCachedData(entries, out cachedInfo); uncachedInfo = new List<CachedInfo>(); } BuildSettings settings = m_Parameters.GetContentBuildSettings(); 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; Hash128 prefabDependency = new Hash128(); 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; prefabDependency = (Hash128)cachedInfo[i].Data[2]; } else { if (!m_Tracker.UpdateInfoUnchecked(scenePath)) return ReturnCode.Canceled; usageTags = new BuildUsageTagSet(); #if UNITY_2019_3_OR_NEWER 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(m_Cache.GetCacheEntry(scene, Version)); 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 var prefabEntries = AssetDatabase.GetDependencies(AssetDatabase.GUIDToAssetPath(scene.ToString())).Where(path => path.EndsWith(".prefab")).Select(m_Cache.GetCacheEntry); prefabDependency = HashingMethods.Calculate(prefabEntries).ToHash128(); uncachedInfo.Add(GetCachedInfo(scene, sceneInfo.referencedObjects, sceneInfo, usageTags, prefabEntries, prefabDependency)); } } SetOutputInformation(scene, sceneInfo, usageTags, prefabDependency); } if (m_Parameters.UseCache && m_Cache != null) m_Cache.SaveCachedData(uncachedInfo); return ReturnCode.Success; }
public static void BuildSubSceneBundle(string manifestPath, string bundleName, string bundlePath, BuildTarget target, HashSet <Entities.Hash128> dependencies) { using (new BuildInterfacesWrapper()) { Directory.CreateDirectory(k_TempBuildPath); // Deterministic ID Generator var generator = new Unity5PackedIdentifiers(); // Target platform settings & script information var buildSettings = new BuildSettings { buildFlags = ContentBuildFlags.None, target = target, group = BuildPipeline.GetBuildTargetGroup(target), typeDB = null }; #if UNITY_2020_1_OR_NEWER // Collect all the objects we need for this asset & bundle (returned array order is deterministic) var manifestObjects = ContentBuildInterface.GetPlayerObjectIdentifiersInSerializedFile(manifestPath, buildSettings.target); #else var method = typeof(ContentBuildInterface).GetMethod("GetPlayerObjectIdentifiersInSerializedFile", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); // Collect all the objects we need for this asset & bundle (returned array order is deterministic) var manifestObjects = (ObjectIdentifier[])method.Invoke(null, new object[] { manifestPath, buildSettings.target }); #endif // Collect all the objects we need to reference for this asset (returned array order is deterministic) var manifestDependencies = ContentBuildInterface.GetPlayerDependenciesForObjects(manifestObjects, buildSettings.target, buildSettings.typeDB); // Scene / Project lighting information var globalUsage = ContentBuildInterface.GetGlobalUsageFromGraphicsSettings(); globalUsage = ForceKeepInstancingVariants(globalUsage); // Inter-asset feature usage (shader features, used mesh channels) var usageSet = new BuildUsageTagSet(); ContentBuildInterface.CalculateBuildUsageTags(manifestDependencies, manifestDependencies, globalUsage, usageSet); // TODO: Cache & Append to the assets that are influenced by this usageTagSet, ideally it would be a nice api to extract just the data for a given asset or object from the result // Bundle all the needed write parameters var writeParams = new WriteParameters { // Target platform settings & script information settings = buildSettings, // Scene / Project lighting information globalUsage = globalUsage, // Inter-asset feature usage (shader features, used mesh channels) usageSet = usageSet, // Serialized File Layout writeCommand = new WriteCommand { fileName = generator.GenerateInternalFileName(bundleName), internalName = generator.GenerateAssetBundleInternalFileName(bundleName), serializeObjects = new List <SerializationInfo>() // Populated Below }, // External object references referenceMap = new BuildReferenceMap(), // Populated Below // Asset Bundle object layout bundleInfo = new AssetBundleInfo { bundleName = bundleName, // What is loadable from this bundle bundleAssets = new List <AssetLoadInfo> { // The manifest object and it's dependencies new AssetLoadInfo { address = bundleName, asset = new GUID(), // TODO: Remove this as it is unused in C++ includedObjects = manifestObjects .ToList(), // TODO: In our effort to modernize the public API design we over complicated it trying to take List or return ReadOnlyLists. Should have just stuck with Arrays[] in all places referencedObjects = manifestDependencies.ToList() } } } }; // The requirement is that a single asset bundle only contains the ObjectManifest and the objects that are directly part of the asset, objects for external assets will be in their own bundles. IE: 1 asset per bundle layout // So this means we need to take manifestObjects & manifestDependencies and filter storing them into writeCommand.serializeObjects and/or referenceMap based on if they are this asset or other assets foreach (var obj in manifestObjects) { writeParams.writeCommand.serializeObjects.Add(new SerializationInfo { serializationObject = obj, serializationIndex = generator.SerializationIndexFromObjectIdentifier(obj) }); writeParams.referenceMap.AddMapping(writeParams.writeCommand.internalName, generator.SerializationIndexFromObjectIdentifier(obj), obj); } foreach (var obj in manifestDependencies) { // MonoScripts need to live beside the MonoBehavior (in this case ScriptableObject) and loaded first. We could move it to it's own bundle, but this is safer and it's a lightweight object var type = ContentBuildInterface.GetTypeForObject(obj); if (obj.guid == k_UnityBuiltinResources) { // For Builtin Resources, we can reference them directly // TODO: Once we switch to using GlobalObjectId for SBP, we will need a mapping for certain special cases of GUID <> FilePath for Builtin Resources writeParams.referenceMap.AddMapping(obj.filePath, obj.localIdentifierInFile, obj); } else if (type == typeof(MonoScript)) { writeParams.writeCommand.serializeObjects.Add(new SerializationInfo { serializationObject = obj, serializationIndex = generator.SerializationIndexFromObjectIdentifier(obj) }); writeParams.referenceMap.AddMapping(writeParams.writeCommand.internalName, generator.SerializationIndexFromObjectIdentifier(obj), obj); } else if (!obj.guid.Empty()) { writeParams.referenceMap.AddMapping( generator.GenerateAssetBundleInternalFileName(obj.guid.ToString()), generator.SerializationIndexFromObjectIdentifier(obj), obj); } // This will be solvable after we move SBP into the asset pipeline as importers. if (!obj.guid.Empty() && type != typeof(MonoScript)) { var convGUID = obj.guid; if (obj.guid == k_UnityBuiltinExtraResources) { PackBuiltinExtraWithFileIdent(ref convGUID, obj.localIdentifierInFile); } dependencies?.Add(convGUID); } } // Write the serialized file var result = ContentBuildInterface.WriteSerializedFile(k_TempBuildPath, writeParams); // Archive and compress the serialized & resource files for the previous operation var crc = ContentBuildInterface.ArchiveAndCompress(result.resourceFiles.ToArray(), bundlePath, UnityEngine.BuildCompression.Uncompressed); // Because the shader compiler progress bar hooks are absolute shit EditorUtility.ClearProgressBar(); //Debug.Log($"Wrote '{writeParams.writeCommand.fileName}' to '{k_TempBuildPath}/{writeParams.writeCommand.internalName}' resulting in {result.serializedObjects.Count} objects in the serialized file."); //Debug.Log($"Archived '{k_TempBuildPath}/{writeParams.writeCommand.internalName}' to '{cacheFilePath}' resulting in {crc} CRC."); Directory.Delete(k_TempBuildPath, true); } }
public static bool BuildSceneBundle(GUID sceneGuid, string cacheFilePath, BuildTarget target, bool collectDependencies = false, HashSet <Entities.Hash128> dependencies = null, HashSet <System.Type> types = null) { using (new BuildInterfacesWrapper()) using (new SceneStateCleanup()) { Directory.CreateDirectory(k_TempBuildPath); var scene = sceneGuid.ToString(); var scenePath = AssetDatabase.GUIDToAssetPath(scene); // Deterministic ID Generator var generator = new Unity5PackedIdentifiers(); // Target platform settings & script information var settings = new BuildSettings { buildFlags = ContentBuildFlags.None, target = target, group = BuildPipeline.GetBuildTargetGroup(target), typeDB = null }; // Inter-asset feature usage (shader features, used mesh channels) var usageSet = new BuildUsageTagSet(); var dependencyResults = ContentBuildInterface.CalculatePlayerDependenciesForScene(scenePath, settings, usageSet); // Bundle all the needed write parameters var writeParams = new WriteSceneParameters { // Target platform settings & script information settings = settings, // Scene / Project lighting information globalUsage = dependencyResults.globalUsage, // Inter-asset feature usage (shader features, used mesh channels) usageSet = usageSet, // Scene being written out scenePath = scenePath, // Serialized File Layout writeCommand = new WriteCommand { fileName = generator.GenerateSceneInternalFileName(scenePath), internalName = generator.GenerateSceneBundleInternalFileName(scenePath), serializeObjects = new List <SerializationInfo>() // Populated Below }, // External object references referenceMap = new BuildReferenceMap(), // Populated Below // External object preload preloadInfo = new PreloadInfo(), // Populated Below sceneBundleInfo = new SceneBundleInfo { bundleName = scene, bundleScenes = new List <SceneLoadInfo> { new SceneLoadInfo { asset = sceneGuid, address = scenePath, internalName = generator.GenerateInternalFileName(scenePath) } } } }; // The requirement is that a single asset bundle only contains the ObjectManifest and the objects that are directly part of the asset, objects for external assets will be in their own bundles. IE: 1 asset per bundle layout // So this means we need to take manifestObjects & manifestDependencies and filter storing them into writeCommand.serializeObjects and/or referenceMap based on if they are this asset or other assets foreach (var obj in dependencyResults.referencedObjects) { // MonoScripts need to live beside the MonoBehavior (in this case ScriptableObject) and loaded first. We could move it to it's own bundle, but this is safer and it's a lightweight object var type = ContentBuildInterface.GetTypeForObject(obj); if (obj.guid == GUIDHelper.UnityBuiltinResources) { // For Builtin Resources, we can reference them directly // TODO: Once we switch to using GlobalObjectId for SBP, we will need a mapping for certain special cases of GUID <> FilePath for Builtin Resources writeParams.referenceMap.AddMapping(obj.filePath, obj.localIdentifierInFile, obj); } else if (type == typeof(MonoScript)) { writeParams.writeCommand.serializeObjects.Add(new SerializationInfo { serializationObject = obj, serializationIndex = generator.SerializationIndexFromObjectIdentifier(obj) }); writeParams.referenceMap.AddMapping(writeParams.writeCommand.internalName, generator.SerializationIndexFromObjectIdentifier(obj), obj); } else if (collectDependencies || obj.guid == sceneGuid) { writeParams.writeCommand.serializeObjects.Add(new SerializationInfo { serializationObject = obj, serializationIndex = generator.SerializationIndexFromObjectIdentifier(obj) }); writeParams.referenceMap.AddMapping(writeParams.writeCommand.internalName, generator.SerializationIndexFromObjectIdentifier(obj), obj); } else if (obj.guid == GUIDHelper.UnityBuiltinExtraResources) { var convGUID = obj.guid; GUIDHelper.PackBuiltinExtraWithFileIdent(ref convGUID, obj.localIdentifierInFile); writeParams.referenceMap.AddMapping(generator.GenerateAssetBundleInternalFileName(convGUID), generator.SerializationIndexFromObjectIdentifier(obj), obj); dependencies?.Add(convGUID); } else if (!obj.guid.Empty()) { writeParams.referenceMap.AddMapping(generator.GenerateAssetBundleInternalFileName(obj.guid), generator.SerializationIndexFromObjectIdentifier(obj), obj); } // This will be solvable after we move SBP into the asset pipeline as importers. if (!obj.guid.Empty() && obj.guid != sceneGuid && type != typeof(MonoScript) && !GUIDHelper.IsBuiltin(obj.guid)) { dependencies?.Add(obj.guid); } if (type != null) { types?.Add(type); } } // Write the serialized file var result = ContentBuildInterface.WriteSceneSerializedFile(k_TempBuildPath, writeParams); // Archive and compress the serialized & resource files for the previous operation var crc = ContentBuildInterface.ArchiveAndCompress(result.resourceFiles.ToArray(), cacheFilePath, UnityEngine.BuildCompression.Uncompressed); // Because the shader compiler progress bar hooks are absolute shit EditorUtility.ClearProgressBar(); //Debug.Log($"Wrote '{writeParams.writeCommand.fileName}' to '{k_TempBuildPath}/{writeParams.writeCommand.internalName}' resulting in {result.serializedObjects.Count} objects in the serialized file."); //Debug.Log($"Archived '{k_TempBuildPath}/{writeParams.writeCommand.internalName}' to '{cacheFilePath}' resulting in {crc} CRC."); return(crc != 0); } }
public static bool BuildAssetBundle(string manifestPath, GUID assetGuid, string cacheFilePath, BuildTarget target, HashSet <Entities.Hash128> dependencies, HashSet <System.Type> types, long fileIdent) { using (new BuildInterfacesWrapper()) { Directory.CreateDirectory(k_TempBuildPath); // Used for naming var fixedGUID = assetGuid; if (fileIdent != -1) { GUIDHelper.PackBuiltinExtraWithFileIdent(ref fixedGUID, fileIdent); } string assetGUIDString = fixedGUID.ToString(); // Deterministic ID Generator var generator = new Unity5PackedIdentifiers(); // Target platform settings & script information var settings = new BuildSettings { buildFlags = ContentBuildFlags.None, target = target, group = BuildPipeline.GetBuildTargetGroup(target), typeDB = null }; if (assetGuid == GUIDHelper.UnityBuiltinResources) { FilterBuiltinResourcesObjectManifest(manifestPath); } if (assetGuid == GUIDHelper.UnityBuiltinExtraResources) { FilterBuiltinExtraResourcesObjectManifest(manifestPath); } // Collect all the objects we need for this asset & bundle (returned array order is deterministic) var manifestObjects = ContentBuildInterface.GetPlayerObjectIdentifiersInSerializedFile(manifestPath, settings.target); // Collect all the objects we need to reference for this asset (returned array order is deterministic) var manifestDependencies = ContentBuildInterface.GetPlayerDependenciesForObjects(manifestObjects, settings.target, settings.typeDB); // Scene / Project lighting information var globalUsage = ContentBuildInterface.GetGlobalUsageFromGraphicsSettings(); globalUsage = ForceKeepInstancingVariants(globalUsage); // Inter-asset feature usage (shader features, used mesh channels) var usageSet = new BuildUsageTagSet(); ContentBuildInterface.CalculateBuildUsageTags(manifestDependencies, manifestDependencies, globalUsage, usageSet); // TODO: Cache & Append to the assets that are influenced by this usageTagSet, ideally it would be a nice api to extract just the data for a given asset or object from the result // Bundle all the needed write parameters var writeParams = new WriteParameters { // Target platform settings & script information settings = settings, // Scene / Project lighting information globalUsage = globalUsage, // Inter-asset feature usage (shader features, used mesh channels) usageSet = usageSet, // Serialized File Layout writeCommand = new WriteCommand { fileName = generator.GenerateInternalFileName(assetGUIDString), internalName = generator.GenerateAssetBundleInternalFileName(fixedGUID), serializeObjects = new List <SerializationInfo>() // Populated Below }, // External object references referenceMap = new BuildReferenceMap(), // Populated Below // Asset Bundle object layout bundleInfo = new AssetBundleInfo { bundleName = assetGUIDString, // What is loadable from this bundle bundleAssets = new List <AssetLoadInfo> { // The manifest object and it's dependencies new AssetLoadInfo { address = assetGUIDString, asset = assetGuid, // TODO: Remove this as it is unused in C++ includedObjects = manifestObjects.ToList(), // TODO: In our effort to modernize the public API design we over complicated it trying to take List or return ReadOnlyLists. Should have just stuck with Arrays[] in all places referencedObjects = manifestDependencies.ToList() } } } }; // The requirement is that a single asset bundle only contains the ObjectManifest and the objects that are directly part of the asset, objects for external assets will be in their own bundles. IE: 1 asset per bundle layout // So this means we need to take manifestObjects & manifestDependencies and filter storing them into writeCommand.serializeObjects and/or referenceMap based on if they are this asset or other assets // For the Manifest Objects, we only have the ScriptableObject `AssetObjectManifest` which is not referenced outside of this bundle. // This creates a deterministic ID for it, regardless of the path of the manifest file var linearGenerator = new LinearPackedIdentifiers(2); foreach (var obj in manifestObjects) { var index = linearGenerator.SerializationIndexFromObjectIdentifier(obj); writeParams.writeCommand.serializeObjects.Add(new SerializationInfo { serializationObject = obj, serializationIndex = index }); writeParams.referenceMap.AddMapping(writeParams.writeCommand.internalName, index, obj); } foreach (var obj in manifestDependencies) { // MonoScripts need to live beside the MonoBehavior (in this case ScriptableObject) and loaded first. We could move it to it's own bundle, but this is safer and it's a lightweight object var type = ContentBuildInterface.GetTypeForObject(obj); if (obj.guid == GUIDHelper.UnityBuiltinResources) { // For Builtin Resources, we can reference them directly // TODO: Once we switch to using GlobalObjectId for SBP, we will need a mapping for certain special cases of GUID <> FilePath for Builtin Resources writeParams.referenceMap.AddMapping(obj.filePath, obj.localIdentifierInFile, obj); } else if (type == typeof(MonoScript)) { writeParams.writeCommand.serializeObjects.Add(new SerializationInfo { serializationObject = obj, serializationIndex = generator.SerializationIndexFromObjectIdentifier(obj) }); writeParams.referenceMap.AddMapping(writeParams.writeCommand.internalName, generator.SerializationIndexFromObjectIdentifier(obj), obj); } else if (obj.guid == assetGuid) { // If we are a specific built-in asset, only add the built-in asset if (fileIdent != -1 && obj.localIdentifierInFile != fileIdent) { continue; } writeParams.writeCommand.serializeObjects.Add(new SerializationInfo { serializationObject = obj, serializationIndex = generator.SerializationIndexFromObjectIdentifier(obj) }); writeParams.referenceMap.AddMapping(writeParams.writeCommand.internalName, generator.SerializationIndexFromObjectIdentifier(obj), obj); } else if (obj.guid == GUIDHelper.UnityBuiltinExtraResources) { var convGUID = obj.guid; GUIDHelper.PackBuiltinExtraWithFileIdent(ref convGUID, obj.localIdentifierInFile); writeParams.referenceMap.AddMapping(generator.GenerateAssetBundleInternalFileName(convGUID), generator.SerializationIndexFromObjectIdentifier(obj), obj); dependencies.Add(convGUID); } else if (!obj.guid.Empty()) { writeParams.referenceMap.AddMapping(generator.GenerateAssetBundleInternalFileName(obj.guid), generator.SerializationIndexFromObjectIdentifier(obj), obj); dependencies.Add(obj.guid); } else { throw new Exception($"Invalid dependency! GUID={obj.guid}, type={type}"); } if (type != null) { types.Add(type); } } // Write the serialized file var result = ContentBuildInterface.WriteSerializedFile(k_TempBuildPath, writeParams); // Archive and compress the serialized & resource files for the previous operation var crc = ContentBuildInterface.ArchiveAndCompress(result.resourceFiles.ToArray(), cacheFilePath, UnityEngine.BuildCompression.Uncompressed); // Because the shader compiler progress bar hooks are absolute shit EditorUtility.ClearProgressBar(); //Debug.Log($"Wrote '{writeParams.writeCommand.fileName}' to '{k_TempBuildPath}/{writeParams.writeCommand.internalName}' resulting in {result.serializedObjects.Count} objects in the serialized file."); //Debug.Log($"Archived '{k_TempBuildPath}/{writeParams.writeCommand.internalName}' to '{cacheFilePath}' resulting in {crc} CRC."); return(crc != 0); } }
public override WriteResult Write(string outputFolder, List <WriteCommand> dependencies, BuildSettings settings, BuildUsageTagGlobal globalUsage, BuildUsageTagSet buildUsage) { buildUsage.UnionWith(usageTags); return(BundleBuildInterface.WriteSceneSerializedFile(outputFolder, scene, processedScene, command, dependencies, settings, globalUsage, buildUsage, preloadInfo, info)); }
public ReturnCode Run() { var globalUsage = m_DependencyData.GlobalUsage; foreach (SceneDependencyInfo sceneInfo in m_DependencyData.SceneInfo.Values) { globalUsage |= sceneInfo.globalUsage; } if (m_SpriteData == null) { m_SpriteData = new BuildSpriteData(); } IList <CachedInfo> cachedInfo = null; List <CachedInfo> uncachedInfo = null; if (m_Parameters.UseCache && m_Cache != null) { IList <CacheEntry> entries = m_Content.Assets.Select(m_Cache.GetCacheEntry).ToList(); m_Cache.LoadCachedData(entries, out cachedInfo); uncachedInfo = new List <CachedInfo>(); } for (int i = 0; i < m_Content.Assets.Count; i++) { GUID asset = m_Content.Assets[i]; string assetPath = AssetDatabase.GUIDToAssetPath(asset.ToString()); AssetLoadInfo assetInfo; BuildUsageTagSet usageTags; SpriteImporterData importerData; if (cachedInfo != null && cachedInfo[i] != null) { if (!m_Tracker.UpdateInfoUnchecked(string.Format("{0} (Cached)", assetPath))) { return(ReturnCode.Canceled); } assetInfo = cachedInfo[i].Data[0] as AssetLoadInfo; usageTags = cachedInfo[i].Data[1] as BuildUsageTagSet; importerData = cachedInfo[i].Data[2] as SpriteImporterData; } else { if (!m_Tracker.UpdateInfoUnchecked(assetPath)) { return(ReturnCode.Canceled); } assetInfo = new AssetLoadInfo(); usageTags = new BuildUsageTagSet(); importerData = null; assetInfo.asset = asset; var includedObjects = ContentBuildInterface.GetPlayerObjectIdentifiersInAsset(asset, m_Parameters.Target); assetInfo.includedObjects = new List <ObjectIdentifier>(includedObjects); var referencedObjects = ContentBuildInterface.GetPlayerDependenciesForObjects(includedObjects, m_Parameters.Target, m_Parameters.ScriptInfo); assetInfo.referencedObjects = new List <ObjectIdentifier>(referencedObjects); ContentBuildInterface.CalculateBuildUsageTags(referencedObjects, includedObjects, globalUsage, usageTags, m_DependencyData.DependencyUsageCache); var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter; if (importer != null && importer.textureType == TextureImporterType.Sprite) { importerData = new SpriteImporterData(); importerData.PackedSprite = !string.IsNullOrEmpty(importer.spritePackingTag); importerData.SourceTexture = includedObjects.First(); } if (uncachedInfo != null) { uncachedInfo.Add(GetCachedInfo(asset, assetInfo, usageTags, importerData)); } } SetOutputInformation(asset, assetInfo, usageTags, importerData); } if (m_SpriteData.ImporterData.Count == 0) { m_SpriteData = null; } if (m_Parameters.UseCache && m_Cache != null) { m_Cache.SaveCachedData(uncachedInfo); } return(ReturnCode.Success); }
#pragma warning restore 649 CachedInfo GetCachedInfo(GUID scene, IEnumerable<ObjectIdentifier> references, SceneDependencyInfo sceneInfo, BuildUsageTagSet usageTags, IEnumerable<CacheEntry> prefabEntries, Hash128 prefabDependency) { var info = new CachedInfo(); info.Asset = m_Cache.GetCacheEntry(scene, Version); var dependencies = new HashSet<CacheEntry>(); foreach (var reference in references) dependencies.Add(m_Cache.GetCacheEntry(reference)); dependencies.UnionWith(prefabEntries); info.Dependencies = dependencies.ToArray(); info.Data = new object[] { sceneInfo, usageTags, prefabDependency }; return info; }