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) { objectIdentifiers = ContentBuildInterface.GetPlayerObjectIdentifiersInSerializedFile(path, m_Parameters.Target); types = ContentBuildInterface.GetTypeForObjects(objectIdentifiers); }
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 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); } }