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();
            }
        }
Example #4
0
        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();
        }