Esempio n. 1
0
        public static SceneSectionData[] WriteEntityScene(EntityManager entityManager, Hash128 sceneGUID, string sceneName, AssetImportContext importContext, int framesToRetainBlobAssets = 0, List <ReferencedUnityObjects> sectionRefObjs = null)
        {
            if (importContext != null)
            {
                using (var allTypes = new NativeHashMap <ComponentType, int>(100, Allocator.Temp))
                    using (var archetypes = new NativeList <EntityArchetype>(Allocator.Temp))
                    {
                        entityManager.GetAllArchetypes(archetypes);
                        foreach (var archetype in archetypes)
                        {
                            using (var componentTypes = archetype.GetComponentTypes())
                                foreach (var componentType in componentTypes)
                                {
                                    if (allTypes.TryAdd(componentType, 0))
                                    {
                                        TypeDependencyCache.AddDependency(importContext, componentType);
                                    }
                                }
                        }
                    }

                TypeDependencyCache.AddAllSystemsDependency(importContext);
            }


            var sceneSections = new List <SceneSectionData>();

            var subSectionList = new List <SceneSection>();

            entityManager.GetAllUniqueSharedComponentData(subSectionList);
            //Order sections by section id
            subSectionList.Sort(Comparer <SceneSection> .Create((a, b) => a.Section.CompareTo(b.Section)));

            var extRefInfoEntities = new NativeArray <Entity>(subSectionList.Count, Allocator.Temp);

            NativeArray <Entity> entitiesInMainSection;

            var sectionQuery = entityManager.CreateEntityQuery(
                new EntityQueryDesc
            {
                All     = new[] { ComponentType.ReadWrite <SceneSection>() },
                Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled
            }
                );

            var sectionBoundsQuery = entityManager.CreateEntityQuery(
                new EntityQueryDesc
            {
                All     = new[] { ComponentType.ReadWrite <SceneBoundingVolume>(), ComponentType.ReadWrite <SceneSection>() },
                Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled
            }
                );

            {
                var section = new SceneSection {
                    SceneGUID = sceneGUID, Section = 0
                };
                sectionQuery.SetSharedComponentFilter(new SceneSection {
                    SceneGUID = sceneGUID, Section = 0
                });
                sectionBoundsQuery.SetSharedComponentFilter(new SceneSection {
                    SceneGUID = sceneGUID, Section = 0
                });
                entitiesInMainSection = sectionQuery.ToEntityArray(Allocator.TempJob);


                var bounds = GetBoundsAndRemove(entityManager, sectionBoundsQuery);

                // Each section will be serialized in its own world, entities that don't have a section are part of the main scene.
                // An entity that holds the array of external references to the main scene is required for each section.
                // We need to create them all before we start moving entities to section scenes,
                // otherwise they would reuse entities that have been moved and mess up the remapping tables.
                for (int sectionIndex = 1; sectionIndex < subSectionList.Count; ++sectionIndex)
                {
                    if (subSectionList[sectionIndex].Section == 0)
                    {
                        // Main section, the only one that doesn't need an external ref array
                        continue;
                    }

                    var extRefInfoEntity = entityManager.CreateEntity();
                    entityManager.AddSharedComponentData(extRefInfoEntity, subSectionList[sectionIndex]);
                    extRefInfoEntities[sectionIndex] = extRefInfoEntity;
                }

                // Public references array, only on the main section.
                var refInfoEntity = entityManager.CreateEntity();
                entityManager.AddBuffer <PublicEntityRef>(refInfoEntity);
                entityManager.AddSharedComponentData(refInfoEntity, section);
                var publicRefs = entityManager.GetBuffer <PublicEntityRef>(refInfoEntity);

//                entityManager.Debug.CheckInternalConsistency();

                //@TODO do we need to keep this index? doesn't carry any additional info
                for (int i = 0; i < entitiesInMainSection.Length; ++i)
                {
                    PublicEntityRef.Add(ref publicRefs,
                                        new PublicEntityRef {
                        entityIndex = i, targetEntity = entitiesInMainSection[i]
                    });
                }

                UnityEngine.Debug.Assert(publicRefs.Length == entitiesInMainSection.Length);

                // Save main section
                var sectionWorld   = new World("SectionWorld");
                var sectionManager = sectionWorld.EntityManager;

                var entityRemapping = entityManager.CreateEntityRemapArray(Allocator.TempJob);
                sectionManager.MoveEntitiesFrom(entityManager, sectionQuery, entityRemapping);

                AddRetainBlobAssetsEntity(sectionManager, framesToRetainBlobAssets);

                // The section component is only there to break the conversion world into different sections
                // We don't want to store that on the disk
                //@TODO: Component should be removed but currently leads to corrupt data file. Figure out why.
                //sectionManager.RemoveComponent(sectionManager.UniversalQuery, typeof(SceneSection));

                var sectionFileSize = WriteEntitySceneSection(sectionManager, "0", importContext, out var objectRefCount, out var objRefs);
                sectionRefObjs?.Add(objRefs);
                sceneSections.Add(new SceneSectionData
                {
                    FileSize             = sectionFileSize,
                    SceneGUID            = sceneGUID,
                    ObjectReferenceCount = objectRefCount,
                    SubSectionIndex      = 0,
                    BoundingVolume       = bounds
                });

                entityRemapping.Dispose();
                sectionWorld.Dispose();
            }

            {
                // Index 0 is the default value of the shared component, not an actual section
                for (int subSectionIndex = 0; subSectionIndex < subSectionList.Count; ++subSectionIndex)
                {
                    var subSection = subSectionList[subSectionIndex];
                    if (subSection.Section == 0)
                    {
                        continue;
                    }

                    sectionQuery.SetSharedComponentFilter(subSection);
                    sectionBoundsQuery.SetSharedComponentFilter(subSection);

                    var bounds = GetBoundsAndRemove(entityManager, sectionBoundsQuery);

                    var entitiesInSection = sectionQuery.ToEntityArray(Allocator.TempJob);

                    if (entitiesInSection.Length > 0)
                    {
                        // Fetch back the external reference entity we created earlier to not disturb the mapping
                        var refInfoEntity = extRefInfoEntities[subSectionIndex];
                        entityManager.AddBuffer <ExternalEntityRef>(refInfoEntity);
                        var externRefs = entityManager.GetBuffer <ExternalEntityRef>(refInfoEntity);

                        // Store the mapping to everything in the main section
                        //@TODO maybe we don't need all that? is this worth worrying about?
                        for (int i = 0; i < entitiesInMainSection.Length; ++i)
                        {
                            ExternalEntityRef.Add(ref externRefs, new ExternalEntityRef {
                                entityIndex = i
                            });
                        }

                        var entityRemapping = entityManager.CreateEntityRemapArray(Allocator.TempJob);

                        // Entities will be remapped to a contiguous range in the section world, but they will
                        // also come with an unpredictable amount of meta entities. We have the guarantee that
                        // the entities in the main section won't be moved over, so there's a free range of that
                        // size at the end of the remapping table. So we use that range for external references.
                        var externEntityIndexStart = entityRemapping.Length - entitiesInMainSection.Length;

                        entityManager.AddComponentData(refInfoEntity,
                                                       new ExternalEntityRefInfo
                        {
                            SceneGUID        = sceneGUID,
                            EntityIndexStart = externEntityIndexStart
                        });

                        var sectionWorld   = new World("SectionWorld");
                        var sectionManager = sectionWorld.EntityManager;

                        // Insert mapping for external references, conversion world entity to virtual index in section
                        for (int i = 0; i < entitiesInMainSection.Length; ++i)
                        {
                            EntityRemapUtility.AddEntityRemapping(ref entityRemapping, entitiesInMainSection[i],
                                                                  new Entity {
                                Index = i + externEntityIndexStart, Version = 1
                            });
                        }

                        sectionManager.MoveEntitiesFrom(entityManager, sectionQuery, entityRemapping);

                        AddRetainBlobAssetsEntity(sectionManager, framesToRetainBlobAssets);
                        // Now that all the required entities have been moved over, we can get rid of the gap between
                        // real entities and external references. This allows remapping during load to deal with a
                        // smaller remap table, containing only useful entries.

                        int highestEntityIndexInUse = 0;
                        for (int i = 0; i < externEntityIndexStart; ++i)
                        {
                            var targetIndex = entityRemapping[i].Target.Index;
                            if (targetIndex < externEntityIndexStart && targetIndex > highestEntityIndexInUse)
                            {
                                highestEntityIndexInUse = targetIndex;
                            }
                        }

                        var oldExternEntityIndexStart = externEntityIndexStart;
                        externEntityIndexStart = highestEntityIndexInUse + 1;

                        sectionManager.SetComponentData
                        (
                            EntityRemapUtility.RemapEntity(ref entityRemapping, refInfoEntity),
                            new ExternalEntityRefInfo
                        {
                            SceneGUID        = sceneGUID,
                            EntityIndexStart = externEntityIndexStart
                        }
                        );

                        // When writing the scene, references to missing entities are set to Entity.Null by default
                        // (but only if they have been used, otherwise they remain untouched)
                        // We obviously don't want that to happen to our external references, so we add explicit mapping
                        // And at the same time, we put them back at the end of the effective range of real entities.
                        for (int i = 0; i < entitiesInMainSection.Length; ++i)
                        {
                            var src = new Entity {
                                Index = i + oldExternEntityIndexStart, Version = 1
                            };
                            var dst = new Entity {
                                Index = i + externEntityIndexStart, Version = 1
                            };
                            EntityRemapUtility.AddEntityRemapping(ref entityRemapping, src, dst);
                        }

                        // The section component is only there to break the conversion world into different sections
                        // We don't want to store that on the disk
                        //@TODO: Component should be removed but currently leads to corrupt data file. Figure out why.
                        //sectionManager.RemoveComponent(sectionManager.UniversalQuery, typeof(SceneSection));
                        var fileSize = WriteEntitySceneSection(sectionManager, subSection.Section.ToString(), importContext, out var objectRefCount, out var objRefs, entityRemapping);
                        sectionRefObjs?.Add(objRefs);
                        sceneSections.Add(new SceneSectionData
                        {
                            FileSize             = fileSize,
                            SceneGUID            = sceneGUID,
                            ObjectReferenceCount = objectRefCount,
                            SubSectionIndex      = subSection.Section,
                            BoundingVolume       = bounds
                        });

                        entityRemapping.Dispose();
                        sectionWorld.Dispose();
                    }

                    entitiesInSection.Dispose();
                }
            }

            {
                var noSectionQuery = entityManager.CreateEntityQuery(
                    new EntityQueryDesc
                {
                    None    = new[] { ComponentType.ReadWrite <SceneSection>() },
                    Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled
                }
                    );
                var sectionEntityQuery = entityManager.CreateEntityQuery(
                    new EntityQueryDesc
                {
                    None    = new[] { ComponentType.ReadWrite <SectionMetadataSetup>() },
                    Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled
                }
                    );
                var notSerializedCount = noSectionQuery.CalculateEntityCount() - sectionEntityQuery.CalculateEntityCount();
                if (notSerializedCount != 0)
                {
                    Debug.LogWarning($"{notSerializedCount} entities in the scene '{sceneName}' had no SceneSection and as a result were not serialized at all.");
                }
            }

            // Save the new header
            var sceneSectionsArray = sceneSections.ToArray();

            WriteSceneHeader(sceneGUID, sceneSectionsArray, sceneName, importContext, entityManager);

            sectionQuery.Dispose();
            sectionBoundsQuery.Dispose();
            entitiesInMainSection.Dispose();

            return(sceneSectionsArray);
        }
        internal static SceneSectionData[] WriteEntitySceneInternal(EntityManager entityManager, Hash128 sceneGUID,
                                                                    string sceneName, AssetImportContext importContext, int framesToRetainBlobAssets,
                                                                    List <ReferencedUnityObjects> sectionRefObjs, WriteEntitySceneSettings writeEntitySceneSettings, ref ConversionJournalData journalData)
        {
            using (var allTypes = new NativeHashMap <ComponentType, int>(100, Allocator.Temp))
                using (var archetypes = new NativeList <EntityArchetype>(Allocator.Temp))
                {
                    entityManager.GetAllArchetypes(archetypes);
                    for (int i = 0; i < archetypes.Length; i++)
                    {
                        var archetype = archetypes[i];
                        unsafe
                        {
                            if (archetype.Archetype->EntityCount == 0)
                            {
                                continue;
                            }
                        }

                        using (var componentTypes = archetype.GetComponentTypes())
                            foreach (var componentType in componentTypes)
                            {
                                if (allTypes.TryAdd(componentType, 0))
                                {
                                    if (importContext != null)
                                    {
                                        TypeDependencyCache.AddDependency(importContext, componentType);
                                    }
                                }
                            }
                    }
                    //Add exported types and assets to the journal data
                    using (var types = allTypes.GetKeyArray(Allocator.Temp))
                    {
                        CheckExportedTypes(writeEntitySceneSettings, true, types.Select(t => TypeManager.GetTypeInfo(t.TypeIndex)), ref journalData);
                    }
                }
            if (importContext != null)
            {
                TypeDependencyCache.AddAllSystemsDependency(importContext);
            }

            var sceneSections = new List <SceneSectionData>();

            var subSectionList = new List <SceneSection>();

            entityManager.GetAllUniqueSharedComponentData(subSectionList);
            //Order sections by section id
            subSectionList.Sort(Comparer <SceneSection> .Create((a, b) => a.Section.CompareTo(b.Section)));

            var extRefInfoEntities = new NativeArray <Entity>(subSectionList.Count, Allocator.Temp);

            NativeArray <Entity> entitiesInMainSection;

            var sectionQuery = entityManager.CreateEntityQuery(
                new EntityQueryDesc
            {
                All     = new[] { ComponentType.ReadWrite <SceneSection>() },
                Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled
            }
                );

            var sectionBoundsQuery = entityManager.CreateEntityQuery(
                new EntityQueryDesc
            {
                All     = new[] { ComponentType.ReadWrite <SceneBoundingVolume>(), ComponentType.ReadWrite <SceneSection>() },
                Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled
            }
                );

            {
                var section = new SceneSection {
                    SceneGUID = sceneGUID, Section = 0
                };
                sectionQuery.SetSharedComponentFilter(new SceneSection {
                    SceneGUID = sceneGUID, Section = 0
                });
                sectionBoundsQuery.SetSharedComponentFilter(new SceneSection {
                    SceneGUID = sceneGUID, Section = 0
                });
                entitiesInMainSection = sectionQuery.ToEntityArray(Allocator.TempJob);

                var bounds = GetBoundsAndRemove(entityManager, sectionBoundsQuery);

                // Each section will be serialized in its own world, entities that don't have a section are part of the main scene.
                // An entity that holds the array of external references to the main scene is required for each section.
                // We need to create them all before we start moving entities to section scenes,
                // otherwise they would reuse entities that have been moved and mess up the remapping tables.
                for (int sectionIndex = 1; sectionIndex < subSectionList.Count; ++sectionIndex)
                {
                    if (subSectionList[sectionIndex].Section == 0)
                    {
                        // Main section, the only one that doesn't need an external ref array
                        continue;
                    }

                    var extRefInfoEntity = entityManager.CreateEntity();
                    entityManager.AddSharedComponentData(extRefInfoEntity, subSectionList[sectionIndex]);
                    extRefInfoEntities[sectionIndex] = extRefInfoEntity;
                }

                // Public references array, only on the main section.
                var refInfoEntity = entityManager.CreateEntity();
                entityManager.AddBuffer <PublicEntityRef>(refInfoEntity);
                entityManager.AddSharedComponentData(refInfoEntity, section);
                var publicRefs = entityManager.GetBuffer <PublicEntityRef>(refInfoEntity);

//                entityManager.Debug.CheckInternalConsistency();

                //@TODO do we need to keep this index? doesn't carry any additional info
                for (int i = 0; i < entitiesInMainSection.Length; ++i)
                {
                    PublicEntityRef.Add(ref publicRefs,
                                        new PublicEntityRef {
                        entityIndex = i, targetEntity = entitiesInMainSection[i]
                    });
                }

                UnityEngine.Debug.Assert(publicRefs.Length == entitiesInMainSection.Length);

                // Save main section
                var sectionWorld   = new World("SectionWorld");
                var sectionManager = sectionWorld.EntityManager;

                var entityRemapping = entityManager.CreateEntityRemapArray(Allocator.TempJob);
                sectionManager.MoveEntitiesFrom(entityManager, sectionQuery, entityRemapping);

                AddRetainBlobAssetsEntity(sectionManager, framesToRetainBlobAssets);

                // The section component is only there to break the conversion world into different sections
                // We don't want to store that on the disk
                //@TODO: Component should be removed but currently leads to corrupt data file. Figure out why.
                //sectionManager.RemoveComponent(sectionManager.UniversalQuery, typeof(SceneSection));

                var(decompressedSectionFileSize, compressedSectionFileSize) = WriteEntitySceneSection(sectionManager, sceneGUID, "0",
                                                                                                      importContext, writeEntitySceneSettings, out var objectRefCount, out var objRefs, default);