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