internal static void CheckExportedTypes(WriteEntitySceneSettings writeEntitySceneSettings, bool record, IEnumerable <TypeManager.TypeInfo> typeInfos, ref ConversionJournalData journalData)
        {
            if (!writeEntitySceneSettings.IsDotsRuntime)
            {
                return;
            }

            if (typeInfos.Any())
            {
                if (record)
                {
                    journalData.RecordLogEvent(null, LogType.Log, "::Exported Types (by stable hash)::");
                }
                foreach (var typeInfo in typeInfos)
                {
                    // TODO: We need to define what the assembly cache should look like for hybrid. Right now BuildAssemblyCache is defined from a root assembly and a build target and has only being used by DotsRuntime
                    if (writeEntitySceneSettings.BuildAssemblyCache != null)
                    {
                        var type = typeInfo.Type;
                        if (!writeEntitySceneSettings.BuildAssemblyCache.HasType(type))
                        {
                            journalData.RecordExceptionEvent(null, new ArgumentException($"The {type.Name} component is defined in the {type.Assembly.GetName().Name} assembly, but that assembly is not referenced by the current build configuration. Either add it as a reference, or ensure that the conversion process that is adding that component does not run."));
                        }
                    }

                    // Record exported types in the conversion log file for debug purposes
                    if (record)
                    {
                        journalData.RecordLogEvent(null, LogType.Log, $"0x{typeInfo.StableTypeHash:x16} - {typeInfo.StableTypeHash,22} - {typeInfo.Type.FullName}");
                    }
                }
            }
        }
        static void AddExportedTypesToJournalData(WriteEntitySceneSettings writeEntitySceneSettings, NativeArray <ComponentType> typeInfos)
        {
            if (!writeEntitySceneSettings.IsDotsRuntime)
            {
                return;
            }

            if (typeInfos.Length > 0)
            {
                writeEntitySceneSettings.JournalData.RecordLogEvent(null, LogType.Log, "::Exported Types (by stable hash)::");
                foreach (var componentType in typeInfos)
                {
                    var typeInfo = TypeManager.GetTypeInfo(componentType.TypeIndex);
                    writeEntitySceneSettings.JournalData.RecordLogEvent(null, LogType.Log, $"0x{typeInfo.StableTypeHash:x16} - {typeInfo.StableTypeHash,22} - {typeInfo.Type.FullName}");
                }
            }
        }
예제 #3
0
        public override void OnImportAsset(AssetImportContext ctx)
        {
            try
            {
                ctx.DependsOnCustomDependency("EntityBinaryFileFormatVersion");
                ctx.DependsOnCustomDependency("SceneMetaDataFileFormatVersion");
                ctx.DependsOnSourceAsset(EntitiesCacheUtility.globalEntitySceneDependencyPath);

                var sceneWithBuildConfiguration = SceneWithBuildConfigurationGUIDs.ReadFromFile(ctx.assetPath);

                // Ensure we have as many dependencies as possible registered early in case an exception is thrown
                var scenePath = AssetDatabase.GUIDToAssetPath(sceneWithBuildConfiguration.SceneGUID.ToString());
                ctx.DependsOnSourceAsset(scenePath);

                if (sceneWithBuildConfiguration.BuildConfiguration.IsValid)
                {
                    var buildConfigurationPath = AssetDatabase.GUIDToAssetPath(sceneWithBuildConfiguration.BuildConfiguration.ToString());
                    ctx.DependsOnSourceAsset(buildConfigurationPath);
                    var buildConfigurationDependencies = AssetDatabase.GetDependencies(buildConfigurationPath);
                    foreach (var dependency in buildConfigurationDependencies)
                    {
                        ctx.DependsOnSourceAsset(dependency);
                    }
                }

                var dependencies = AssetDatabase.GetDependencies(scenePath);
                foreach (var dependency in dependencies)
                {
                    if (dependency.ToLower().EndsWith(".prefab"))
                    {
                        ctx.DependsOnSourceAsset(dependency);
                    }
                }

                var config = BuildConfiguration.LoadAsset(sceneWithBuildConfiguration.BuildConfiguration);

                var scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Additive);

                try
                {
                    var settings = new GameObjectConversionSettings();

                    settings.SceneGUID          = sceneWithBuildConfiguration.SceneGUID;
                    settings.BuildConfiguration = config;
                    settings.AssetImportContext = ctx;
                    settings.FilterFlags        = WorldSystemFilterFlags.HybridGameObjectConversion;

                    WriteEntitySceneSettings writeEntitySettings = new WriteEntitySceneSettings();
                    if (config != null && config.TryGetComponent <DotsRuntimeBuildProfile>(out var profile))
                    {
                        if (config.TryGetComponent <DotsRuntimeRootAssembly>(out var rootAssembly))
                        {
                            ctx.DependsOnSourceAsset(AssetDatabase.GetAssetPath(rootAssembly.RootAssembly.asset));
                            EditorSceneManager.SetActiveScene(scene);
                            writeEntitySettings.Codec              = Codec.LZ4;
                            writeEntitySettings.IsDotsRuntime      = true;
                            writeEntitySettings.BuildAssemblyCache = new BuildAssemblyCache()
                            {
                                BaseAssemblies = rootAssembly.RootAssembly.asset,
                                PlatformName   = profile.Target.UnityPlatformName
                            };
                            settings.FilterFlags = WorldSystemFilterFlags.DotsRuntimeGameObjectConversion;
                        }
                    }

                    var sectionRefObjs = new List <ReferencedUnityObjects>();
                    var sectionData    = EditorEntityScenes.ConvertAndWriteEntitySceneInternal(scene, settings, sectionRefObjs, writeEntitySettings);

                    WriteAssetDependencyGUIDs(sectionRefObjs, sectionData, ctx);
                }
                finally
                {
                    EditorSceneManager.CloseScene(scene, true);
                }
            }
            // Currently it's not acceptable to let the asset database catch the exception since it will create a default asset without any dependencies
            // This means a reimport will not be triggered if the scene is subsequently modified
            catch (Exception e)
            {
                Debug.Log($"Exception thrown during SubScene import: {e}");
            }
        }
        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);
        internal static SceneSectionData[] ConvertAndWriteEntitySceneInternal(Scene scene, GameObjectConversionSettings settings, List <ReferencedUnityObjects> sectionRefObjs, WriteEntitySceneSettings writeEntitySettings)
        {
            var world = new World("ConversionWorld");

            settings.DestinationWorld = world;

            bool disposeBlobAssetCache = false;

            if (settings.BlobAssetStore == null)
            {
                settings.BlobAssetStore = new BlobAssetStore();
                disposeBlobAssetCache   = true;
            }

            SceneSectionData[] sections = null;
            settings.ConversionWorldPreDispose += conversionWorld =>
            {
                var mappingSystem = conversionWorld.GetExistingSystem <GameObjectConversionMappingSystem>();
                if (settings.AssetImportContext != null)
                {
                    RegisterDependencies(settings.AssetImportContext, mappingSystem.Dependencies);
                }

                // Optimizing and writing the scene is done here to include potential log messages in the conversion log.
                EntitySceneOptimization.Optimize(world);
                int framesToRetainBlobAssets = RetainBlobAssetsSetting.GetFramesToRetainBlobAssets(settings.BuildConfiguration);
                sections = WriteEntitySceneInternal(world.EntityManager, settings.SceneGUID, scene.name, settings.AssetImportContext, framesToRetainBlobAssets, sectionRefObjs, writeEntitySettings, ref mappingSystem.JournalData);

                if (writeEntitySettings.IsDotsRuntime && sectionRefObjs.Count != 0)
                {
                    mappingSystem.JournalData.RecordExceptionEvent(null, new ArgumentException("We are serializing a world that contains UnityEngine.Object references which are not supported in Dots Runtime."));
                }

                // Save the log of issues that happened during conversion
                var journalData = mappingSystem.JournalData.SelectLogEventsOrdered().ToList();
                WriteConversionLog(settings.SceneGUID, journalData, settings.AssetImportContext, writeEntitySettings.OutputPath);
            };

            ConvertScene(scene, settings);

            if (disposeBlobAssetCache)
            {
                settings.BlobAssetStore.Dispose();
            }

            world.Dispose();

            return(sections);
        }
        public override void OnImportAsset(AssetImportContext ctx)
        {
            try
            {
                var sceneWithBuildConfiguration = SceneWithBuildConfigurationGUIDs.ReadFromFile(ctx.assetPath);

                // Ensure we have as many dependencies as possible registered early in case an exception is thrown
                EditorEntityScenes.AddEntityBinaryFileDependencies(ctx, sceneWithBuildConfiguration.BuildConfiguration);
                EditorEntityScenes.DependOnSceneGameObjects(sceneWithBuildConfiguration.SceneGUID, ctx);

                var config = BuildConfiguration.LoadAsset(sceneWithBuildConfiguration.BuildConfiguration);

                var scenePath = AssetDatabaseCompatibility.GuidToPath(sceneWithBuildConfiguration.SceneGUID);
                var scene     = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Additive);
                try
                {
                    EditorSceneManager.SetActiveScene(scene);

                    var settings = new GameObjectConversionSettings();

                    settings.SceneGUID = sceneWithBuildConfiguration.SceneGUID;
                    if (!sceneWithBuildConfiguration.IsBuildingForEditor)
                    {
                        settings.ConversionFlags |= GameObjectConversionUtility.ConversionFlags.IsBuildingForPlayer;
                    }

                    settings.BuildConfiguration = config;
                    settings.AssetImportContext = ctx;
                    settings.FilterFlags        = WorldSystemFilterFlags.HybridGameObjectConversion;

                    WriteEntitySceneSettings writeEntitySettings = new WriteEntitySceneSettings();
                    if (config != null && config.TryGetComponent <DotsRuntimeBuildProfile>(out var profile))
                    {
                        if (config.TryGetComponent <DotsRuntimeRootAssembly>(out var rootAssembly))
                        {
                            writeEntitySettings.Codec              = Codec.LZ4;
                            writeEntitySettings.IsDotsRuntime      = true;
                            writeEntitySettings.BuildAssemblyCache = new BuildAssemblyCache()
                            {
                                BaseAssemblies = rootAssembly.RootAssembly.asset,
                                PlatformName   = profile.Target.UnityPlatformName
                            };
                            settings.FilterFlags = WorldSystemFilterFlags.DotsRuntimeGameObjectConversion;

                            //Updating the root asmdef references or its references should re-trigger conversion
                            ctx.DependsOnArtifact(AssetDatabase.GetAssetPath(rootAssembly.RootAssembly.asset));
                            foreach (var assemblyPath in writeEntitySettings.BuildAssemblyCache.AssembliesPath)
                            {
                                ctx.DependsOnArtifact(assemblyPath);
                            }
                        }
                    }

                    var sectionRefObjs = new List <ReferencedUnityObjects>();
                    var sectionData    = EditorEntityScenes.ConvertAndWriteEntityScene(scene, settings, sectionRefObjs, writeEntitySettings);

                    WriteAssetDependencyGUIDs(sectionRefObjs, sectionData, ctx);

                    foreach (var objRefs in sectionRefObjs)
                    {
                        DestroyImmediate(objRefs);
                    }
                }
                finally
                {
                    EditorSceneManager.CloseScene(scene, true);
                }
            }
            // Currently it's not acceptable to let the asset database catch the exception since it will create a default asset without any dependencies
            // This means a reimport will not be triggered if the scene is subsequently modified
            catch (Exception e)
            {
                Debug.Log($"Exception thrown during SubScene import: {e}");
            }
        }