public static LoadableScene[] GetLoadableScenes(SubScene[] scenes)
        {
            var loadables = new List <LoadableScene>();

            foreach (var scene in scenes)
            {
                var sceneHeaderPath = EntityScenesPaths.GetLoadPath(scene.SceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1);
                var sceneHeader     = AssetDatabase.LoadAssetAtPath <SubSceneHeader>(sceneHeaderPath);

                if (sceneHeader != null && sceneHeader.Sections != null && scene._SceneEntities.Count == sceneHeader.Sections.Length)
                {
                    for (int i = 0; i != sceneHeader.Sections.Length; i++)
                    {
                        var name         = scene.SceneAsset.name;
                        var sectionIndex = sceneHeader.Sections[i].SubSectionIndex;
                        if (sectionIndex != 0)
                        {
                            name += $" Section: {sectionIndex}";
                        }

                        loadables.Add(new LoadableScene
                        {
                            Scene = scene._SceneEntities[i],
                            Name  = name
                        });
                    }
                }
            }

            return(loadables.ToArray());
        }
        public static string GetEntitySceneWarning(SubScene[] scenes, out bool requireCacheRebuild)
        {
            requireCacheRebuild = false;
            foreach (var scene in scenes)
            {
                if (scene.SceneAsset == null)
                {
                    return($"Please assign a valid Scene Asset");
                }

                var sceneHeaderPath = EntityScenesPaths.GetLoadPath(scene.SceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1);
                var sceneHeader     = AssetDatabase.LoadAssetAtPath <SubSceneHeader>(sceneHeaderPath);

                if (sceneHeader == null)
                {
                    requireCacheRebuild = true;
                    return($"The entity binary file header couldn't be found. Please Rebuild Entity Cache.");
                }

                //@TODO: validate header against wrong types?
                //@TODO: validate actual errors when loading
                //@TODO: validate against dependency chain being out of date
            }

            return(null);
        }
Ejemplo n.º 3
0
        internal static string GetSceneWritePath(EntityScenesPaths.PathType type, string subsectionName, AssetImportContext ctx)
        {
            var prefix = string.IsNullOrEmpty(subsectionName) ? "" : subsectionName + ".";
            var path   = ctx.GetResultPath(prefix + EntityScenesPaths.GetExtension(type));

            return(path);
        }
        public void SubScene_WithoutContents_DeletingSceneAssetUnloadsScene()
        {
            var subScene = SubSceneTestsHelper.CreateSubSceneFromObjects(ref m_TempAssets, "SubScene", false, null);

            subScene.AutoLoadScene = false;
            subScene.gameObject.SetActive(false);

            var world       = World.DefaultGameObjectInjectionWorld;
            var sceneSystem = world.GetOrCreateSystem <SceneSystem>();
            var sceneEntity = sceneSystem.LoadSceneAsync(subScene.SceneGUID, new SceneSystem.LoadParameters
            {
                Flags = SceneLoadFlags.BlockOnImport | SceneLoadFlags.BlockOnStreamIn
            });

            Assert.IsFalse(sceneSystem.IsSceneLoaded(sceneEntity), "Scene should not be loaded yet.");

            // TODO: Editor doesn't update if it doesn't have focus, so we must explicitly update the world to process the load.
            world.Update();
            Assert.IsTrue(sceneSystem.IsSceneLoaded(sceneEntity), "Failed to load scene");

            AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(subScene.SceneAsset));

            // Block the import of this subscene so that we can get a single-frame result for this test
            var hash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, sceneSystem.BuildConfigurationGUID, ImportMode.Synchronous);

            Assert.IsTrue(hash.IsValid, "Failed to import SubScene.");

            LogAssert.Expect(LogType.Error, new Regex("Loading Entity Scene failed.*"));

            // TODO: Editor doesn't update if it doesn't have focus, so we must explicitly update the world to process the load.
            world.Update();

            Assert.IsFalse(sceneSystem.IsSceneLoaded(sceneEntity), "Scene should not be loaded");
        }
        public void SubScene_WithDependencyOnAssetInScene_Reimport_EndToEnd()
        {
            var subScene = SubSceneTestsHelper.CreateSubSceneFromObjects(ref m_TempAssets, "SubScene", false, () =>
            {
                var go           = new GameObject();
                var authoring    = go.AddComponent <DependencyTestAuthoring>();
                var sphereHolder = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                authoring.Asset  = sphereHolder.GetComponent <MeshFilter>().sharedMesh;
                UnityEngine.Object.DestroyImmediate(sphereHolder);
                return(new List <GameObject> {
                    go
                });
            });

            var buildSettings = default(Unity.Entities.Hash128);
            var originalHash  = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(originalHash.IsValid);

            SubSceneInspectorUtility.ForceReimport(new [] { subScene });

            var newHashCreated = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(newHashCreated.IsValid);
            Assert.AreNotEqual(originalHash, newHashCreated);

            SubSceneInspectorUtility.ForceReimport(new [] { subScene });

            var newHashUpdated = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(newHashUpdated.IsValid);
            Assert.AreNotEqual(newHashCreated, newHashUpdated);
            Assert.AreNotEqual(originalHash, newHashUpdated);
        }
        public void SubScene_WithDependencyOnAsset_IsInvalidatedWhenAssetChanges()
        {
            var subScene = SubSceneTestsHelper.CreateSubSceneFromObjects(ref m_TempAssets, "SubScene", false, () =>
            {
                var go          = new GameObject();
                var authoring   = go.AddComponent <DependencyTestAuthoring>();
                authoring.Asset = m_Texture1;
                return(new List <GameObject> {
                    go
                });
            });

            var buildSettings = default(Unity.Entities.Hash128);
            var hash          = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(hash.IsValid);

            m_Texture1.wrapMode = m_Texture1.wrapMode == TextureWrapMode.Repeat ? TextureWrapMode.Mirror : TextureWrapMode.Repeat;
            AssetDatabase.SaveAssets();

            var newHash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.NoImport);

            Assert.AreNotEqual(hash, newHash);
            Assert.IsFalse(newHash.IsValid);
        }
 public void TestGetSectionIndexFromPath()
 {
     Assert.AreEqual(0, EntityScenesPaths.GetSectionIndexFromPath(""));
     Assert.AreEqual(5, EntityScenesPaths.GetSectionIndexFromPath("somelongpath.5.entities"));
     Assert.AreEqual(100, EntityScenesPaths.GetSectionIndexFromPath("somelongpath.100.entities"));
     Assert.AreEqual(99, EntityScenesPaths.GetSectionIndexFromPath("somelongpathwith.dots.in.the.name.98.99.entities"));
     Assert.AreEqual(0, EntityScenesPaths.GetSectionIndexFromPath("pathwith.dots.but.no.number.entities"));
 }
Ejemplo n.º 8
0
        static int WriteEntityScene(EntityManager scene, Entities.Hash128 sceneGUID, string subsection, NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapInfos = default(NativeArray <EntityRemapUtility.EntityRemapInfo>))
        {
            k_ProfileEntitiesSceneSave.Begin();

            var entitiesBinaryPath = EntityScenesPaths.GetPathAndCreateDirectory(sceneGUID, EntityScenesPaths.PathType.EntitiesBinary, subsection);
            var sharedDataPath     = EntityScenesPaths.GetPathAndCreateDirectory(sceneGUID, EntityScenesPaths.PathType.EntitiesSharedComponents, subsection);

            GameObject sharedComponents;

            // We're going to do file writing manually, so make sure to do version control dance if needed
            if (Provider.isActive && !AssetDatabase.IsOpenForEdit(entitiesBinaryPath, StatusQueryOptions.UseCachedIfPossible))
            {
                var task = Provider.Checkout(entitiesBinaryPath, CheckoutMode.Asset);
                task.Wait();
                if (!task.success)
                {
                    throw new System.Exception($"Failed to checkout entity cache file {entitiesBinaryPath}");
                }
            }

            // Write binary entity file
            int entitySceneFileSize = 0;

            using (var writer = new StreamBinaryWriter(entitiesBinaryPath))
            {
                if (entityRemapInfos.IsCreated)
                {
                    SerializeUtilityHybrid.Serialize(scene, writer, out sharedComponents, entityRemapInfos);
                }
                else
                {
                    SerializeUtilityHybrid.Serialize(scene, writer, out sharedComponents);
                }
                entitySceneFileSize = (int)writer.Length;
            }

            // Write shared component data prefab
            k_ProfileEntitiesSceneCreatePrefab.Begin();
            //var oldPrefab = AssetDatabase.LoadMainAssetAtPath(sharedDataPath);
            //if (oldPrefab == null)
            //        PrefabUtility.CreatePrefab(sharedDataPath, sharedComponents, ReplacePrefabOptions.ReplaceNameBased);

            if (sharedComponents != null)
            {
                PrefabUtility.SaveAsPrefabAsset(sharedComponents, sharedDataPath);
            }

            //else
            //    PrefabUtility.Save
            //PrefabUtility.ReplacePrefab(sharedComponents, oldPrefab, ReplacePrefabOptions.ReplaceNameBased);

            Object.DestroyImmediate(sharedComponents);
            k_ProfileEntitiesSceneCreatePrefab.End();


            k_ProfileEntitiesSceneSave.End();
            return(entitySceneFileSize);
        }
        public void SectionMetadata()
        {
            using (var world = TestWorldSetup.CreateEntityWorld("World", false))
            {
                var resolveParams = new SceneSystem.LoadParameters
                {
                    Flags = SceneLoadFlags.BlockOnImport | SceneLoadFlags.DisableAutoLoad
                };
                var sceneSystem = world.GetOrCreateSystem <SceneSystem>();
                var sceneEntity = sceneSystem.LoadSceneAsync(SceneGUID, resolveParams);
                world.Update();
                var manager         = world.EntityManager;
                var sectionEntities = manager.GetBuffer <ResolvedSectionEntity>(sceneEntity);

                Assert.AreEqual(3, sectionEntities.Length);
                Assert.IsTrue(manager.HasComponent <TestMetadata>(sectionEntities[0].SectionEntity));
                Assert.IsFalse(manager.HasComponent <TestMetadata>(sectionEntities[1].SectionEntity));
                Assert.IsTrue(manager.HasComponent <TestMetadata>(sectionEntities[2].SectionEntity));

                Assert.IsTrue(manager.HasComponent <TestMetadataTag>(sectionEntities[0].SectionEntity));
                Assert.IsFalse(manager.HasComponent <TestMetadataTag>(sectionEntities[1].SectionEntity));
                Assert.IsTrue(manager.HasComponent <TestMetadataTag>(sectionEntities[2].SectionEntity));

                // These components should not be added, instead an error is logged that meta info components can't contain entities or blob assets
                var filteredTypes = new[]
                {
                    typeof(TestMetadataWithEntity), typeof(TestMetadataWithBlobAsset), typeof(EcsTestSharedComp), typeof(EcsIntElement), typeof(EcsState1),
#if !UNITY_DISABLE_MANAGED_COMPONENTS
                    typeof(EcsTestManagedComponent)
#endif
                };

                foreach (var type in filteredTypes)
                {
                    var componentType = ComponentType.FromTypeIndex(TypeManager.GetTypeIndex(type));
                    Assert.IsFalse(manager.HasComponent(sectionEntities[0].SectionEntity, componentType));
                }

                Assert.AreEqual(0, manager.GetComponentData <TestMetadata>(sectionEntities[0].SectionEntity).SectionIndex);
                Assert.AreEqual(13, manager.GetComponentData <TestMetadata>(sectionEntities[0].SectionEntity).Value);
                Assert.AreEqual(42, manager.GetComponentData <TestMetadata>(sectionEntities[2].SectionEntity).SectionIndex);
                Assert.AreEqual(100, manager.GetComponentData <TestMetadata>(sectionEntities[2].SectionEntity).Value);

                var hash = EntityScenesPaths.GetSubSceneArtifactHash(SceneGUID, sceneSystem.BuildConfigurationGUID, true, ImportMode.Synchronous);
                Assert.IsTrue(hash.IsValid);
                AssetDatabaseCompatibility.GetArtifactPaths(hash, out var paths);
                var logPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesConversionLog);
                Assert.NotNull(logPath);
                var log = System.IO.File.ReadAllText(logPath);
                Assert.IsTrue(log.Contains("The component type must contains only blittable/basic data types"));
                Assert.IsFalse(log.Contains("entities in the scene 'TestSubSceneWithSectionMetadata' had no SceneSection and as a result were not serialized at all."));
            }
        }
Ejemplo n.º 10
0
        static void WriteHeader(Entities.Hash128 sceneGUID, SubSceneHeader header)
        {
            k_ProfileEntitiesSceneSaveHeader.Begin();

            string headerPath = EntityScenesPaths.GetPathAndCreateDirectory(sceneGUID, EntityScenesPaths.PathType.EntitiesHeader, "");

            AssetDatabase.CreateAsset(header, headerPath);

            //subscene.CacheSceneInformation();

            k_ProfileEntitiesSceneSaveHeader.End();
        }
    public void TestGetTempCachePath()
    {
        var tempCachePath = EntityScenesPaths.GetTempCachePath();

        // Verify we can make and remove this path
        if (!Directory.Exists(tempCachePath))
        {
            Directory.CreateDirectory(tempCachePath);
        }

        Directory.Delete(tempCachePath);
    }
Ejemplo n.º 12
0
        // This function is responsible for providing all the subscenes to the build.
        //
        // The way these files get generated is that we have a SceneWithBuildConfiguration file, (which is a bit of a hack to work around the inability for scriptable importers to take arguments, so
        // instead we create a different file that points to the scene we want to import, and points to the buildconfiguration we want to import it for).   The SubsceneImporter will import this file,
        // and it will make 3 (relevant) kind of files:
        // - headerfile
        // - entitybinaryformat file (the actual entities payloads)
        // - a SerializedFile that has an array of UnityEngine.Object PPtrs that are used by this entity file.
        //
        // The first two we deal with very simply: they just need to be copied into the build, and we're done.
        // the third one, we will feed as input to the Scriptable build pipeline (which is actually about creating assetbundles), and create an assetbundle that
        // has all those objects in it that the 3rd file referred to.  We do this with a batch api, first we loop through all subscenes, and register with this batch
        // api which assetbundles we'd like to see produced, and then at the end, we say "okay make them please".  this assetbundle creation api has a caching system
        // that is separate from the assetpipeline caching system, so if all goes well, the call to produce these assetbundles will return very fast and did nothing.
        //
        // The reason for the strange looking api, where a two callbacks get passed in is to make integration of the new incremental buildpipeline easier, as this code
        // needs to be compatible both with the current buildpipeline in the dots-repo, as well as with the incremental buildpipeline.  When that is merged, we can simplify this.

        public static void PrepareAdditionalFiles(string buildConfigurationGuid, Func <Type, IBuildComponent> getRequiredComponent, Action <string, string> RegisterFileCopy, string outputStreamingAssetsDirectory, string buildWorkingDirectory)
        {
            T GetRequiredComponent <T>() => (T)getRequiredComponent(typeof(T));

            var profile = GetRequiredComponent <ClassicBuildProfile>();

            if (profile.Target == BuildTarget.NoTarget)
            {
                throw new InvalidOperationException($"Invalid build target '{profile.Target.ToString()}'.");
            }

            if (profile.Target != EditorUserBuildSettings.activeBuildTarget)
            {
                throw new InvalidOperationException($"ActiveBuildTarget must be switched before the {nameof(SubSceneBuildCode)} runs.");
            }

            var content       = new BundleBuildContent(new AssetBundleBuild[0]);
            var sceneList     = GetRequiredComponent <SceneList>();
            var bundleNames   = new List <string>();
            var subSceneGuids = sceneList.GetScenePathsForBuild().SelectMany(scenePath => SceneMetaDataImporter.GetSubSceneGuids(AssetDatabase.AssetPathToGUID(scenePath))).Distinct().ToList();

            foreach (var subSceneGuid in subSceneGuids)
            {
                var hash128Guid = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(subSceneGuid, new Hash128(buildConfigurationGuid));

                var hash = AssetDatabaseCompatibility.GetArtifactHash(hash128Guid.ToString(), typeof(SubSceneImporter), ImportMode.Synchronous);
                AssetDatabaseCompatibility.GetArtifactPaths(hash, out var artifactPaths);

                foreach (var artifactPath in artifactPaths)
                {
                    var ext = Path.GetExtension(artifactPath).Replace(".", "");
                    if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader))
                    {
                        var destinationFile = outputStreamingAssetsDirectory + "/" + EntityScenesPaths.RelativePathInStreamingAssetsFolderFor(subSceneGuid, EntityScenesPaths.PathType.EntitiesHeader, -1);
                        RegisterFileCopy(artifactPath, destinationFile);
                    }

                    if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary))
                    {
                        var destinationFile = outputStreamingAssetsDirectory + "/" + EntityScenesPaths.RelativePathInStreamingAssetsFolderFor(subSceneGuid, EntityScenesPaths.PathType.EntitiesBinary, EntityScenesPaths.GetSectionIndexFromPath(artifactPath));
                        RegisterFileCopy(artifactPath, destinationFile);
                    }

                    if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectReferences))
                    {
                        content.CustomAssets.Add(new CustomContent
                        {
                            Asset     = hash128Guid,
                            Processor = (guid, processor) =>
                            {
                                var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(artifactPath);
                                processor.GetObjectIdentifiersAndTypesForSerializedFile(artifactPath, out ObjectIdentifier[] objectIds, out Type[] types);
Ejemplo n.º 13
0
        bool CheckConversionLog(SubScene subScene)
        {
            var pendingWork = false;

            foreach (var world in World.All)
            {
                var sceneSystem = world.GetExistingSystem <SceneSystem>();
                if (sceneSystem is null)
                {
                    continue;
                }

                if (!m_ConversionLogLoaded.TryGetValue(sceneSystem.BuildConfigurationGUID, out var loaded))
                {
                    m_ConversionLogLoaded.Add(sceneSystem.BuildConfigurationGUID, false);
                }
                else if (loaded)
                {
                    continue;
                }

                var hash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, sceneSystem.BuildConfigurationGUID, ImportMode.Asynchronous);
                if (!hash.IsValid)
                {
                    pendingWork = true;
                    continue;
                }

                m_ConversionLogLoaded[sceneSystem.BuildConfigurationGUID] = true;

                AssetDatabaseCompatibility.GetArtifactPaths(hash, out var paths);
                var logPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesConversionLog);
                if (logPath == null)
                {
                    continue;
                }

                var log = File.ReadAllText(logPath);
                if (log.Trim().Length != 0)
                {
                    if (m_ConversionLog.Length != 0)
                    {
                        m_ConversionLog += "\n\n";
                    }
                    m_ConversionLog += log;
                }
            }

            return(pendingWork);
        }
Ejemplo n.º 14
0
        static int WriteEntityScene(EntityManager scene, Entities.Hash128 sceneGUID, string subsection, NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapInfos = default(NativeArray <EntityRemapUtility.EntityRemapInfo>))
        {
            k_ProfileEntitiesSceneSave.Begin();

            var entitiesBinaryPath = EntityScenesPaths.GetPathAndCreateDirectory(sceneGUID, EntityScenesPaths.PathType.EntitiesBinary, subsection);
            var sharedDataPath     = EntityScenesPaths.GetPathAndCreateDirectory(sceneGUID, EntityScenesPaths.PathType.EntitiesSharedComponents, subsection);

            GameObject sharedComponents;

            // Write binary entity file
            int entitySceneFileSize = 0;

            using (var writer = new StreamBinaryWriter(entitiesBinaryPath))
            {
                if (entityRemapInfos.IsCreated)
                {
                    SerializeUtilityHybrid.Serialize(scene, writer, out sharedComponents, entityRemapInfos);
                }
                else
                {
                    SerializeUtilityHybrid.Serialize(scene, writer, out sharedComponents);
                }
                entitySceneFileSize = (int)writer.Length;
            }

            // Write shared component data prefab
            k_ProfileEntitiesSceneCreatePrefab.Begin();
            //var oldPrefab = AssetDatabase.LoadMainAssetAtPath(sharedDataPath);
            //if (oldPrefab == null)
            //        PrefabUtility.CreatePrefab(sharedDataPath, sharedComponents, ReplacePrefabOptions.ReplaceNameBased);

            if (sharedComponents != null)
            {
                PrefabUtility.SaveAsPrefabAsset(sharedComponents, sharedDataPath);
            }

            //else
            //    PrefabUtility.Save
            //PrefabUtility.ReplacePrefab(sharedComponents, oldPrefab, ReplacePrefabOptions.ReplaceNameBased);

            Object.DestroyImmediate(sharedComponents);
            k_ProfileEntitiesSceneCreatePrefab.End();


            k_ProfileEntitiesSceneSave.End();
            return(entitySceneFileSize);
        }
Ejemplo n.º 15
0
        public void SetUpOnce()
        {
#if UNITY_EDITOR
            try
            {
                BuildConfiguration.CreateAsset(m_BuildConfigPath, config =>
                {
                    config.SetComponent(new SceneList
                    {
                        SceneInfos = new List <SceneList.SceneInfo>
                        {
                            new SceneList.SceneInfo
                            {
                                Scene = GlobalObjectId.GetGlobalObjectIdSlow(
                                    AssetDatabase.LoadAssetAtPath <SceneAsset>(m_SubScenePath))
                            }
                        }
                    });
                });
                m_BuildConfigurationGUID = new GUID(AssetDatabase.AssetPathToGUID(m_BuildConfigPath));
                m_SceneGUID = new GUID(AssetDatabase.AssetPathToGUID(m_SubScenePath));

                var guid = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(m_SceneGUID, m_BuildConfigurationGUID, true,
                                                                            out var requestRefresh);
                if (requestRefresh)
                {
                    AssetDatabase.Refresh();
                }
                m_SceneWithBuildSettingsPath = SceneWithBuildConfigurationGUIDs.GetSceneWithBuildSettingsPath(guid);
                EntityScenesPaths.GetSubSceneArtifactHash(m_SceneGUID, m_BuildConfigurationGUID, true,
                                                          ImportMode.Synchronous);
            }
            catch
            {
                AssetDatabase.DeleteAsset(m_TempPath);
                AssetDatabase.DeleteAsset(m_SceneWithBuildSettingsPath);
                throw;
            }

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
#else
            //TODO: Playmode test not supported yet
            m_SceneGUID = new Unity.Entities.Hash128();
#endif
        }
        public void SubScene_WithDependencyOnAssetInScene_ClearCache_EndToEnd()
        {
            var subScene = SubSceneTestsHelper.CreateSubSceneFromObjects(ref m_TempAssets, "SubScene", false, () =>
            {
                var go           = new GameObject();
                var authoring    = go.AddComponent <DependencyTestAuthoring>();
                var sphereHolder = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                authoring.Asset  = sphereHolder.GetComponent <MeshFilter>().sharedMesh;
                UnityEngine.Object.DestroyImmediate(sphereHolder);
                return(new List <GameObject> {
                    go
                });
            });

            var buildSettings = default(Unity.Entities.Hash128);
            var originalHash  = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(originalHash.IsValid);

            // Clear Cache (First time this creates global dependency asset, so we will test both steps)
            EntitiesCacheUtility.UpdateEntitySceneGlobalDependency();

            var newHashCreated = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(newHashCreated.IsValid);
            Assert.AreNotEqual(originalHash, newHashCreated);

            // Clear Cache (This updates existing asset)
            EntitiesCacheUtility.UpdateEntitySceneGlobalDependency();

            var newHashUpdated = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(newHashUpdated.IsValid);
            Assert.AreNotEqual(newHashCreated, newHashUpdated);
            Assert.AreNotEqual(originalHash, newHashUpdated);

            // Delete created dependency, this cleans up test but also we need to verify that the scene returns to the original hash
            AssetDatabase.DeleteAsset(EntitiesCacheUtility.globalEntitiesDependencyDir);
            AssetDatabase.Refresh();

            // With the dependency deleted, the hash should return to the original
            var finalHash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.AreEqual(originalHash, finalHash);
        }
        public void SubScene_WithDependencyOnAssetInScene_StillImports()
        {
            var subScene = SubSceneTestsHelper.CreateSubSceneFromObjects(ref m_TempAssets, "SubScene", false, () =>
            {
                var go          = new GameObject();
                var authoring   = go.AddComponent <DependencyTestAuthoring>();
                var texture     = new Texture2D(64, 64);
                authoring.Asset = texture;
                return(new List <GameObject> {
                    go
                });
            });

            var buildSettings = default(Unity.Entities.Hash128);
            var hash          = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(hash.IsValid);
        }
        static bool IsSubsceneImported(SubScene subScene)
        {
            foreach (var world in World.All)
            {
                var sceneSystem = world.GetExistingSystem <SceneSystem>();
                if (sceneSystem is null)
                {
                    continue;
                }

                var hash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, sceneSystem.BuildConfigurationGUID, ImportMode.NoImport);
                if (!hash.IsValid)
                {
                    return(false);
                }
            }

            return(true);
        }
        public void SubScene_WithDependencyOnBuiltInAsset_StillImports()
        {
            var subScene = SubSceneTestsHelper.CreateSubSceneFromObjects(ref m_TempAssets, "SubScene", false, () =>
            {
                var go           = new GameObject();
                var authoring    = go.AddComponent <DependencyTestAuthoring>();
                var sphereHolder = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                authoring.Asset  = sphereHolder.GetComponent <MeshFilter>().sharedMesh;
                UnityEngine.Object.DestroyImmediate(sphereHolder);
                return(new List <GameObject> {
                    go
                });
            });

            var buildSettings = default(Unity.Entities.Hash128);
            var hash          = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(hash.IsValid);
        }
        public static void ConvertToBuild(GUID buildSettingSceneGuid, UnityEditor.Build.Pipeline.Tasks.CalculateCustomDependencyData task)
        {
            var buildSettingScenePath  = AssetDatabase.GUIDToAssetPath(buildSettingSceneGuid.ToString());
            var sceneWithBuildSettings = ReadSceneWithBuildSettings(buildSettingScenePath);

            var hash = UnityEditor.Experimental.AssetDatabaseExperimental.GetArtifactHash(buildSettingSceneGuid.ToString(), typeof(SubSceneImporter));

            string[] paths;
            if (!UnityEditor.Experimental.AssetDatabaseExperimental.GetArtifactPaths(hash, out paths))
            {
                return;
            }

            foreach (var path in paths)
            {
                var ext = System.IO.Path.GetExtension(path).Replace(".", "");
                if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader))
                {
                    var loadPath = EntityScenesPaths.GetLoadPath(sceneWithBuildSettings.SceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1);
                    System.IO.File.Copy(path, loadPath, true);
                    continue;
                }

                if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary))
                {
                    var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(path);
                    var loadPath     = EntityScenesPaths.GetLoadPath(sceneWithBuildSettings.SceneGUID, EntityScenesPaths.PathType.EntitiesBinary, sectionIndex);
                    System.IO.File.Copy(path, loadPath, true);
                    continue;
                }

                if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectReferences))
                {
                    var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(path);
                    task.GetObjectIdentifiersAndTypesForSerializedFile(path, out UnityEditor.Build.Content.ObjectIdentifier[] objectIds, out System.Type[] types);
                    var bundlePath = EntityScenesPaths.GetLoadPath(sceneWithBuildSettings.SceneGUID, EntityScenesPaths.PathType.EntitiesUnityObjectReferences, sectionIndex);
                    var bundleName = System.IO.Path.GetFileName(bundlePath);
                    task.CreateAssetEntryForObjectIdentifiers(objectIds, path, bundleName, bundleName, typeof(ReferencedUnityObjects));
                }
            }
        }
Ejemplo n.º 21
0
        public static void WriteRefGuids(List <ReferencedUnityObjects> referencedUnityObjects, AssetImportContext ctx)
        {
            for (var index = 0; index < referencedUnityObjects.Count; index++)
            {
                var objRefs = referencedUnityObjects[index];
                if (objRefs == null)
                {
                    continue;
                }

                var refGuidsPath           = ctx.GetResultPath($"{index}.{EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectRefGuids)}");
                var runtimeGlobalObjectIds = ReferencedUnityObjectsToRuntimeGlobalObjectIds(objRefs);

                using (var refGuidWriter = new StreamBinaryWriter(refGuidsPath))
                {
                    refGuidWriter.Write(runtimeGlobalObjectIds.Length);
                    refGuidWriter.WriteArray(runtimeGlobalObjectIds.AsArray());
                }

                runtimeGlobalObjectIds.Dispose();
            }
        }
        //TODO: There is too much code duplication here, refactor this to send general artifacts to the editor
        unsafe void SendSubScene(Unity.Entities.Hash128 subSceneGuid, Unity.Entities.Hash128 buildSettingsGuid, int playerId)
        {
            LiveLinkMsg.LogInfo($"Sending SubScene: 'GUID: {subSceneGuid}' with 'BuildSettings: {buildSettingsGuid}' to playerId: {playerId}");

            var hash = EntityScenesPaths.GetSubSceneArtifactHash(subSceneGuid, buildSettingsGuid, AssetDatabaseExperimental.ImportSyncMode.Block);

            AssetDatabaseExperimental.GetArtifactPaths(hash, out var paths);
            var sceneHeaderPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesHeader);

            if (!File.Exists(sceneHeaderPath))
            {
                Debug.LogError("Send Entity Scene failed because the entity header file could not be found: " + sceneHeaderPath);
                return;
            }

            if (!BlobAssetReference <SceneMetaData> .TryRead(sceneHeaderPath, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef))
            {
                Debug.LogError("Send Entity Scene failed because the entity header file was an old version: " + sceneHeaderPath);
                return;
            }

            ref var sceneMetaData = ref sceneMetaDataRef.Value;
        public void RequestSubSceneTargetHash(MessageEventArgs args)
        {
            using (var subScenes = args.ReceiveArray <SubSceneGUID>())
            {
                var resolvedScenes = new HashSet <ResolvedSubSceneID>();
                foreach (var subScene in subScenes)
                {
                    LiveLinkMsg.LogInfo($"RequestSubSceneTargetHash => {subScene.Guid}, {subScene.BuildConfigurationGuid}");

                    var targetHash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.Guid, subScene.BuildConfigurationGuid, UnityEditor.Experimental.AssetDatabaseExperimental.ImportSyncMode.Queue);
                    _UsedSubSceneTargetHash[subScene] = targetHash;
                    if (targetHash.IsValid)
                    {
                        resolvedScenes.Add(new ResolvedSubSceneID {
                            SubSceneGUID = subScene, TargetHash = targetHash
                        });
                    }
                }

                TimeBasedCallbackInvoker.SetCallback(DetectChangedAssets);

                if (resolvedScenes.Count == 0)
                {
                    return;
                }

                var resolved = new NativeArray <ResolvedSubSceneID>(resolvedScenes.Count, Allocator.Temp);
                int i        = 0;
                foreach (var id in resolvedScenes)
                {
                    resolved[i++] = id;
                }

                SendSubSceneTargetHash(resolved, args.playerId);
            }
        }
Ejemplo n.º 24
0
        public void SubScene_WithDependencyOnAsset_IsInvalidatedWhenAssetChanges()
        {
            var subScene = CreateSubScene("SubScene", nameof(SubScene_WithDependencyOnAsset_IsInvalidatedWhenAssetChanges));

            SubSceneInspectorUtility.EditScene(subScene);
            var go        = new GameObject();
            var authoring = go.AddComponent <DependencyTestAuthoring>();

            var dependency = new GameObject();

            authoring.GameObject = dependency;
            var texture = new Texture2D(64, 64);

            authoring.Asset = texture;
            var assetPath = Path.Combine(m_TempAssetDir, "Texture.asset");

            AssetDatabase.CreateAsset(authoring.Asset, assetPath);
            SceneManager.MoveGameObjectToScene(dependency, subScene.EditingScene);
            SceneManager.MoveGameObjectToScene(go, subScene.EditingScene);
            EditorSceneManager.SaveScene(subScene.EditingScene);

            AssetDatabase.TryGetGUIDAndLocalFileIdentifier(subScene.SceneAsset, out var guid, out long _);

            var buildSettings = default(Unity.Entities.Hash128);
            var subSceneGuid  = new GUID(guid);
            var hash          = EntityScenesPaths.GetSubSceneArtifactHash(subSceneGuid, buildSettings, ImportMode.Synchronous);

            Assert.IsTrue(hash.IsValid);

            texture.wrapMode = texture.wrapMode == TextureWrapMode.Repeat ? TextureWrapMode.Mirror : TextureWrapMode.Repeat;
            AssetDatabase.SaveAssets();
            var newHash = EntityScenesPaths.GetSubSceneArtifactHash(subSceneGuid, buildSettings, ImportMode.NoImport);

            Assert.AreNotEqual(hash, newHash);
            Assert.IsFalse(newHash.IsValid);
        }
Ejemplo n.º 25
0
        static void WriteAssetDependencyGUIDs(List <ReferencedUnityObjects> referencedUnityObjects, SceneSectionData[] sectionData, AssetImportContext ctx)
        {
            for (var index = 0; index < referencedUnityObjects.Count; index++)
            {
                var sectionIndex = sectionData[index].SubSectionIndex;

                var objRefs = referencedUnityObjects[index];
                if (objRefs == null)
                {
                    continue;
                }

                var path = ctx.GetResultPath($"{sectionIndex}.{EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesAssetDependencyGUIDs)}");
                var assetDependencyGUIDs = ReferencedUnityObjectsToGUIDs(objRefs, ctx);

                using (var writer = new StreamBinaryWriter(path))
                {
                    writer.Write(assetDependencyGUIDs.Length);
                    writer.WriteArray(assetDependencyGUIDs.AsArray());
                }

                assetDependencyGUIDs.Dispose();
            }
        }
        internal static string GetSceneWritePath(EntityScenesPaths.PathType type, string subsectionName, Hash128 sceneGUID, string outputPath)
        {
            var prefix = string.IsNullOrEmpty(subsectionName) ? "" : subsectionName + ".";

            return(Path.Combine(outputPath, sceneGUID + "." + prefix + EntityScenesPaths.GetExtension(type)));
        }
Ejemplo n.º 27
0
        void RequestSubSceneTargetHash(MessageEventArgs args)
        {
            //@TODO: should be based on connection / BuildSetting
            var buildTarget = EditorUserBuildSettings.activeBuildTarget;

            using (var subScenes = args.ReceiveArray <SubSceneGUID>())
            {
                var resolvedScenes    = new HashSet <ResolvedSubSceneID>();
                var assetDependencies = new HashSet <ResolvedAssetID>();

                foreach (var subScene in subScenes)
                {
                    LiveLinkMsg.LogInfo($"RequestSubSceneTargetHash => {subScene.Guid}, {subScene.BuildConfigurationGuid}");

                    var targetHash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.Guid, subScene.BuildConfigurationGuid, ImportMode.Asynchronous);
                    m_TrackedSubScenes[subScene] = targetHash;
                    if (targetHash.IsValid)
                    {
                        resolvedScenes.Add(new ResolvedSubSceneID {
                            SubSceneGUID = subScene, TargetHash = targetHash
                        });

                        var sceneDependencies = LiveLinkBuildPipeline.GetSubSceneDependencies(targetHash);
                        foreach (var sceneDependency in sceneDependencies)
                        {
                            assetDependencies.Add(sceneDependency);
                            m_TrackedAssets[sceneDependency.GUID] = sceneDependency.TargetHash;

                            if (sceneDependency.TargetHash.IsValid)
                            {
                                LiveLinkBuildPipeline.CalculateTargetDependencies(sceneDependency.TargetHash, buildTarget, out ResolvedAssetID[] dependencies, ImportMode.Asynchronous, sceneDependency.GUID);
                                foreach (var dependency in dependencies)
                                {
                                    m_TrackedAssets[dependency.GUID] = dependency.TargetHash;
                                    assetDependencies.Add(new ResolvedAssetID {
                                        GUID = dependency.GUID, TargetHash = dependency.TargetHash
                                    });
                                }
                            }
                        }
                    }
                }

                TimeBasedCallbackInvoker.SetCallback(DetectChangedAssets);

                if (resolvedScenes.Count == 0)
                {
                    return;
                }

                var resolved = new NativeArray <ResolvedSubSceneID>(resolvedScenes.Count, Allocator.Temp);
                int i        = 0;
                foreach (var id in resolvedScenes)
                {
                    resolved[i++] = id;
                }

                SendSubSceneTargetHash(resolved, args.playerId);

                if (assetDependencies.Count > 0)
                {
                    var resolvedAssets = new NativeArray <ResolvedAssetID>(assetDependencies.Count, Allocator.Temp);
                    int assetIndex     = 0;
                    foreach (var asset in assetDependencies)
                    {
                        resolvedAssets[assetIndex++] = asset;
                    }

                    SendAssetTargetHash(resolvedAssets, args.playerId);
                }
            }
        }
        // This function is responsible for providing all the subscenes to the build.
        //
        // The way these files get generated is that we have a SceneWithBuildConfiguration file, (which is a bit of a hack to work around the inability for scriptable importers to take arguments, so
        // instead we create a different file that points to the scene we want to import, and points to the buildconfiguration we want to import it for).   The SubsceneImporter will import this file,
        // and it will make 3 (relevant) kind of files:
        // - headerfile
        // - entitybinaryformat file (the actual entities payloads)
        // - a SerializedFile that has an array of UnityEngine.Object PPtrs that are used by this entity file.
        //
        // The first two we deal with very simply: they just need to be copied into the build, and we're done.
        // the third one, we will feed as input to the Scriptable build pipeline (which is actually about creating assetbundles), and create an assetbundle that
        // has all those objects in it that the 3rd file referred to.  We do this with a batch api, first we loop through all subscenes, and register with this batch
        // api which assetbundles we'd like to see produced, and then at the end, we say "okay make them please".  this assetbundle creation api has a caching system
        // that is separate from the assetpipeline caching system, so if all goes well, the call to produce these assetbundles will return very fast and did nothing.
        //
        // The reason for the strange looking api, where a two callbacks get passed in is to make integration of the new incremental buildpipeline easier, as this code
        // needs to be compatible both with the current buildpipeline in the dots-repo, as well as with the incremental buildpipeline.  When that is merged, we can simplify this.
        public static void PrepareAdditionalFiles(GUID[] sceneGuids, ArtifactKey[] entitySceneArtifacts, BuildTarget target, Action <string, string> RegisterFileCopy, string outputStreamingAssetsDirectory, string buildWorkingDirectory)
        {
            if (target == BuildTarget.NoTarget)
            {
                throw new InvalidOperationException($"Invalid build target '{target.ToString()}'.");
            }

            if (target != EditorUserBuildSettings.activeBuildTarget)
            {
                throw new InvalidOperationException($"ActiveBuildTarget must be switched before the {nameof(SubSceneBuildCode)} runs.");
            }

            Assert.AreEqual(sceneGuids.Length, entitySceneArtifacts.Length);

            var content             = new BundleBuildContent(new AssetBundleBuild[0]);
            var bundleNames         = new HashSet <string>();
            var subScenePaths       = new Dictionary <Hash128, string>();
            var dependencyInputData = new Dictionary <SceneSection, SectionDependencyInfo>();

            var    refExt    = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectReferences);
            var    headerExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader);
            var    binaryExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary);
            string conversionLogExtension = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesConversionLog);

            var group      = BuildPipeline.GetBuildTargetGroup(target);
            var parameters = new BundleBuildParameters(target, @group, buildWorkingDirectory)
            {
                BundleCompression = BuildCompression.LZ4Runtime
            };

            var artifactHashes = new UnityEngine.Hash128[entitySceneArtifacts.Length];

            AssetDatabaseCompatibility.ProduceArtifactsRefreshIfNecessary(entitySceneArtifacts, artifactHashes);

            for (int i = 0; i != entitySceneArtifacts.Length; i++)
            {
                var sceneGuid            = sceneGuids[i];
                var sceneBuildConfigGuid = entitySceneArtifacts[i].guid;
                var artifactHash         = artifactHashes[i];

                bool foundEntityHeader = false;

                if (!artifactHash.isValid)
                {
                    throw new Exception($"Building EntityScene artifact failed: '{AssetDatabaseCompatibility.GuidToPath(sceneGuid)}' ({sceneGuid}). There were exceptions during the entity scene imports.");
                }

                AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out var artifactPaths);

                foreach (var artifactPath in artifactPaths)
                {
                    //UnityEngine.Debug.Log($"guid: {sceneGuid} artifact: '{artifactPath}'");

                    //@TODO: This looks like a workaround. Whats going on here?
                    var ext = Path.GetExtension(artifactPath).Replace(".", "");

                    if (ext == conversionLogExtension)
                    {
                        var res = ConversionLogUtils.PrintConversionLogToUnityConsole(artifactPath);

                        if (res.HasException)
                        {
                            throw new Exception("Building entity scenes failed. There were exceptions during the entity scene imports.");
                        }
                    }
                    else if (ext == headerExt)
                    {
                        foundEntityHeader = true;

                        if (!string.IsNullOrEmpty(artifactPaths.FirstOrDefault(a => a.EndsWith(refExt))))
                        {
                            subScenePaths[sceneGuid] = artifactPath;
                        }
                        else
                        {
                            //if there are no reference bundles, then deduplication can be skipped
                            var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesHeader, -1);
                            DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile);
                        }
                    }
                    else if (ext == binaryExt)
                    {
                        var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesBinary, EntityScenesPaths.GetSectionIndexFromPath(artifactPath));
                        DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile);
                    }
                    else if (ext == refExt)
                    {
                        content.CustomAssets.Add(new CustomContent
                        {
                            Asset     = sceneBuildConfigGuid,
                            Processor = (guid, processor) =>
                            {
                                var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(artifactPath);
                                processor.GetObjectIdentifiersAndTypesForSerializedFile(artifactPath, out ObjectIdentifier[] objectIds, out Type[] types);
Ejemplo n.º 29
0
        public static bool HasEntitySceneCache(Hash128 sceneGUID)
        {
            string headerPath = EntityScenesPaths.GetPathAndCreateDirectory(sceneGUID, EntityScenesPaths.PathType.EntitiesHeader, "");

            return(File.Exists(headerPath));
        }
Ejemplo n.º 30
0
        // This function is responsible for providing all the subscenes to the build.
        //
        // The way these files get generated is that we have a SceneWithBuildConfiguration file, (which is a bit of a hack to work around the inability for scriptable importers to take arguments, so
        // instead we create a different file that points to the scene we want to import, and points to the buildconfiguration we want to import it for).   The SubsceneImporter will import this file,
        // and it will make 3 (relevant) kind of files:
        // - headerfile
        // - entitybinaryformat file (the actual entities payloads)
        // - a SerializedFile that has an array of UnityEngine.Object PPtrs that are used by this entity file.
        //
        // The first two we deal with very simply: they just need to be copied into the build, and we're done.
        // the third one, we will feed as input to the Scriptable build pipeline (which is actually about creating assetbundles), and create an assetbundle that
        // has all those objects in it that the 3rd file referred to.  We do this with a batch api, first we loop through all subscenes, and register with this batch
        // api which assetbundles we'd like to see produced, and then at the end, we say "okay make them please".  this assetbundle creation api has a caching system
        // that is separate from the assetpipeline caching system, so if all goes well, the call to produce these assetbundles will return very fast and did nothing.
        //
        // The reason for the strange looking api, where a two callbacks get passed in is to make integration of the new incremental buildpipeline easier, as this code
        // needs to be compatible both with the current buildpipeline in the dots-repo, as well as with the incremental buildpipeline.  When that is merged, we can simplify this.
        public static void PrepareAdditionalFiles(string buildConfigurationGuid, string[] scenePathsForBuild, BuildTarget target, Action <string, string> RegisterFileCopy, string outputStreamingAssetsDirectory, string buildWorkingDirectory)
        {
            if (target == BuildTarget.NoTarget)
            {
                throw new InvalidOperationException($"Invalid build target '{target.ToString()}'.");
            }

            if (target != EditorUserBuildSettings.activeBuildTarget)
            {
                throw new InvalidOperationException($"ActiveBuildTarget must be switched before the {nameof(SubSceneBuildCode)} runs.");
            }

            var content             = new BundleBuildContent(new AssetBundleBuild[0]);
            var bundleNames         = new HashSet <string>();
            var subSceneGuids       = scenePathsForBuild.SelectMany(scenePath => SceneMetaDataImporter.GetSubSceneGuids(AssetDatabase.AssetPathToGUID(scenePath))).Distinct().ToList();
            var subScenePaths       = new Dictionary <Hash128, string>();
            var dependencyInputData = new Dictionary <SceneSection, SectionDependencyInfo>();
            var refExt    = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectReferences);
            var headerExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader);
            var binaryExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary);

            var group      = BuildPipeline.GetBuildTargetGroup(target);
            var parameters = new BundleBuildParameters(target, @group, buildWorkingDirectory)
            {
                BundleCompression = BuildCompression.LZ4Runtime
            };

            var requiresRefresh       = false;
            var sceneBuildConfigGuids = new NativeArray <GUID>(subSceneGuids.Count, Allocator.TempJob);

            for (int i = 0; i != sceneBuildConfigGuids.Length; i++)
            {
                sceneBuildConfigGuids[i] = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(subSceneGuids[i], new Hash128(buildConfigurationGuid), out var thisRequiresRefresh);
                requiresRefresh         |= thisRequiresRefresh;
            }
            if (requiresRefresh)
            {
                AssetDatabase.Refresh();
            }

            var artifactHashes = new NativeArray <UnityEngine.Hash128>(subSceneGuids.Count, Allocator.TempJob);

            AssetDatabaseCompatibility.ProduceArtifactsRefreshIfNecessary(sceneBuildConfigGuids, typeof(SubSceneImporter), artifactHashes);

            for (int i = 0; i != sceneBuildConfigGuids.Length; i++)
            {
                var sceneGuid            = subSceneGuids[i];
                var sceneBuildConfigGuid = sceneBuildConfigGuids[i];
                var artifactHash         = artifactHashes[i];

                bool foundEntityHeader = false;
                AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out var artifactPaths);
                foreach (var artifactPath in artifactPaths)
                {
                    //@TODO: This looks like a workaround. Whats going on here?
                    var ext = Path.GetExtension(artifactPath).Replace(".", "");
                    if (ext == headerExt)
                    {
                        foundEntityHeader = true;

                        if (!string.IsNullOrEmpty(artifactPaths.FirstOrDefault(a => a.EndsWith(refExt))))
                        {
                            subScenePaths[sceneGuid] = artifactPath;
                        }
                        else
                        {
                            //if there are no reference bundles, then deduplication can be skipped
                            var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesHeader, -1);
                            DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile);
                        }
                    }
                    else if (ext == binaryExt)
                    {
                        var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesBinary, EntityScenesPaths.GetSectionIndexFromPath(artifactPath));
                        DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile);
                    }

                    if (ext == refExt)
                    {
                        content.CustomAssets.Add(new CustomContent
                        {
                            Asset     = sceneBuildConfigGuid,
                            Processor = (guid, processor) =>
                            {
                                var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(artifactPath);
                                processor.GetObjectIdentifiersAndTypesForSerializedFile(artifactPath, out ObjectIdentifier[] objectIds, out Type[] types);