/// <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 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); } }
/// <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; 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); } 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) { 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); }
/// <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 => GetSceneCacheEntry(x)).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]; var objectTypes = cachedInfo[i].Data[3] as List <ObjectTypes>; if (objectTypes != null) { BuildCacheUtility.SetTypeForObjects(objectTypes); } } else { if (!m_Tracker.UpdateInfoUnchecked(scenePath)) { return(ReturnCode.Canceled); } 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)); sceneInfo.SetReferencedObjects(filteredReferences); } else { sceneInfo = ContentBuildInterface.CalculatePlayerDependenciesForScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache); } #else sceneInfo = ContentBuildInterface.CalculatePlayerDependenciesForScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache); #endif #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); }
internal virtual void BuiltInResourcesToDependenciesMap(string[] resourcePaths) { for (int sceneIndex = 0; sceneIndex < resourcePaths.Length; ++sceneIndex) { string path = resourcePaths[sceneIndex]; if (EditorUtility.DisplayCancelableProgressBar("Generating built-in resource dependency map", "Checking " + path + " for duplicates with Addressables content.", (float)sceneIndex / resourcePaths.Length)) { m_ResourcesToDependencies.Clear(); EditorUtility.ClearProgressBar(); return; } string[] dependencies; if (path.EndsWith(".unity")) { #if UNITY_2019_3_OR_NEWER using (var w = new BuildInterfacesWrapper()) { var usageTags = new BuildUsageTagSet(); BuildSettings settings = new BuildSettings { group = EditorUserBuildSettings.selectedBuildTargetGroup, target = EditorUserBuildSettings.activeBuildTarget, typeDB = null, buildFlags = ContentBuildFlags.None }; SceneDependencyInfo sceneInfo = ContentBuildInterface.CalculatePlayerDependenciesForScene(path, settings, usageTags); dependencies = new string[sceneInfo.referencedObjects.Count]; for (int i = 0; i < sceneInfo.referencedObjects.Count; ++i) { if (string.IsNullOrEmpty(sceneInfo.referencedObjects[i].filePath)) { dependencies[i] = AssetDatabase.GUIDToAssetPath(sceneInfo.referencedObjects[i].guid.ToString()); } else { dependencies[i] = sceneInfo.referencedObjects[i].filePath; } } } #else HashSet <string> assetPaths = new HashSet <string>(); assetPaths.Add(path); var s = EditorSceneManager.OpenScene(path, OpenSceneMode.Additive); List <UnityEngine.Object> roots = new List <UnityEngine.Object>(s.GetRootGameObjects()); var sceneHierarchyStack = new Stack <GameObject>(); for (int i = roots.Count - 1; i >= 0; --i) { GameObject go = (GameObject)roots[i]; if (go.CompareTag("EditorOnly")) { UnityEngine.Object.DestroyImmediate(roots[i]); roots.RemoveAt(i); } else { sceneHierarchyStack.Push(go); } } while (sceneHierarchyStack.Count > 0) { var item = sceneHierarchyStack.Pop(); for (int i = 0; i < item.transform.childCount; ++i) { GameObject go = item.transform.GetChild(i).gameObject; if (go.CompareTag("EditorOnly")) { UnityEngine.Object.DestroyImmediate(go); } else { sceneHierarchyStack.Push(go); } } } UnityEngine.Object[] deps = EditorUtility.CollectDependencies(roots.ToArray()); foreach (UnityEngine.Object o in deps) { string p = AssetDatabase.GetAssetPath(o.GetInstanceID()); if (!string.IsNullOrEmpty(p)) { assetPaths.Add(p); } } EditorSceneManager.CloseScene(s, true); dependencies = assetPaths.ToArray(); #endif } else { dependencies = AssetDatabase.GetDependencies(path); } if (!m_ResourcesToDependencies.ContainsKey(path)) { m_ResourcesToDependencies.Add(path, new List <GUID>(dependencies.Length)); } else { m_ResourcesToDependencies[path].Capacity += dependencies.Length; } foreach (string dependency in dependencies) { if (dependency.EndsWith(".cs") || dependency.EndsWith(".dll")) { continue; } m_ResourcesToDependencies[path].Add(new GUID(AssetDatabase.AssetPathToGUID(dependency))); } } EditorUtility.ClearProgressBar(); }
/// <summary> /// Build map of resources to corresponding dependencies /// </summary> /// <param name="resourcePaths"> Array of resource paths</param> protected internal virtual void BuiltInResourcesToDependenciesMap(string[] resourcePaths) { for (int sceneIndex = 0; sceneIndex < resourcePaths.Length; ++sceneIndex) { string path = resourcePaths[sceneIndex]; if (EditorUtility.DisplayCancelableProgressBar("Generating built-in resource dependency map", "Checking " + path + " for duplicates with Addressables content.", (float)sceneIndex / resourcePaths.Length)) { m_ResourcesToDependencies.Clear(); EditorUtility.ClearProgressBar(); return; } string[] dependencies; if (path.EndsWith(".unity")) { using (var w = new BuildInterfacesWrapper()) { var usageTags = new BuildUsageTagSet(); BuildSettings settings = new BuildSettings { group = EditorUserBuildSettings.selectedBuildTargetGroup, target = EditorUserBuildSettings.activeBuildTarget, typeDB = null, buildFlags = ContentBuildFlags.None }; SceneDependencyInfo sceneInfo = ContentBuildInterface.CalculatePlayerDependenciesForScene(path, settings, usageTags); dependencies = new string[sceneInfo.referencedObjects.Count]; for (int i = 0; i < sceneInfo.referencedObjects.Count; ++i) { if (string.IsNullOrEmpty(sceneInfo.referencedObjects[i].filePath)) { dependencies[i] = AssetDatabase.GUIDToAssetPath(sceneInfo.referencedObjects[i].guid.ToString()); } else { dependencies[i] = sceneInfo.referencedObjects[i].filePath; } } } } else { dependencies = AssetDatabase.GetDependencies(path); } if (!m_ResourcesToDependencies.ContainsKey(path)) { m_ResourcesToDependencies.Add(path, new List <GUID>(dependencies.Length)); } else { m_ResourcesToDependencies[path].Capacity += dependencies.Length; } foreach (string dependency in dependencies) { if (dependency.EndsWith(".cs") || dependency.EndsWith(".dll")) { continue; } m_ResourcesToDependencies[path].Add(new GUID(AssetDatabase.AssetPathToGUID(dependency))); } } EditorUtility.ClearProgressBar(); }