static unsafe void ReadBootstrap() { var path = bootstrapPath; using (var rdr = new StreamBinaryReader(path)) { Hash128 guid = default; long id = 0; rdr.ReadBytes(&guid, sizeof(Hash128)); rdr.ReadBytes(&id, sizeof(long)); BuildConfigurationGUID = guid; LiveLinkId = id; } }
void RemoveSceneEntities() { if (_AddedSceneGUID != default) { var sceneGUID = _AddedSceneGUID; _AddedSceneGUID = default; foreach (var world in World.All) { var sceneSystem = world.GetExistingSystem <SceneSystem>(); if (sceneSystem != null) { sceneSystem.UnloadScene(sceneGUID, SceneSystem.UnloadParameters.DestroySceneProxyEntity | SceneSystem.UnloadParameters.DestroySectionProxyEntities); } } } }
static NativeArray<Entity> GetActiveWorldSections(World world, Hash128 sceneGUID) { if (world == null || !world.IsCreated) return default; var sceneSystem = world.GetExistingSystem<SceneSystem>(); if (sceneSystem == null) return default; var entities = world.EntityManager; var sceneEntity = sceneSystem.GetSceneEntity(sceneGUID); if (!entities.HasComponent<ResolvedSectionEntity>(sceneEntity)) return default; return entities.GetBuffer<ResolvedSectionEntity>(sceneEntity).Reinterpret<Entity>().AsNativeArray(); }
private bool IsExportingRootScene() { var sceneList = Settings.BuildConfiguration.GetComponent <SceneList>(); bool convertingRootScene = false; foreach (var sceneInfo in sceneList.SceneInfos) { var sceneHash = new Hash128(sceneInfo.Scene.assetGUID.ToString()); if (sceneHash == Settings.SceneGUID) { convertingRootScene = true; break; } } return(convertingRootScene); }
public void Convert(Scene scene, Hash128 sceneGUID, GameObjectConversionUtility.ConversionFlags flags, BuildSettings buildSettings) { using (m_ConvertMarker.Auto()) { // Try incremental conversion if (!_RequestCleanConversion) { // Debug.Log("Incremental convert"); try { GameObjectConversionUtility.ConvertIncremental(_GameObjectWorld, _ChangedGameObjects, flags); _ChangedGameObjects.Clear(); } #pragma warning disable 168 catch (Exception e) { _RequestCleanConversion = true; // Debug.Log("Incremental conversion failed. Performing full conversion instead\n" + e.ToString()); } #pragma warning restore 168 } // If anything failed, fall back to clean conversion if (_RequestCleanConversion) { // Debug.Log("Clean convert"); _ConvertedWorld.EntityManager.DestroyEntity(_ConvertedWorld.EntityManager.UniversalQuery); var conversionSettings = new GameObjectConversionSettings(_ConvertedWorld, flags); conversionSettings.BuildSettings = buildSettings; conversionSettings.SceneGUID = sceneGUID; conversionSettings.DebugConversionName = _SceneName; conversionSettings.BlobAssetStore = m_BlobAssetStore; if (_GameObjectWorld != null && _GameObjectWorld.IsCreated) { _GameObjectWorld.Dispose(); _GameObjectWorld = null; } _GameObjectWorld = GameObjectConversionUtility.ConvertIncrementalInitialize(scene, conversionSettings); } _ChangedGameObjects.Clear(); _RequestCleanConversion = false; } }
internal Hash128 ComputeHash() { m_computedHash = false; m_blobProfile = default; m_filtersLeft.Clear(); m_filtersRight.Clear(); m_channelIndicesLeft.Clear(); m_channelIndicesRight.Clear(); m_anglesPerLeftChannel.Clear(); m_anglesPerRightChannel.Clear(); m_passthroughFractionsPerLeftChannel.Clear(); m_passthroughFractionsPerRightChannel.Clear(); m_filterVolumesPerLeftChannel.Clear(); m_filterVolumesPerRightChannel.Clear(); m_passthroughVolumesPerLeftChannel.Clear(); m_passthroughVolumesPerRightChannel.Clear(); BuildProfile(); var job = new ComputeHashJob { filtersLeft = m_filtersLeft, channelIndicesLeft = m_channelIndicesLeft, filtersRight = m_filtersRight, channelIndicesRight = m_channelIndicesRight, anglesPerLeftChannel = m_anglesPerLeftChannel, anglesPerRightChannel = m_anglesPerRightChannel, passthroughFractionsPerLeftChannel = m_passthroughFractionsPerLeftChannel, passthroughFractionsPerRightChannel = m_passthroughFractionsPerRightChannel, filterVolumesPerLeftChannel = m_filterVolumesPerLeftChannel, filterVolumesPerRightChannel = m_filterVolumesPerRightChannel, passthroughVolumesPerLeftChannel = m_passthroughVolumesPerLeftChannel, passthroughVolumesPerRightChannel = m_passthroughVolumesPerRightChannel, result = new NativeReference <Hash128>(Allocator.TempJob) }; job.Run(); m_hash = job.result.Value; job.result.Dispose(); m_computedHash = true; return(m_hash); }
public static string RelativePathInStreamingAssetsFolderFor(Hash128 sceneGUID, PathType type, int sectionIndex) { var extension = GetExtension(type); switch (type) { case PathType.EntitiesBinary: return($"SubScenes/{sceneGUID}.{sectionIndex}.{extension}"); case PathType.EntitiesHeader: return($"SubScenes/{sceneGUID}.{extension}"); case PathType.EntitiesUnityObjectReferences: return($"SubScenes/{sceneGUID}.{sectionIndex}.bundle"); default: throw new ArgumentException(); } }
void CalculateNumberOfLights(Hash128 sceneGuid) { //DOTSR-2180: There is still a bug to fix where if a subscene is loaded as a scene in the Editor instead of being loaded as part of a root scene, the build will unload it and create a new empty scene. //SubScene.UnloadScene here will be called on the subscene since we are closing the root scene it will unload the subscene without saving it first (so changes might be lost) and will load a new empty scene. using (var loadedScene = new LoadedSceneScope(sceneGuid)) { List <GameObject> rootObjectsInScene = new List <GameObject>(); loadedScene.ProjectScene.GetRootGameObjects(rootObjectsInScene); for (int i = 0; i < rootObjectsInScene.Count; i++) { var lights = rootObjectsInScene[i].GetComponentsInChildren <UnityEngine.Light>(true); foreach (var light in lights) { var cascadeComp = light.gameObject.GetComponent <Tiny.Authoring.CascadedShadowMappedLight>(); if (light.type == LightType.Directional || light.type == LightType.Point) { m_NumberOfPointOrDirLights++; } if (light.type == LightType.Directional || light.type == LightType.Spot) { if (light.shadows != LightShadows.None) { if (cascadeComp != null) { m_NumberOfCascadedShadowMappedLights++; } else { m_NumberOfShadowMappedLights++; } } } } var subScene = rootObjectsInScene[i].GetComponent <Unity.Scenes.SubScene>(); if (subScene != null && subScene.AutoLoadScene && subScene.SceneAsset != null) { CalculateNumberOfLights(subScene.SceneGUID); } } } }
unsafe public static EntityGuid GetEntityGuid(GameObject go, int index) { #if false var id = GlobalObjectId.GetGlobalObjectId(go); // For the time being use InstanceID until we support GlobalObjectID API //Debug.Log(id); var hash = Hash128.Compute($"{id}:{index}"); EntityGuid entityGuid; Assert.AreEqual(sizeof(EntityGuid), sizeof(Hash128)); UnsafeUtility.MemCpy(&entityGuid, &hash, sizeof(Hash128)); return(entityGuid); #else EntityGuid entityGuid; entityGuid.a = (ulong)go.GetInstanceID(); entityGuid.b = (ulong)index; return(entityGuid); #endif }
Scene GetExistingScene(Hash128 sceneGUID) { string scenePath = World.GetExistingSystem <SceneSystem>().GetScenePath(sceneGUID); // Try to find out scene amongst loaded scenes // TODO: https://unity3d.atlassian.net/browse/DOTS-3329 Scene gameObjectScene = default; for (int i = 0; i < SceneManager.sceneCount; i++) { var currentScene = SceneManager.GetSceneAt(i); if (currentScene.path == scenePath) { gameObjectScene = currentScene; break; } } return(gameObjectScene); }
public static string GetLoadPath(Hash128 sceneGUID, PathType type, int sectionIndex) { var extension = GetExtension(type); if (type == PathType.EntitiesBinary) { return($"{Application.streamingAssetsPath}/SubScenes/{sceneGUID}.{sectionIndex}.{extension}"); } else if (type == PathType.EntitiesHeader) { return($"{Application.streamingAssetsPath}/SubScenes/{sceneGUID}.{extension}"); } else if (type == PathType.EntitiesUnityObjectReferences) { return($"{Application.streamingAssetsPath}/SubScenes/{sceneGUID}.{sectionIndex}.bundle"); } else { return(""); } }
public static string GetLiveLinkCachePath(Hash128 targetHash, PathType type, int sectionIndex) { var extension = GetExtension(type); if (type == PathType.EntitiesBinary) { return($"{Application.persistentDataPath}/{targetHash}.{sectionIndex}.{extension}"); } else if (type == PathType.EntitiesHeader) { return($"{Application.persistentDataPath}/{targetHash}.{extension}"); } else if (type == PathType.EntitiesUnityObjectReferences) { return($"{Application.persistentDataPath}/{targetHash}.{sectionIndex}.refguids"); } else { return(""); } }
LiveLinkDiffGenerator(Scene scene, Hash128 sceneGUID, GUID buildConfigGUID, BuildConfiguration buildConfig, bool liveLinkEnabled) { _SceneGUID = sceneGUID; _Scene = scene; _buildConfigurationGUID = buildConfigGUID; _buildConfiguration = buildConfig; _LiveLinkEnabled = liveLinkEnabled; var worldFlags = WorldFlags.Editor | WorldFlags.Conversion | WorldFlags.Staging; _ConvertedWorld = new World($"Converted Scene: '{_Scene.name}", worldFlags); _LiveLinkDiffer = new EntityManagerDiffer(_ConvertedWorld.EntityManager, Allocator.Persistent); _IncrementalConversionChangeTracker = new IncrementalConversionChangeTracker(); #if UNITY_2020_2_OR_NEWER _IncrementalConversionDebug.World = new World($"Incremental Conversion Debug: '{_Scene.name}'", worldFlags); _IncrementalConversionDebug.BlobAssets = new BlobAssetCache(Allocator.Persistent); _IncrementalConversionDebug.BlobAssetStore = new BlobAssetStore(); #endif _RequestCleanConversion = true; var missingRenderDataQueryDesc = new EntityQueryDesc { All = new ComponentType[] { typeof(SceneTag) }, None = new ComponentType[] { typeof(EditorRenderData) }, Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled }; var missingSceneDataQueryDesc = new EntityQueryDesc { None = new ComponentType[] { typeof(SceneTag) }, Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled }; _MissingRenderDataQuery = _ConvertedWorld.EntityManager.CreateEntityQuery(missingRenderDataQueryDesc); _MissingSceneQuery = _ConvertedWorld.EntityManager.CreateEntityQuery(missingSceneDataQueryDesc); #if UNITY_2020_2_OR_NEWER _IncrementalConversionDebug.MissingRenderDataQuery = _IncrementalConversionDebug.World.EntityManager.CreateEntityQuery(missingRenderDataQueryDesc); _IncrementalConversionDebug.MissingSceneQuery = _IncrementalConversionDebug.World.EntityManager.CreateEntityQuery(missingSceneDataQueryDesc); #endif }
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); m_SceneWithBuildSettingsPath = SceneWithBuildConfigurationGUIDs.GetSceneWithBuildSettingsPath(ref guid); EntityScenesPaths.GetSubSceneArtifactHash(m_SceneGUID, m_BuildConfigurationGUID, ImportMode.Synchronous); } catch { AssetDatabase.DeleteAsset(m_TempPath); AssetDatabase.DeleteAsset(m_SceneWithBuildSettingsPath); throw; } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); #else //TODO: Playmode test not supported yet var sceneGuid = new Unity.Entities.Hash128(); #endif }
protected override void OnUpdate() { var ics = World.GetExistingSystem <IncrementalChangesSystem>(); if (ics.SceneGUID != _sceneGuid) { return; } _sceneGuid = default; ChangedGameObjects.AddRange(ics.IncomingChanges.ChangedGameObjects); Fill(ChangedGameObjectsInstanceIds, ics.IncomingChanges.ChangedGameObjectsInstanceIds); Fill(DeletedGameObjectInstanceIds, ics.IncomingChanges.RemovedGameObjectInstanceIds); ChangedComponents.AddRange(ics.IncomingChanges.ChangedComponents); void Fill(List <int> list, NativeArray <int> .ReadOnly data) { for (int i = 0; i < data.Length; i++) { list.Add(data[i]); } } }
public LiveLinkDiffGenerator(Hash128 sceneGUID, bool liveLinkEnabled) { _SceneName = Path.GetFileNameWithoutExtension(AssetDatabase.GUIDToAssetPath(sceneGUID.ToString())); _LiveLinkEnabled = liveLinkEnabled; _ConvertedWorld = new World($"Converted Scene: '{_SceneName}", WorldFlags.Editor | WorldFlags.Conversion | WorldFlags.Staging); _LiveLinkDiffer = new EntityManagerDiffer(_ConvertedWorld.EntityManager, Allocator.Persistent); _RequestCleanConversion = true; _MissingRenderDataQuery = _ConvertedWorld.EntityManager.CreateEntityQuery(new EntityQueryDesc { All = new ComponentType[] { typeof(SceneTag) }, None = new ComponentType[] { typeof(EditorRenderData) }, Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled }); _MissingSceneQuery = _ConvertedWorld.EntityManager.CreateEntityQuery(new EntityQueryDesc { None = new ComponentType[] { typeof(SceneTag) }, Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled }); }
public void UnloadScene(Hash128 sceneGUID) { var dstEntities = _DstWorld.EntityManager; var sceneSystem = _DstWorld.GetExistingSystem<SceneSystem>(); var sceneEntity = sceneSystem.GetSceneEntity(sceneGUID); dstEntities.RemoveComponent<DisableSceneResolveAndLoad>(sceneEntity); dstEntities.RemoveComponent<LiveLinkedSceneState>(sceneEntity); sceneSystem.UnloadScene(sceneEntity, SceneSystem.UnloadParameters.DestroySectionProxyEntities | SceneSystem.UnloadParameters.DontRemoveRequestSceneLoaded); // Cleanup leftover LiveLinkedScene system state // (This happens if the scene entity got destroyed) var job = new RemoveLiveLinkSceneState { DeleteGuid = sceneGUID, Commands = new EntityCommandBuffer(Allocator.TempJob) }; job.Run(_RemovedScenesQuery); job.Commands.Playback(dstEntities); job.Commands.Dispose(); }
void UpdateSceneContentsChanged(Hash128 buildConfigurationGUID) { #if UNITY_EDITOR var importCounter = UnityEditor.Experimental.AssetDatabaseExperimental.counters.import.imported.total; if (importCounter == m_LastNumImports) { return; } m_LastNumImports = importCounter; Entities.With(m_ResolvedScenes).ForEach((Entity sceneEntity, ref SceneReference scene, ref ResolvedSceneHash resolvedScene) => { LogResolving("Queuing UpdateSceneContentsChanged", scene.SceneGUID); var hash = EntityScenesPaths.GetSubSceneArtifactHash(scene.SceneGUID, buildConfigurationGUID, UnityEditor.Experimental.AssetDatabaseExperimental.ImportSyncMode.Queue); if ((hash != default) && (hash != resolvedScene.ArtifactHash)) { NotifySceneContentsHasChanged(scene.SceneGUID); } }); #endif if (m_ChangedScenes.Length != 0) { var sceneSystem = World.GetExistingSystem <SceneSystem>(); foreach (var scene in m_ChangedScenes) { var sceneEntity = sceneSystem.GetSceneEntity(scene); // Don't touch it if the scene is under live link control (@Todo: SubSceneStreamingSystem.IgnoreTag could be live link specific?) if (sceneEntity != Entity.Null && !EntityManager.HasComponent <DisableSceneResolveAndLoad>(sceneEntity)) { var unloadFlags = SceneSystem.UnloadParameters.DestroySectionProxyEntities | SceneSystem.UnloadParameters.DontRemoveRequestSceneLoaded; sceneSystem.UnloadScene(sceneEntity, unloadFlags); } } m_ChangedScenes.Clear(); } }
protected override void OnCreate() { #if UNITY_ANDROID var uwrFile = new UnityWebRequest(SceneSystem.GetBootStrapPath()); uwrFile.SendWebRequest(); while (!uwrFile.isDone) { } if (uwrFile.isNetworkError || uwrFile.isHttpError) { Enabled = false; } else { Enabled = true; } #else var bootstrapFilePath = GetBootStrapPath(); Enabled = File.Exists(bootstrapFilePath); #endif if (Enabled) { if (!UnityEngine.Networking.PlayerConnection.PlayerConnection.instance.isConnected) { Debug.LogError("Failed to connect to the Editor.\nAn Editor connection is required for LiveLink to work."); } using (var rdr = File.OpenText(bootstrapFilePath)) { var buildConfigurationGUID = new Hash128(rdr.ReadLine()); LiveLinkSessionId = long.Parse(rdr.ReadLine() ?? throw new Exception("Expected line in bootstrap containing session id!")); World.GetOrCreateSystem <SceneSystem>().BuildConfigurationGUID = buildConfigurationGUID; } } }
public void SetUpOnce() { if (m_TempAssets.TempAssetDir != null) { return; } m_TempAssets.SetUp(); var tempScene = SubSceneTestsHelper.CreateTmpScene(ref m_TempAssets); SubSceneTestsHelper.CreateSubSceneInSceneFromObjects("SubScene", false, tempScene, () => { var go = new GameObject(); var authoring = go.AddComponent <AuthoringWithUnmanaged>(); authoring.Value = 42; return(new List <GameObject> { go }); }); m_ScenePath = tempScene.path; m_SceneGUID = new GUID(AssetDatabase.AssetPathToGUID(m_ScenePath)); }
public static unsafe Hash128 CreateBuildSettingSceneFile(Hash128 sceneGUID, Hash128 buildSettingGUID) { var guids = new SceneWithBuildSettingsGUIDs { SceneGUID = sceneGUID, BuildSettings = buildSettingGUID }; Hash128 guid; guid.Value.x = math.hash(&guids, sizeof(SceneWithBuildSettingsGUIDs)); guid.Value.y = math.hash(&guids, sizeof(SceneWithBuildSettingsGUIDs), 0x96a755e2); guid.Value.z = math.hash(&guids, sizeof(SceneWithBuildSettingsGUIDs), 0x4e936206); guid.Value.w = math.hash(&guids, sizeof(SceneWithBuildSettingsGUIDs), 0xac602639); string dir = "Assets/SceneDependencyCache"; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } string fileName = $"{dir}/{guid}.sceneWithBuildSettings"; if (!File.Exists(fileName)) { using (var writer = new Entities.Serialization.StreamBinaryWriter(fileName)) { writer.WriteBytes(&guids, sizeof(SceneWithBuildSettingsGUIDs)); } File.WriteAllText(fileName + ".meta", $"fileFormatVersion: 2\nguid: {guid}\nDefaultImporter:\n externalObjects: {{}}\n userData:\n assetBundleName:\n assetBundleVariant:\n"); // Refresh is necessary because it appears the asset pipeline // can't depend on an asset on disk that has not yet been refreshed. AssetDatabase.Refresh(); } return(guid); }
public static LiveLinkChangeSet UpdateLiveLink(Scene scene, Hash128 sceneGUID, ref LiveLinkDiffGenerator liveLinkData, int sceneDirtyID, LiveLinkMode mode, BuildConfiguration config, out NativeArray <GUID> assetDependencies) { //Debug.Log("ApplyLiveLink: " + scene.SceneName); int framesToRetainBlobAssets = RetainBlobAssetsSetting.GetFramesToRetainBlobAssets(config); var liveLinkEnabled = mode != LiveLinkMode.Disabled; if (liveLinkData != null && liveLinkData._LiveLinkEnabled != liveLinkEnabled) { liveLinkData.Dispose(); liveLinkData = null; } var unloadAllPreviousEntities = liveLinkData == null; if (liveLinkData == null) { liveLinkData = new LiveLinkDiffGenerator(sceneGUID, liveLinkEnabled); } if (!liveLinkEnabled) { assetDependencies = default; return(new LiveLinkChangeSet { UnloadAllPreviousEntities = unloadAllPreviousEntities, SceneName = scene.name, SceneGUID = sceneGUID, FramesToRetainBlobAssets = framesToRetainBlobAssets }); } var flags = GameObjectConversionUtility.ConversionFlags.AddEntityGUID | GameObjectConversionUtility.ConversionFlags.AssignName | GameObjectConversionUtility.ConversionFlags.GameViewLiveLink; if (mode == LiveLinkMode.LiveConvertSceneView) { flags |= GameObjectConversionUtility.ConversionFlags.SceneViewLiveLink; } liveLinkData.Convert(scene, sceneGUID, flags, config, out assetDependencies); var convertedEntityManager = liveLinkData._ConvertedWorld.EntityManager; // We don't know the scene tag of the destination world, so we create a null Scene Tag. // In the patching code this will be translated into the final scene entity. convertedEntityManager.AddSharedComponentData(liveLinkData._MissingSceneQuery, new SceneTag { SceneEntity = Entity.Null }); #if UNITY_2020_1_OR_NEWER convertedEntityManager.AddSharedComponentData(liveLinkData._MissingRenderDataQuery, new EditorRenderData { SceneCullingMask = UnityEditor.SceneManagement.SceneCullingMasks.GameViewObjects, PickableObject = null }); #else convertedEntityManager.AddSharedComponentData(liveLinkData._MissingRenderDataQuery, new EditorRenderData { SceneCullingMask = EditorRenderData.LiveLinkEditGameViewMask, PickableObject = null }); #endif var options = EntityManagerDifferOptions.IncludeForwardChangeSet | EntityManagerDifferOptions.FastForwardShadowWorld | EntityManagerDifferOptions.ValidateUniqueEntityGuid | EntityManagerDifferOptions.ClearMissingReferences; var changes = new LiveLinkChangeSet { Changes = liveLinkData._LiveLinkDiffer.GetChanges(options, Allocator.TempJob).ForwardChangeSet, UnloadAllPreviousEntities = unloadAllPreviousEntities, SceneName = scene.name, SceneGUID = sceneGUID, FramesToRetainBlobAssets = framesToRetainBlobAssets }; liveLinkData.LiveLinkDirtyID = sceneDirtyID; // convertedEntityManager.Debug.CheckInternalConsistency(); return(changes); }
public void NotifySceneContentsHasChanged(Hash128 scene) { m_ChangedScenes.Add(scene); }
public static SceneData[] WriteEntityScene(Scene scene, Hash128 sceneGUID, ConversionFlags conversionFlags) { var world = new World("ConversionWorld"); var entityManager = world.EntityManager; ConvertScene(scene, sceneGUID, world, conversionFlags); EntitySceneOptimization.Optimize(world); var sceneSections = new List <SceneData>(); var subSectionList = new List <SceneSection>(); entityManager.GetAllUniqueSharedComponentData(subSectionList); 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.SetFilter(new SceneSection { SceneGUID = sceneGUID, Section = 0 }); sectionBoundsQuery.SetFilter(new SceneSection { SceneGUID = sceneGUID, Section = 0 }); entitiesInMainSection = sectionQuery.ToEntityArray(Allocator.TempJob); var bounds = GetBoundsAndDestroy(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] }); } 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); // 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 = WriteEntityScene(sectionManager, sceneGUID, "0"); sceneSections.Add(new SceneData { FileSize = sectionFileSize, SceneGUID = sceneGUID, SharedComponentCount = sectionManager.GetSharedComponentCount() - 1, 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.SetFilter(subSection); sectionBoundsQuery.SetFilter(subSection); var bounds = GetBoundsAndDestroy(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); // 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 = WriteEntityScene(sectionManager, sceneGUID, subSection.Section.ToString(), entityRemapping); sceneSections.Add(new SceneData { FileSize = fileSize, SceneGUID = sceneGUID, SharedComponentCount = sectionManager.GetSharedComponentCount() - 1, 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 } ); if (noSectionQuery.CalculateLength() != 0) { Debug.LogWarning($"{noSectionQuery.CalculateLength()} entities in the scene '{scene.path}' had no SceneSection and as a result were not serialized at all."); } } sectionQuery.Dispose(); sectionBoundsQuery.Dispose(); entitiesInMainSection.Dispose(); world.Dispose(); // Save the new header var header = ScriptableObject.CreateInstance <SubSceneHeader>(); header.Sections = sceneSections.ToArray(); WriteHeader(sceneGUID, header); return(sceneSections.ToArray()); }
string GetCachePath(Hash128 targetHash) { return($"{Application.persistentDataPath}/{targetHash}"); }
static NativeArray <Entity> GetActiveWorldSections(World world, Hash128 sceneGUID) { if (world == null || !world.IsCreated) { return(default);
void ResolveScene(Entity sceneEntity, ref SceneReference scene, RequestSceneLoaded requestSceneLoaded, Hash128 artifactHash) { // Resolve first (Even if the file doesn't exist we want to stop continously trying to load the section) EntityManager.AddBuffer <ResolvedSectionEntity>(sceneEntity); #if UNITY_EDITOR && !USE_SUBSCENE_EDITORBUNDLES EntityManager.AddComponentData(sceneEntity, new ResolvedSceneHash { ArtifactHash = artifactHash }); UnityEditor.Experimental.AssetDatabaseExperimental.GetArtifactPaths(artifactHash, out var paths); var sceneHeaderPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesHeader); #else var sceneHeaderPath = EntityScenesPaths.GetLoadPath(scene.SceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1); #endif if (!File.Exists(sceneHeaderPath)) { Debug.LogError($"Loading Entity Scene failed because the entity header file could not be found: {scene.SceneGUID}\n{sceneHeaderPath}"); return; } if (!BlobAssetReference <SceneMetaData> .TryRead(sceneHeaderPath, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef)) { Debug.LogError("Loading Entity Scene failed because the entity header file was an old version: " + scene.SceneGUID); return; } LogResolving("ResolveScene (success)", scene.SceneGUID); ref var sceneMetaData = ref sceneMetaDataRef.Value;
public static bool HasEntitySceneCache(Hash128 sceneGUID) { string headerPath = EntityScenesPaths.GetPathAndCreateDirectory(sceneGUID, EntityScenesPaths.PathType.EntitiesHeader, ""); return(File.Exists(headerPath)); }
void LogResolving(string type, Hash128 sceneGUID) { Debug.Log(type + ": " + sceneGUID); }
public ColliderInstanceId(Hash128 blobDataHash, int authoringComponentId) { BlobDataHash = blobDataHash; AuthoringComponentId = authoringComponentId; }