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);
        }
        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);
        }
 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));
 }
#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);
        }