public void ApplyPatch(LiveLinkChangeSet changeSet) { var dstEntities = _DstWorld.EntityManager; var sceneSystem = _DstWorld.GetExistingSystem<SceneSystem>(); Entity sectionEntity; var sceneEntity = sceneSystem.GetSceneEntity(changeSet.SceneGUID); //@TODO: Check if the scene or section is requested to be loaded if (sceneEntity == Entity.Null) { Debug.LogWarning($"'{changeSet.SceneName}' ({{changeSet.sceneGUID}}) was ignored in live link since it is not loaded."); return; } // Unload scene if (changeSet.UnloadAllPreviousEntities) { //@Todo: Can we try to keep scene & section entities alive? (In case user put custom data on it) sceneSystem.UnloadScene(sceneEntity, SceneSystem.UnloadParameters.DestroySectionProxyEntities | SceneSystem.UnloadParameters.DontRemoveRequestSceneLoaded); // Create section sectionEntity = dstEntities.CreateEntity(); dstEntities.AddComponentData(sectionEntity, new SceneSectionStreamingSystem.StreamingState { Status = SceneSectionStreamingSystem.StreamingStatus.Loaded}); dstEntities.AddComponentData(sectionEntity, new DisableSceneResolveAndLoad( )); // Configure scene dstEntities.AddComponentData(sceneEntity, new DisableSceneResolveAndLoad( )); dstEntities.AddComponentData(sceneEntity, new LiveLinkedSceneState { Scene = changeSet.SceneGUID }); dstEntities.AddBuffer<ResolvedSectionEntity>(sceneEntity).Add(new ResolvedSectionEntity { SectionEntity = sectionEntity} ); #if UNITY_EDITOR dstEntities.SetName(sectionEntity, "SceneSection (LiveLink): " + changeSet.SceneName); dstEntities.SetName(sceneEntity, "Scene (LiveLink): " + changeSet.SceneName); #endif } else { sectionEntity = dstEntities.GetBuffer<ResolvedSectionEntity>(sceneEntity)[0].SectionEntity; } // SceneTag.SceneEntity == Entity.Null is reserved for new entities added via live link. if (_AddedScenesQuery.CalculateChunkCount() != 0) { Debug.LogWarning("SceneTag.SceneEntity must not reference Entity.Null. Destroying Entities."); dstEntities.DestroyEntity(_AddedScenesQuery); } EntityPatcher.ApplyChangeSet(_DstWorld.EntityManager, changeSet.Changes); //liveLink.ConvertedShadowWorld.EntityManager.Debug.CheckInternalConsistency(); dstEntities.SetSharedComponentData(_AddedScenesQuery, new SceneTag { SceneEntity = sectionEntity }); EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); }
protected override void OnUpdate() { var destroySubScenes = new NativeList <Entity>(Allocator.Temp); var sceneDataFromEntity = GetComponentDataFromEntity <SceneSectionData>(); bool SceneSectionRequiresSynchronousLoading(Entity entity) => (EntityManager.GetComponentData <RequestSceneLoaded>(entity).LoadFlags & SceneLoadFlags.BlockOnStreamIn) != 0; // Sections > 0 need the external references from sections 0 and will wait for it to be loaded. // So we have to ensure sections 0 are loaded first, otherwise there's a risk of starving loading streams. var priorityList = new NativeList <Entity>(Allocator.Temp); using (var entities = m_PendingStreamRequests.ToEntityArray(Allocator.TempJob)) { var priorities = new NativeArray <int>(entities.Length, Allocator.Temp); for (int i = 0; i < entities.Length; ++i) { var entity = entities[i]; if (SceneSectionRequiresSynchronousLoading(entity)) { priorities[i] = 0; var operation = CreateAsyncLoadSceneOperation(m_SynchronousSceneLoadWorld.EntityManager, entity, true); var result = UpdateLoadOperation(operation, m_SynchronousSceneLoadWorld, entity); if (result == UpdateLoadOperationResult.Error) { m_SynchronousSceneLoadWorld.Dispose(); m_SynchronousSceneLoadWorld = new World("LoadingWorld (synchronous)"); } Assert.AreNotEqual(UpdateLoadOperationResult.Aborted, result); } else if (sceneDataFromEntity[entity].SubSectionIndex == 0) { priorities[i] = 1; } else { priorities[i] = 2; } } for (int priority = 1; priority <= 2; ++priority) { for (int i = 0; i < entities.Length; ++i) { if (priorityList.Length == LoadScenesPerFrame) { break; } if (priorities[i] == priority) { priorityList.Add(entities[i]); } } } } var priorityArray = priorityList.AsArray(); foreach (var entity in priorityArray) { var streamIndex = CreateAsyncLoadScene(entity, false); if (streamIndex != -1) { var streamingState = new StreamingState { ActiveStreamIndex = streamIndex, Status = StreamingStatus.NotYetProcessed }; EntityManager.AddComponentData(entity, streamingState); } } Entities.With(m_UnloadStreamRequests).ForEach((Entity entity) => { destroySubScenes.Add(entity); }); foreach (var destroyScene in destroySubScenes.AsArray()) { UnloadSectionImmediate(destroyScene); } if (ProcessActiveStreams()) { EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); } // Process unloading bundles SceneBundleHandle.ProcessUnloadingBundles(); }
protected override void OnUpdate() { SceneWithBuildConfigurationGUIDs.ValidateBuildSettingsCache(); var sceneSystem = World.GetExistingSystem <SceneSystem>(); var buildConfigurationGUID = sceneSystem.BuildConfigurationGUID; // Add scene entities that haven't been encountered yet if (!m_AddScenes.IsEmptyIgnoreFilter) { //@TODO: Should use Entities.ForEach but we are missing // 1. Entities.ForEach support with execute always (ILPP compilation not taking effect on first domain reload) // 2. Entities.ForEach not supporting explicit queries using (var addScenes = m_AddScenes.ToEntityArray(Allocator.TempJob)) { var trackerStates = new NativeArray <AssetDependencyTrackerState>(addScenes.Length, Allocator.Temp); for (int i = 0; i != addScenes.Length; i++) { var sceneEntity = addScenes[i]; var scene = EntityManager.GetComponentData <SceneReference>(sceneEntity); var requestSceneLoaded = EntityManager.GetComponentData <RequestSceneLoaded>(sceneEntity); var guid = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(scene.SceneGUID, buildConfigurationGUID, out var requireRefresh); var async = (requestSceneLoaded.LoadFlags & SceneLoadFlags.BlockOnImport) == 0; LogResolving(async ? "Adding Async" : "Adding Sync", guid); _AssetDependencyTracker.Add(guid, sceneEntity, async); if (requireRefresh) { _AssetDependencyTracker.RequestRefresh(); } trackerStates[i] = new AssetDependencyTrackerState { SceneAndBuildConfigGUID = guid }; } EntityManager.AddComponentData(m_AddScenes, trackerStates); trackerStates.Dispose(); } } // Remove scene entities that were added and should no longer be tracked if (!m_RemoveScenes.IsEmptyIgnoreFilter) { using (var removeEntities = m_RemoveScenes.ToEntityArray(Allocator.TempJob)) using (var removeGuids = m_RemoveScenes.ToComponentDataArray <AssetDependencyTrackerState>(Allocator.TempJob)) { for (int i = 0; i != removeEntities.Length; i++) { LogResolving("Removing", removeGuids[i].SceneAndBuildConfigGUID); _AssetDependencyTracker.Remove(removeGuids[i].SceneAndBuildConfigGUID, removeEntities[i]); } } EntityManager.RemoveComponent <AssetDependencyTrackerState>(m_RemoveScenes); } // Process any scenes that have completed their asset import var isDone = _AssetDependencyTracker.GetCompleted(_Changed); foreach (var change in _Changed) { var sceneEntity = change.UserKey; LogResolving($"Resolving: {change.Asset} -> {change.ArtifactID}"); if (!m_ValidSceneMask.Matches(sceneEntity)) { throw new InvalidOperationException("entity should have been removed from tracker already"); } // Unload any previous state var unloadFlags = SceneSystem.UnloadParameters.DestroySectionProxyEntities | SceneSystem.UnloadParameters.DontRemoveRequestSceneLoaded; sceneSystem.UnloadScene(sceneEntity, unloadFlags); // Resolve new state var scene = EntityManager.GetComponentData <SceneReference>(change.UserKey); var request = EntityManager.GetComponentData <RequestSceneLoaded>(change.UserKey); if (change.ArtifactID != default) { ResolveSceneSectionUtility.ResolveSceneSections(EntityManager, change.UserKey, scene.SceneGUID, request, change.ArtifactID); } else { Debug.LogError( $"Failed to import entity scene because the automatically generated SceneAndBuildConfigGUID asset was not present: '{AssetDatabaseCompatibility.GuidToPath(scene.SceneGUID)}' -> '{AssetDatabaseCompatibility.GuidToPath(change.Asset)}'"); } } if (!isDone) { EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); } }
protected override void OnUpdate() { var destroySubScenes = new NativeList <Entity>(Allocator.Temp); var sceneDataFromEntity = GetComponentDataFromEntity <SceneData>(); // Sections > 0 need the external references from sections 0 and will wait for it to be loaded. // So we have to ensure sections 0 are loaded first, otherwise there's a risk of starving loading streams. var priorityList = new NativeList <Entity>(Allocator.Temp); using (var entities = m_PendingStreamRequests.ToEntityArray(Allocator.TempJob)) { foreach (var entity in entities) { if (priorityList.Length == LoadScenesPerFrame) { break; } if (sceneDataFromEntity[entity].SubSectionIndex == 0) { priorityList.Add(entity); } } foreach (var entity in entities) { if (priorityList.Length == LoadScenesPerFrame) { break; } if (sceneDataFromEntity[entity].SubSectionIndex > 0) { priorityList.Add(entity); } } } var priorityArray = priorityList.AsArray(); foreach (var entity in priorityArray) { var streamIndex = CreateAsyncLoadScene(entity); if (streamIndex != -1) { var streamingState = new StreamingState { ActiveStreamIndex = streamIndex, Status = StreamingStatus.NotYetProcessed }; EntityManager.AddComponentData(entity, streamingState); } } Entities.With(m_UnloadStreamRequests).ForEach((Entity entity) => { destroySubScenes.Add(entity); }); foreach (var destroyScene in destroySubScenes.AsArray()) { UnloadSceneImmediate(destroyScene); } if (ProcessActiveStreams()) { EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); } }
public static void ApplyLiveLink(SubScene scene, World dstWorld, int sceneDirtyID, LiveLinkMode mode) { //Debug.Log("ApplyLiveLink: " + scene.SceneName); #if ENABLE_UNITY_COLLECTIONS_CHECKS if (mode == LiveLinkMode.Disabled) { throw new System.ArgumentException("LiveLinkMode must not be disabled"); } #endif // When switching mode, completely unload the previous scene if (scene.LiveLinkData != null && (scene.LiveLinkData._LiveLinkMode == LiveLinkMode.ConvertWithoutDiff || mode == LiveLinkMode.ConvertWithoutDiff || scene.LiveLinkData.DestinationWorld != dstWorld)) { scene.LiveLinkData.Dispose(); scene.LiveLinkData = null; } var unloadAllPreviousEntities = scene.LiveLinkData == null; if (scene.LiveLinkData == null) { scene.LiveLinkData = new LiveLinkScene(dstWorld, mode); } var liveLink = scene.LiveLinkData; var flags = GameObjectConversionUtility.ConversionFlags.AddEntityGUID | GameObjectConversionUtility.ConversionFlags.AssignName | GameObjectConversionUtility.ConversionFlags.GameViewLiveLink; if (mode == LiveLinkMode.LiveConvertSceneView) { flags |= GameObjectConversionUtility.ConversionFlags.SceneViewLiveLink; } liveLink.Convert(scene.LoadedScene, scene.SceneGUID, flags); var streamingSystem = dstWorld.GetExistingSystem <SubSceneStreamingSystem>(); var dstEntities = dstWorld.EntityManager; // Unload scene if (unloadAllPreviousEntities) { foreach (var s in scene._SceneEntities) { streamingSystem.UnloadSceneImmediate(s); dstEntities.DestroyEntity(s); } var sceneEntity = dstEntities.CreateEntity(); dstEntities.SetName(sceneEntity, "Scene (LiveLink): " + scene.SceneName); dstEntities.AddComponentObject(sceneEntity, scene); dstEntities.AddComponentData(sceneEntity, new SubSceneStreamingSystem.StreamingState { Status = SubSceneStreamingSystem.StreamingStatus.Loaded }); dstEntities.AddComponentData(sceneEntity, new SubSceneStreamingSystem.IgnoreTag( )); scene._SceneEntities = new List <Entity>(); scene._SceneEntities.Add(sceneEntity); } var convertedEntityManager = liveLink.ConvertedWorld.EntityManager; var liveLinkSceneEntity = scene._SceneEntities[0]; /// We want to let the live linked scene be able to reference the already existing Scene Entity (Specifically SceneTag should point to the scene Entity after live link completes) // Add Scene tag to all entities using the convertedSceneEntity that will map to the already existing scene entity. using (var missingSceneQuery = convertedEntityManager.CreateEntityQuery(new EntityQueryDesc { None = new ComponentType[] { typeof(SceneTag) }, Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled })) { convertedEntityManager.AddSharedComponentData(missingSceneQuery, new SceneTag { SceneEntity = liveLinkSceneEntity }); } if (mode != LiveLinkMode.ConvertWithoutDiff) { var options = EntityManagerDifferOptions.IncludeForwardChangeSet | EntityManagerDifferOptions.FastForwardShadowWorld | EntityManagerDifferOptions.ValidateUniqueEntityGuid | EntityManagerDifferOptions.ClearMissingReferences; using (var changes = liveLink.LiveLinkDiffer.GetChanges(options, Allocator.TempJob)) { liveLink.LiveLinkPatcher.ApplyChangeSet(changes.ForwardChangeSet); } } else { dstWorld.EntityManager.MoveEntitiesFrom(liveLink.ConvertedWorld.EntityManager); } // convertedEntityManager.Debug.CheckInternalConsistency(); //liveLink.ConvertedShadowWorld.EntityManager.Debug.CheckInternalConsistency(); using (var missingRenderData = dstEntities.CreateEntityQuery(new EntityQueryDesc { All = new ComponentType[] { typeof(SceneTag) }, None = new ComponentType[] { typeof(EditorRenderData) }, Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled })) { missingRenderData.SetFilter(new SceneTag { SceneEntity = liveLinkSceneEntity }); dstEntities.AddSharedComponentData(missingRenderData, new EditorRenderData() { SceneCullingMask = EditorRenderData.LiveLinkEditGameViewMask, PickableObject = scene.gameObject }); } liveLink.LiveLinkDirtyID = sceneDirtyID; EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); }