UndoPropertyModification[] PostprocessModifications(UndoPropertyModification[] modifications)
        {
            foreach (var mod in modifications)
            {
                var target = GetGameObjectFromAny(mod.currentValue.target);
                if (target)
                {
                    var liveLink = GetLiveLink(target.scene);
                    if (liveLink != null)
                    {
                        liveLink.AddChanged(target);
                        EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                    }
                }
            }

            if (m_AssetDependencies.Count() > 0)
            {
                foreach (var mod in modifications)
                {
                    AssetDatabase.TryGetGUIDAndLocalFileIdentifier(mod.currentValue.target, out var guid, out long _);
                    if (m_AssetDependencies.ContainsKey(new GUID(guid)))
                    {
                        GlobalDirtyLiveLink();
                        break;
                    }
                }
            }

            return(modifications);
        }
Ejemplo n.º 2
0
        UndoPropertyModification[] PostprocessModifications(UndoPropertyModification[] modifications)
        {
            foreach (var mod in modifications)
            {
                var target = GetGameObjectFromAny(mod.currentValue.target);
                if (target)
                {
                    var liveLink = GetLiveLink(target.scene);
                    if (liveLink != null)
                    {
                        liveLink.AddChanged(target);
                        EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                    }
                }
            }

            if (HasAssetDependencies())
            {
                foreach (var mod in modifications)
                {
                    if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(mod.currentValue.target, out var guidString, out long _))
                    {
                        continue;
                    }
                    var guid = new GUID(guidString);
                    foreach (var kvp in _SceneGUIDToLiveLink)
                    {
                        kvp.Value.MarkAssetChanged(guid);
                    }
                }
            }

            return(modifications);
        }
        UndoPropertyModification[] PostprocessModifications(UndoPropertyModification[] modifications)
        {
            if (LiveConversionSettings.IsFullyIncremental)
            {
                return(modifications);
            }

            foreach (var mod in modifications)
            {
                var target = GetGameObjectFromAny(mod.currentValue.target);
                if (target)
                {
                    var liveLink = GetLiveLink(target.scene);
                    if (liveLink != null)
                    {
                        liveLink.MarkChanged(target);
                        EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                    }
                }
            }

            if (HasAssetDependencies())
            {
                foreach (var mod in modifications)
                {
                    foreach (var kvp in _SceneGUIDToLiveLink)
                    {
                        kvp.Value.ChangeTracker.MarkAssetChanged(mod.currentValue.target.GetInstanceID());
                    }
                }
            }
            return(modifications);
        }
Ejemplo n.º 4
0
        void ConnectLiveLink(MessageEventArgs args)
        {
            LiveLinkMsg.LogReceived("ConnectLiveLink");

            int player        = args.playerId;
            var buildSettings = args.Receive <Hash128>();

            //@TODO: Implement this properly
            //system.World.GetExistingSystem<EditorSubSceneLiveLinkSystem>().CleanupAllScenes();

            //@TODO: How does this work with multiple connections?
            LiveLinkAssetBundleBuildSystem.instance.ClearUsedAssetsTargetHash();
            if (_Connections.TryGetValue(player, out var connection))
            {
                connection.Dispose();
            }

            var newConnection = new LiveLinkConnection(buildSettings);

            _Connections[player] = newConnection;

            TimeBasedCallbackInvoker.SetCallback(DetectSceneChanges);
            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();

            LiveLinkPlayerConnected?.Invoke(player, newConnection._BuildSettingsGUID);
        }
        void ConnectLiveLink(MessageEventArgs args)
        {
            LiveLinkMsg.LogReceived("ConnectLiveLink");

            int player = args.playerId;
            var buildConfigurationGuid = args.Receive <Hash128>();

            //@TODO: Implement this properly
            //system.World.GetExistingSystem<EditorSubSceneLiveLinkSystem>().CleanupAllScenes();

            //@TODO: How does this work with multiple connections?
            LiveLinkAssetBundleBuildSystem.instance.ClearTrackedAssets();
            if (_Connections.TryGetValue(player, out var connection))
            {
                connection.Dispose();
            }

            var newConnection = new LiveLinkConnection(buildConfigurationGuid);

            _Connections[player] = newConnection;
            using (var scenes = newConnection.GetInitialScenes(player, Allocator.Temp))
                m_Connection.SendArray(LiveLinkMsg.EditorResponseConnectLiveLink, scenes, player);

            TimeBasedCallbackInvoker.SetCallback(DetectSceneChanges);
            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();

            LiveLinkPlayerConnected?.Invoke(player, newConnection._BuildConfigurationGUID);
        }
Ejemplo n.º 6
0
        public static void Register(IEntityHierarchy hierarchy)
        {
            var system = World.DefaultGameObjectInjectionWorld.GetExistingSystem <EntityHierarchyDiffSystem>();

            system.DoRegister(hierarchy);

            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
        }
Ejemplo n.º 7
0
        void AddLiveLinkChangeSet(Hash128 sceneGUID, List <LiveLinkChangeSet> changeSets, LiveLinkMode mode)
        {
            var liveLink  = GetLiveLink(sceneGUID);
            var editScene = _GUIDToEditScene[sceneGUID];

            // The current behaviour is that we do incremental conversion until we release the hot control
            // This is to avoid any unexpected stalls
            // Optimally the undo system would tell us if only properties have changed, but currently we don't have such an event stream.
            var sceneDirtyID   = GetSceneDirtyID(editScene);
            var updateLiveLink = true;

            if (IsHotControlActive())
            {
                if (liveLink != null)
                {
                    sceneDirtyID = liveLink.LiveLinkDirtyID;
                }
                else
                {
                    updateLiveLink = false;
                    EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                }
            }
            else
            {
                if (liveLink != null && liveLink.LiveLinkDirtyID != sceneDirtyID)
                {
                    liveLink.RequestCleanConversion();
                }
            }

            if (updateLiveLink)
            {
                //@TODO: need one place that LiveLinkDiffGenerators are managed. UpdateLiveLink does a Dispose()
                // but this must be paired with membership in _SceneGUIDToLiveLink. not good to have multiple places
                // doing ownership management.
                //
                // also: when implementing an improvement to this, be sure to deal with exceptions, which can occur
                // during conversion.

                if (liveLink != null)
                {
                    _SceneGUIDToLiveLink.Remove(sceneGUID);
                }

                try
                {
                    changeSets.Add(LiveLinkDiffGenerator.UpdateLiveLink(editScene, sceneGUID, ref liveLink, sceneDirtyID, mode, _BuildSettings));
                }
                finally
                {
                    if (liveLink != null)
                    {
                        _SceneGUIDToLiveLink.Add(sceneGUID, liveLink);
                    }
                }
            }
        }
Ejemplo n.º 8
0
        protected override void OnFilterChanged(string filter)
        {
            var query = m_EntityHierarchyQueryBuilder.BuildQuery(filter, out var nameFilter);

            QueryDesc = query;
            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();

            m_EntityHierarchy.SetFilter(nameFilter);
        }
        static IEnumerator SkipAnEditorFrame()
        {
            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();

            // Yield twice to ensure EditorApplication.update was invoked before resuming.
            yield return(null);

            yield return(null);
        }
Ejemplo n.º 10
0
        public void SetSystemState(bool state)
        {
            if (Node.Enabled == state)
            {
                return;
            }

            Node.Enabled = state;
            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
        }
 void SceneOpened(Scene scene, OpenSceneMode mode)
 {
     {
         // @TODO: This is a temporary workaround until ObjectChangeEventStream handles this
         // When a scene is re-loaded, we need to re-convert it. This happens for example when the changes in a scene
         // are discarded.
         GetLiveLink(scene)?.RequestCleanConversion();
     }
     EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
 }
Ejemplo n.º 12
0
        public static void Unregister(IEntityHierarchy hierarchy)
        {
            if (!hierarchy.World.IsCreated)
            {
                return; // World was already disposed.
            }
            var system = World.DefaultGameObjectInjectionWorld.GetExistingSystem <EntityHierarchyDiffSystem>();

            system.DoUnregister(hierarchy);

            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
        }
        void AddLiveLinkChangeSet(ref LiveLinkDiffGenerator liveLink, Hash128 sceneGUID, List <LiveLinkChangeSet> changeSets, LiveLinkMode mode)
        {
            var editScene = _GUIDToEditScene[sceneGUID];

            int sceneDirtyID = 0;

#if !UNITY_2020_2_OR_NEWER
            // The current behaviour is that we do incremental conversion until we release the hot control
            // This is to avoid any unexpected stalls
            if (IsHotControlActive())
            {
                if (liveLink == null)
                {
                    EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                    return;
                }
                sceneDirtyID = liveLink.LiveLinkDirtyID;
            }
            else
            {
                sceneDirtyID = GetSceneDirtyID(editScene);
                if (liveLink != null && liveLink.LiveLinkDirtyID != sceneDirtyID)
                {
                    liveLink.RequestCleanConversion();
                }
            }
#endif

            //@TODO: need one place that LiveLinkDiffGenerators are managed. UpdateLiveLink does a Dispose()
            // but this must be paired with membership in _SceneGUIDToLiveLink. not good to have multiple places
            // doing ownership management.
            //
            // also: when implementing an improvement to this, be sure to deal with exceptions, which can occur
            // during conversion.

            if (liveLink != null)
            {
                _SceneGUIDToLiveLink.Remove(sceneGUID);
            }

            try
            {
                changeSets.Add(LiveLinkDiffGenerator.UpdateLiveLink(editScene, sceneGUID, ref liveLink, sceneDirtyID, mode, _BuildConfigurationGUID, _BuildConfiguration));
            }
            finally
            {
                if (liveLink != null)
                {
                    _SceneGUIDToLiveLink.Add(sceneGUID, liveLink);
                }
            }
        }
        protected override void OnComponentChanged(PropertyElement element, PropertyPath path)
        {
            var buffer    = element.GetTarget <InspectedBuffer <TList, TElement> >();
            var container = Container;

            if (container.IsReadOnly)
            {
                return;
            }

            PropertyContainer.SetValue(ref container, Path, buffer.Value);
            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
        }
Ejemplo n.º 15
0
        protected override void OnUpdate()
        {
            // Ugly hack to ensure the systems are called in editor
            var utcNow = DateTime.UtcNow;

            if (utcNow - s_LastUpdate >= k_RefreshPeriod)
            {
                s_LastUpdate = utcNow;
                EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
            }

            m_EntityHierarchy.OnUpdate();
        }
Ejemplo n.º 16
0
        UndoPropertyModification[] PostprocessModifications(UndoPropertyModification[] modifications)
        {
            foreach (var mod in modifications)
            {
                var target = GetGameObjectFromAny(mod.currentValue.target);
                if (target)
                {
                    var liveLink = GetLiveLink(target.scene);
                    if (liveLink != null)
                    {
                        liveLink.AddChanged(target);
                        EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                    }
                }
            }

            return(modifications);
        }
        UndoPropertyModification[] PostprocessModifications(UndoPropertyModification[] modifications)
        {
            foreach (var mod in modifications)
            {
                var target = GetGameObjectFromAny(mod.currentValue.target);
                if (target)
                {
                    var targetScene = target.scene;
                    Entities.ForEach((SubScene scene) =>
                    {
                        if (scene.LiveLinkData != null && scene.LoadedScene == targetScene)
                        {
                            scene.LiveLinkData.AddChanged(target);
                            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                        }
                    });
                }
            }

            return(modifications);
        }
Ejemplo n.º 18
0
        public override void OnInspectorGUI()
        {
            var subScene = target as SubScene;

            if (!subScene.IsInMainStage())
            {
                // In Prefab Mode and when selecting a Prefab Asset in the Project Browser we only show the inspector of data of the
                // SubScene, and not the load/unload/edit/close buttons.
                base.OnInspectorGUI();

                EditorGUILayout.HelpBox($"Only Sub Scenes in the Main Stage can be loaded and unloaded.", MessageType.Info, true);
                EditorGUILayout.Space();
                return;
            }

            var prevColor = subScene.HierarchyColor;

            CachePreviousSceneAssetReferences();

            base.OnInspectorGUI();

            HandleChangedSceneAssetReferences();

            if (subScene.HierarchyColor != prevColor)
            {
                SceneHierarchyHooks.ReloadAllSceneHierarchies();
            }

            var targetsArray = targets;
            var subscenes    = new SubScene[targetsArray.Length];

            targetsArray.CopyTo(subscenes, 0);

            GUILayout.BeginHorizontal();
            if (!SubSceneInspectorUtility.IsEditingAll(subscenes))
            {
                GUI.enabled = SubSceneInspectorUtility.CanEditScene(subscenes);
                if (GUILayout.Button("Edit"))
                {
                    SubSceneInspectorUtility.EditScene(subscenes);
                }
            }
            else
            {
                GUI.enabled = true;
                if (GUILayout.Button("Close"))
                {
                    SubSceneInspectorUtility.CloseAndAskSaveIfUserWantsTo(subscenes);
                }
            }

            GUI.enabled = SubSceneInspectorUtility.IsDirty(subscenes);
            if (GUILayout.Button("Save"))
            {
                SubSceneInspectorUtility.SaveScene(subscenes);
            }
            GUI.enabled = true;

            GUILayout.EndHorizontal();

            var scenes = SubSceneInspectorUtility.GetLoadableScenes(subscenes);

            GUILayout.Space(10);

            if (World.DefaultGameObjectInjectionWorld != null)
            {
                var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

                foreach (var scene in scenes)
                {
                    if (!entityManager.HasComponent <RequestSceneLoaded>(scene.Scene))
                    {
                        if (GUILayout.Button($"Load '{scene.Name}'"))
                        {
                            entityManager.AddComponentData(scene.Scene, new RequestSceneLoaded());
                            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                        }
                    }
                    else
                    {
                        if (GUILayout.Button($"Unload '{scene.Name}'"))
                        {
                            entityManager.RemoveComponent <RequestSceneLoaded>(scene.Scene);
                            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                        }
                    }
                }
            }

    #if false
            // @TODO: TEMP for debugging
            if (GUILayout.Button("ClearWorld"))
            {
                World.DisposeAllWorlds();
                DefaultWorldInitialization.Initialize("Default World", !Application.isPlaying);

                var scenes = FindObjectsOfType <SubScene>();
                foreach (var scene in scenes)
                {
                    var oldEnabled = scene.enabled;
                    scene.enabled = false;
                    scene.enabled = oldEnabled;
                }

                EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
            }
    #endif

            bool hasDuplicates = subScene.SceneAsset != null && (SubScene.AllSubScenes.Count(s => (s.SceneAsset == subScene.SceneAsset)) > 1);
            if (hasDuplicates)
            {
                EditorGUILayout.HelpBox($"The Scene Asset '{subScene.EditableScenePath}' is used mutiple times and this is not supported. Clear the reference.", MessageType.Warning, true);
                if (GUILayout.Button("Clear"))
                {
                    subScene.SceneAsset = null;
                    SceneHierarchyHooks.ReloadAllSceneHierarchies();
                }
                EditorGUILayout.Space();
            }

            var uncleanHierarchyObject = SubSceneInspectorUtility.GetUncleanHierarchyObject(subscenes);
            if (uncleanHierarchyObject != null)
            {
                EditorGUILayout.HelpBox($"Scene transform values are not applied to scenes child transforms. But {uncleanHierarchyObject.name} has an offset Transform.", MessageType.Warning, true);
                if (GUILayout.Button("Clear"))
                {
                    foreach (var scene in subscenes)
                    {
                        scene.transform.localPosition = Vector3.zero;
                        scene.transform.localRotation = Quaternion.identity;
                        scene.transform.localScale    = Vector3.one;
                    }
                }
                EditorGUILayout.Space();
            }
            if (SubSceneInspectorUtility.HasChildren(subscenes))
            {
                EditorGUILayout.HelpBox($"SubScenes can not have child game objects. Close the scene and delete the child game objects.", MessageType.Warning, true);
            }

            GUILayout.Space(10);
            if (CheckConversionLog(subScene))
            {
                GUILayout.Label("Importing...");
                Repaint();
            }
            else
            {
                if (!SubSceneInspectorUtility.IsEditingAll(subscenes))
                {
                    if (GUILayout.Button("Reimport"))
                    {
                        SubSceneInspectorUtility.ForceReimport(subscenes);
                    }
                }
            }
            if (m_ConversionLog.Length != 0)
            {
                GUILayout.Space(10);

                GUILayout.Label("Conversion Log");
                GUILayout.TextArea(m_ConversionLog);
            }
        }
        private static bool DrawClosedSubScenes(SubSceneInspectorUtility.LoadableScene[] loadableScenes, SubScene[] subscenes)
        {
            if (World.DefaultGameObjectInjectionWorld != null && loadableScenes.Length != 0)
            {
                GUILayout.Space(EditorGUIUtility.singleLineHeight);
                var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

                {
                    int numScenesLoaded   = 0;
                    int numScenesImported = 0;
                    foreach (var scene in loadableScenes)
                    {
                        if (entityManager.HasComponent <RequestSceneLoaded>(scene.Scene))
                        {
                            numScenesLoaded++;
                        }
                        if (IsSubsceneImported(scene.SubScene))
                        {
                            numScenesImported++;
                        }
                    }

                    if (EditorGUIUtility.wideMode)
                    {
                        GUILayout.BeginHorizontal();
                        GUILayout.Label(Content.ClosedSubScenesLabel, EditorStyles.boldLabel);
                        GUILayout.FlexibleSpace();
                        GUILayout.Label(string.Format(Content.ClosedStatusString, numScenesLoaded, loadableScenes.Length, numScenesImported));
                        GUILayout.EndHorizontal();
                    }
                    else
                    {
                        GUILayout.Label(Content.ClosedSubScenesLabel, EditorStyles.boldLabel);
                        GUILayout.BeginHorizontal();
                        GUILayout.FlexibleSpace();
                        GUILayout.Label(string.Format(Content.ClosedStatusString, numScenesLoaded, loadableScenes.Length, numScenesImported));
                        GUILayout.EndHorizontal();
                    }
                }

                if (loadableScenes.Length > 1)
                {
                    GUILayout.BeginHorizontal();
                    bool reimportRequested = GUILayout.Button(Content.ReimportAllLabel);

                    if (GUILayout.Button(Content.LoadAllLabel))
                    {
                        foreach (var scene in loadableScenes)
                        {
                            if (!entityManager.HasComponent <RequestSceneLoaded>(scene.Scene))
                            {
                                entityManager.AddComponentData(scene.Scene, new RequestSceneLoaded());
                            }
                        }

                        EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                    }

                    if (GUILayout.Button(Content.UnloadAllLabel))
                    {
                        foreach (var scene in loadableScenes)
                        {
                            if (entityManager.HasComponent <RequestSceneLoaded>(scene.Scene))
                            {
                                entityManager.RemoveComponent <RequestSceneLoaded>(scene.Scene);
                            }
                        }
                        EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                    }

                    GUILayout.EndHorizontal();

                    if (reimportRequested && EditorUtility.DisplayDialog(Content.ReimportAllSubScenes, Content.ReimportAllSubScenesDetails, Content.Yes, Content.No))
                    {
                        SubSceneInspectorUtility.ForceReimport(subscenes);
                    }

                    GUILayout.Space(EditorGUIUtility.standardVerticalSpacing);
                }

                bool needsRepaint = false;
                foreach (var scene in loadableScenes)
                {
                    s_TmpContent.text    = scene.Name;
                    s_TmpContent.tooltip = scene.SubScene.EditableScenePath;

                    var buttonRect = DrawButtonGridLabelAndGetFirstButtonRect(s_TmpContent, 3, out var spacing);

                    if (!IsSubsceneImported(scene.SubScene))
                    {
                        GUI.Label(buttonRect, Content.ImportingLabel);
                        needsRepaint = true;
                    }
                    else if (GUI.Button(buttonRect, Content.ReimportLabel))
                    {
                        SubSceneInspectorUtility.ForceReimport(scene.SubScene);
                    }

                    buttonRect.x += buttonRect.width + spacing;
                    if (!entityManager.HasComponent <RequestSceneLoaded>(scene.Scene))
                    {
                        if (GUI.Button(buttonRect, Content.LoadLabel))
                        {
                            entityManager.AddComponentData(scene.Scene, new RequestSceneLoaded());
                            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                        }
                    }
                    else
                    {
                        if (GUI.Button(buttonRect, Content.UnloadLabel))
                        {
                            entityManager.RemoveComponent <RequestSceneLoaded>(scene.Scene);
                            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                        }
                    }

                    buttonRect.x += buttonRect.width + spacing;
                    using (new EditorGUI.DisabledScope(!SubSceneInspectorUtility.CanEditScene(scene.SubScene)))
                    {
                        if (GUI.Button(buttonRect, Content.OpenLabel))
                        {
                            SubSceneInspectorUtility.EditScene(scene.SubScene);
                        }
                    }
                }

                return(needsRepaint);
            }

            return(false);
        }
        protected override void OnUpdate()
        {
            List <SubScene> needLiveLinkSync              = null;
            List <SubScene> cleanupScene                  = null;
            List <SubScene> markSceneLoadedFromLiveLink   = null;
            List <SubScene> removeSceneLoadedFromLiveLink = null;

            m_EditingSceneAssets.Clear();

            var liveLinkEnabled = SubSceneInspectorUtility.LiveLinkEnabled;

            // By default all scenes need to have m_GameObjectSceneCullingMask, otherwise they won't show up in game view
            for (int i = 0; i != EditorSceneManager.sceneCount; i++)
            {
                var scene = EditorSceneManager.GetSceneAt(i);
                if (scene.isSubScene)
                {
                    if (liveLinkEnabled)
                    {
                        EditorSceneManager.SetSceneCullingMask(scene, m_LiveLinkEditSceneViewMask);
                    }
                    else
                    {
                        EditorSceneManager.SetSceneCullingMask(scene, EditorSceneManager.DefaultSceneCullingMask | m_LiveLinkEditGameViewMask);
                    }

                    var sceneAsset = AssetDatabase.LoadAssetAtPath <SceneAsset>(scene.path);
                    if (scene.isLoaded && sceneAsset != null)
                    {
                        m_EditingSceneAssets.Add(sceneAsset);
                    }
                }
            }

            if (PreviousGlobalDirtyID != GlobalDirtyID)
            {
                Entities.ForEach((SubScene subScene) =>
                {
                    subScene.LiveLinkDirtyID = -1;
                });
                PreviousGlobalDirtyID = GlobalDirtyID;
            }

            Entities.ForEach((SubScene subScene) =>
            {
                var isLoaded = m_EditingSceneAssets.Contains(subScene.SceneAsset);
                // We are editing with live link. Ensure it is active & up to date
                if (isLoaded && liveLinkEnabled)
                {
                    if (subScene.LiveLinkDirtyID != GetSceneDirtyID(subScene.LoadedScene) || subScene.LiveLinkShadowWorld == null)
                    {
                        AddUnique(ref needLiveLinkSync, subScene);
                    }
                }
                // We are editing without live link.
                // We should have no entity representation loaded for the scene.
                else if (isLoaded && !liveLinkEnabled)
                {
                    var hasAnythingLoaded = false;
                    foreach (var s in subScene._SceneEntities)
                    {
                        hasAnythingLoaded |= EntityManager.HasComponent <SubSceneStreamingSystem.StreamingState>(s) || !EntityManager.HasComponent <SubSceneStreamingSystem.IgnoreTag>(s);
                    }

                    if (hasAnythingLoaded)
                    {
                        AddUnique(ref cleanupScene, subScene);
                        AddUnique(ref markSceneLoadedFromLiveLink, subScene);
                    }
                }
                // Scene is not being edited, thus should not be live linked.
                else
                {
                    var isDrivenByLiveLink = false;
                    foreach (var s in subScene._SceneEntities)
                    {
                        isDrivenByLiveLink |= EntityManager.HasComponent <SubSceneStreamingSystem.IgnoreTag>(s);
                    }

                    if (isDrivenByLiveLink || subScene.LiveLinkShadowWorld != null)
                    {
                        AddUnique(ref cleanupScene, subScene);
                        AddUnique(ref removeSceneLoadedFromLiveLink, subScene);
                    }
                }
            });

            if (needLiveLinkSync != null)
            {
                // Live link changes to entity world
                foreach (var scene in needLiveLinkSync)
                {
                    // Prevent live link updating during drag operation
                    // (Currently performance is not good enough to do it completely live)
                    if (!IsHotControlActive())
                    {
                        ApplyLiveLink(scene);
                    }
                    else
                    {
                        EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                    }
                }
            }


            if (cleanupScene != null)
            {
                // Live link changes to entity world
                foreach (var scene in cleanupScene)
                {
                    CleanupScene(scene);
                }
            }

            if (markSceneLoadedFromLiveLink != null)
            {
                foreach (var scene in markSceneLoadedFromLiveLink)
                {
                    foreach (var sceneEntity in scene._SceneEntities)
                    {
                        if (!EntityManager.HasComponent <SubSceneStreamingSystem.IgnoreTag>(sceneEntity))
                        {
                            EntityManager.AddComponentData(sceneEntity, new SubSceneStreamingSystem.IgnoreTag());
                        }
                    }
                }
            }

            if (removeSceneLoadedFromLiveLink != null)
            {
                foreach (var scene in removeSceneLoadedFromLiveLink)
                {
                    foreach (var sceneEntity in scene._SceneEntities)
                    {
                        EntityManager.RemoveComponent <SubSceneStreamingSystem.IgnoreTag>(sceneEntity);
                    }
                }
            }
        }
        void ApplyLiveLink(SubScene scene)
        {
            //Debug.Log("ApplyLiveLink: " + scene.SceneName);

            var streamingSystem = World.GetExistingManager <SubSceneStreamingSystem>();

            var isFirstTime = scene.LiveLinkShadowWorld == null;

            if (scene.LiveLinkShadowWorld == null)
            {
                scene.LiveLinkShadowWorld = new World("LiveLink");
            }


            using (var cleanConvertedEntityWorld = new World("Clean Entity Conversion World"))
            {
                // Unload scene
                //@TODO: We optimally shouldn't be unloading the scene here. We should simply prime the shadow world with the scene that we originally loaded into the player (Including Entity GUIDs)
                //       This way we can continue the live link, compared to exactly what we loaded into the player.
                if (isFirstTime)
                {
                    foreach (var s in scene._SceneEntities)
                    {
                        streamingSystem.UnloadSceneImmediate(s);
                        EntityManager.DestroyEntity(s);
                    }

                    var sceneEntity = EntityManager.CreateEntity();
                    EntityManager.SetName(sceneEntity, "Scene (LiveLink): " + scene.SceneName);
                    EntityManager.AddComponentObject(sceneEntity, scene);
                    EntityManager.AddComponentData(sceneEntity, new SubSceneStreamingSystem.StreamingState {
                        Status = SubSceneStreamingSystem.StreamingStatus.Loaded
                    });
                    EntityManager.AddComponentData(sceneEntity, new SubSceneStreamingSystem.IgnoreTag( ));

                    scene._SceneEntities = new List <Entity>();
                    scene._SceneEntities.Add(sceneEntity);
                }

                // Convert scene
                GameObjectConversionUtility.ConvertScene(scene.LoadedScene, scene.SceneGUID, cleanConvertedEntityWorld, GameObjectConversionUtility.ConversionFlags.AddEntityGUID | GameObjectConversionUtility.ConversionFlags.AssignName);

                var convertedEntityManager = cleanConvertedEntityWorld.GetOrCreateManager <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.
                convertedEntityManager.AddSharedComponentData(convertedEntityManager.UniversalGroup, new SceneTag {
                    SceneEntity = liveLinkSceneEntity
                });

                WorldDiffer.DiffAndApply(cleanConvertedEntityWorld, scene.LiveLinkShadowWorld, World);

                convertedEntityManager.Debug.CheckInternalConsistency();
                scene.LiveLinkShadowWorld.GetOrCreateManager <EntityManager>().Debug.CheckInternalConsistency();

                var group = EntityManager.CreateComponentGroup(typeof(SceneTag), ComponentType.Exclude <EditorRenderData>());
                group.SetFilter(new SceneTag {
                    SceneEntity = liveLinkSceneEntity
                });

                EntityManager.AddSharedComponentData(group, new EditorRenderData()
                {
                    SceneCullingMask = m_LiveLinkEditGameViewMask, PickableObject = scene.gameObject
                });

                group.Dispose();

                scene.LiveLinkDirtyID = GetSceneDirtyID(scene.LoadedScene);
                EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
            }
        }
        public override void OnInspectorGUI()
        {
            var subScene = target as SubScene;

            var prevSceneAsset = subScene.SceneAsset;
            var prevColor      = subScene.HierarchyColor;

            base.OnInspectorGUI();

            if (subScene.SceneAsset != prevSceneAsset || subScene.HierarchyColor != prevColor)
            {
                SceneHierarchyHooks.ReloadAllSceneHierarchies();
            }

            var targetsArray = targets;
            var subscenes    = new SubScene[targetsArray.Length];

            targetsArray.CopyTo(subscenes, 0);


            EditorGUILayout.TextArea("", GUI.skin.horizontalSlider);

            GUILayout.BeginHorizontal();
            if (!SubSceneInspectorUtility.IsEditingAll(subscenes))
            {
                GUI.enabled = SubSceneInspectorUtility.CanEditScene(subscenes);
                if (GUILayout.Button("Edit"))
                {
                    SubSceneInspectorUtility.EditScene(subscenes);
                }
            }
            else
            {
                GUI.enabled = true;
                if (GUILayout.Button("Close"))
                {
                    SubSceneInspectorUtility.CloseAndAskSaveIfUserWantsTo(subscenes);
                }
            }


            GUI.enabled = SubSceneInspectorUtility.IsDirty(subscenes);
            if (GUILayout.Button("Save"))
            {
                SubSceneInspectorUtility.SaveScene(subscenes);
            }
            GUI.enabled = true;

            GUILayout.EndHorizontal();

            var scenes = SubSceneInspectorUtility.GetLoadableScenes(subscenes);

            EditorGUILayout.TextArea("", GUI.skin.horizontalSlider);

            GUILayout.Space(10);

            if (World.DefaultGameObjectInjectionWorld != null)
            {
                var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

                foreach (var scene in scenes)
                {
                    if (!entityManager.HasComponent <RequestSceneLoaded>(scene.Scene))
                    {
                        if (GUILayout.Button($"Load '{scene.Name}'"))
                        {
                            entityManager.AddComponentData(scene.Scene, new RequestSceneLoaded());
                            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                        }
                    }
                    else
                    {
                        if (GUILayout.Button($"Unload '{scene.Name}'"))
                        {
                            entityManager.RemoveComponent <RequestSceneLoaded>(scene.Scene);
                            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                        }
                    }
                }
            }


    #if false
            // @TODO: TEMP for debugging
            if (GUILayout.Button("ClearWorld"))
            {
                World.DisposeAllWorlds();
                DefaultWorldInitialization.Initialize("Default World", !Application.isPlaying);

                var scenes = FindObjectsOfType <SubScene>();
                foreach (var scene in scenes)
                {
                    var oldEnabled = scene.enabled;
                    scene.enabled = false;
                    scene.enabled = oldEnabled;
                }

                EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
            }
    #endif

            var uncleanHierarchyObject = SubSceneInspectorUtility.GetUncleanHierarchyObject(subscenes);
            if (uncleanHierarchyObject != null)
            {
                EditorGUILayout.HelpBox($"Scene transform values are not applied to scenes child transforms. But {uncleanHierarchyObject.name} has an offset Transform.", MessageType.Warning, true);
                if (GUILayout.Button("Clear"))
                {
                    foreach (var scene in subscenes)
                    {
                        scene.transform.localPosition = Vector3.zero;
                        scene.transform.localRotation = Quaternion.identity;
                        scene.transform.localScale    = Vector3.one;
                    }
                }
            }
            if (SubSceneInspectorUtility.HasChildren(subscenes))
            {
                EditorGUILayout.HelpBox($"SubScenes can not have child game objects. Close the scene and delete the child game objects.", MessageType.Warning, true);
            }

            if (CheckConversionLog(subScene))
            {
                GUILayout.Space(10);
                GUILayout.Label("Importing...");
                Repaint();
            }
            if (m_ConversionLog.Length != 0)
            {
                GUILayout.Space(10);

                GUILayout.Label("Conversion Log");
                GUILayout.TextArea(m_ConversionLog);
            }
        }
        public void Update(List <LiveLinkChangeSet> changeSets, NativeList <Hash128> loadScenes, NativeList <Hash128> unloadScenes, LiveLinkMode mode)
        {
            if (_LoadedScenes.Count == 0 && _SceneGUIDToLiveLink.Count == 0 && _RemovedScenes.Length == 0)
            {
                return;
            }

            // If build configuration changed, we need to trigger a full conversion
            if (_BuildConfigurationGUID != default)
            {
                var buildConfigurationDependencyHash = AssetDatabaseCompatibility.GetAssetDependencyHash(_BuildConfigurationGUID);
                if (_BuildConfigurationArtifactHash != buildConfigurationDependencyHash)
                {
                    _BuildConfigurationArtifactHash = buildConfigurationDependencyHash;
                    RequestCleanConversion();
                }
            }

            if (_PreviousGlobalDirtyID != GlobalDirtyID)
            {
                RequestCleanConversion();
                _PreviousGlobalDirtyID = GlobalDirtyID;
            }

            // By default all scenes need to have m_GameObjectSceneCullingMask, otherwise they won't show up in game view
            _GUIDToEditScene.Clear();
            for (int i = 0; i != EditorSceneManager.sceneCount; i++)
            {
                var scene     = EditorSceneManager.GetSceneAt(i);
                var sceneGUID = AssetDatabaseCompatibility.PathToGUID(scene.path);

                if (_LoadedScenes.Contains(sceneGUID))
                {
                    if (scene.isLoaded && sceneGUID != default(GUID))
                    {
                        _GUIDToEditScene.Add(sceneGUID, scene);
                    }
                }
            }

            foreach (var scene in _SceneGUIDToLiveLink)
            {
                if (!_GUIDToEditScene.ContainsKey(scene.Key))
                {
                    unloadScenes.Add(scene.Key);
                }
            }

            // Process scenes that are no longer loaded
            foreach (var scene in unloadScenes)
            {
                var liveLink = _SceneGUIDToLiveLink[scene];
                liveLink.Dispose();
                _SceneGUIDToLiveLink.Remove(scene);
                _SentLoadScenes.Remove(scene);
            }
            foreach (var scene in _RemovedScenes)
            {
                if (_SceneGUIDToLiveLink.TryGetValue(scene, out var liveLink))
                {
                    liveLink.Dispose();
                    _SceneGUIDToLiveLink.Remove(scene);
                }

                unloadScenes.Add(scene);
                _SentLoadScenes.Remove(scene);
            }
            _RemovedScenes.Clear();

            _SentLoadScenes.RemoveWhere(scene => !_LoadedScenes.Contains(scene));

            // Process all scenes that the player needs
            var conversionMode = LiveConversionSettings.Mode;

            foreach (var sceneGuid in _LoadedScenes)
            {
                var isLoaded = _GUIDToEditScene.TryGetValue(sceneGuid, out var scene);

                // We are editing with live link. Ensure it is active & up to date
                if (isLoaded)
                {
                    var liveLink = GetLiveLink(sceneGuid);

                    if (liveLink == null || liveLink.DidRequestUpdate())
                    {
                        AddLiveLinkChangeSet(ref liveLink, sceneGuid, changeSets, mode);
                    }
#if !UNITY_2020_2_OR_NEWER
                    else if (liveLink.LiveLinkDirtyID != GetSceneDirtyID(scene))
                    {
                        AddLiveLinkChangeSet(ref liveLink, sceneGuid, changeSets, mode);
                    }
#endif

#if UNITY_2020_2_OR_NEWER
                    if (conversionMode == LiveConversionSettings.ConversionMode.IncrementalConversionWithDebug)
                    {
                        if (liveLink != null && liveLink.DidRequestDebugConversion())
                        {
                            if (IsHotControlActive())
                            {
                                EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                            }
                            else
                            {
                                liveLink.DebugIncrementalConversion();
                            }
                        }
                    }
#endif
                }
                else
                {
                    if (_SentLoadScenes.Add(sceneGuid))
                    {
                        loadScenes.Add(sceneGuid);
                    }
                }
            }
        }
 public static void GlobalDirtyLiveLink()
 {
     GlobalDirtyID++;
     EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
 }
        public override void OnInspectorGUI()
        {
            var subScene = target as SubScene;

            if (!subScene.IsInMainStage())
            {
                // In Prefab Mode and when selecting a Prefab Asset in the Project Browser we only show the inspector of data of the
                // SubScene, and not the load/unload/edit/close buttons.
                base.OnInspectorGUI();

                EditorGUILayout.HelpBox($"Only Sub Scenes in the Main Stage can be loaded and unloaded.", MessageType.Info, true);
                EditorGUILayout.Space();
                return;
            }

            var prevColor = subScene.HierarchyColor;

            CachePreviousSceneAssetReferences();

            base.OnInspectorGUI();

            HandleChangedSceneAssetReferences();

            if (subScene.HierarchyColor != prevColor)
            {
                SceneHierarchyHooks.ReloadAllSceneHierarchies();
            }

            DrawOpenSubScenes(_selectedSubscenes);
            var loadableScenes = SubSceneInspectorUtility.GetLoadableScenes(_selectedSubscenes);

            if (DrawClosedSubScenes(loadableScenes, _selectedSubscenes))
            {
                Repaint();
            }

#if false
            // @TODO: TEMP for debugging
            if (GUILayout.Button("ClearWorld"))
            {
                World.DisposeAllWorlds();
                DefaultWorldInitialization.Initialize("Default World", !Application.isPlaying);

                var scenes = FindObjectsOfType <SubScene>();
                foreach (var scene in scenes)
                {
                    var oldEnabled = scene.enabled;
                    scene.enabled = false;
                    scene.enabled = oldEnabled;
                }

                EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
            }
    #endif

            bool hasDuplicates = subScene.SceneAsset != null && (SubScene.AllSubScenes.Count(s => (s.SceneAsset == subScene.SceneAsset)) > 1);
            if (hasDuplicates)
            {
                EditorGUILayout.HelpBox($"The Scene Asset '{subScene.EditableScenePath}' is used mutiple times and this is not supported. Clear the reference.", MessageType.Warning, true);
                if (GUILayout.Button("Clear"))
                {
                    subScene.SceneAsset = null;
                    SceneHierarchyHooks.ReloadAllSceneHierarchies();
                }
                EditorGUILayout.Space();
            }

            var uncleanHierarchyObject = SubSceneInspectorUtility.GetUncleanHierarchyObject(_selectedSubscenes);
            if (uncleanHierarchyObject != null)
            {
                EditorGUILayout.HelpBox($"Scene transform values are not applied to scenes child transforms. But {uncleanHierarchyObject.name} has an offset Transform.", MessageType.Warning, true);
                if (GUILayout.Button("Clear"))
                {
                    foreach (var scene in _selectedSubscenes)
                    {
                        scene.transform.localPosition = Vector3.zero;
                        scene.transform.localRotation = Quaternion.identity;
                        scene.transform.localScale    = Vector3.one;
                    }
                }
                EditorGUILayout.Space();
            }
            if (SubSceneInspectorUtility.HasChildren(_selectedSubscenes))
            {
                EditorGUILayout.HelpBox($"SubScenes can not have child game objects. Close the scene and delete the child game objects.", MessageType.Warning, true);
            }

            if (targets.Length == 1)
            {
                GUILayout.Space(EditorGUIUtility.singleLineHeight);
                if (CheckConversionLog(subScene))
                {
                    GUILayout.Label("Importing...");
                    Repaint();
                }

                if (m_ConversionLog.Length != 0)
                {
                    GUILayout.Space(EditorGUIUtility.singleLineHeight);

                    GUILayout.Label("Conversion Log", EditorStyles.boldLabel);
                    GUILayout.TextArea(m_ConversionLog);
                }
            }
        }
        void OnEditorChangeEvents(ref ObjectChangeEventStream stream)
        {
            for (int i = 0; i < stream.length; i++)
            {
                var type = stream.GetEventType(i);
                switch (type)
                {
                case ObjectChangeKind.None:
                    break;

                case ObjectChangeKind.ChangeScene:
                {
                    stream.GetChangeSceneEvent(i, out var evt);
                    if (evt.scene.IsValid())
                    {
                        GetLiveLink(evt.scene)?.RequestCleanConversion();
                    }
                    break;
                }

                case ObjectChangeKind.CreateGameObjectHierarchy:
                {
                    stream.GetCreateGameObjectHierarchyEvent(i, out var evt);
                    GetLiveLink(evt.scene)?.ChangeTracker.MarkReconvertHierarchy(evt.instanceId);
                    break;
                }

                case ObjectChangeKind.ChangeGameObjectStructureHierarchy:
                {
                    stream.GetChangeGameObjectStructureHierarchyEvent(i, out var evt);
                    GetLiveLink(evt.scene)?.ChangeTracker.MarkReconvertHierarchy(evt.instanceId);
                    break;
                }

                case ObjectChangeKind.ChangeGameObjectStructure:
                {
                    stream.GetChangeGameObjectStructureEvent(i, out var evt);
                    GetLiveLink(evt.scene)?.ChangeTracker.MarkChanged(evt.instanceId);
                    break;
                }

                case ObjectChangeKind.ChangeGameObjectParent:
                {
                    stream.GetChangeGameObjectParentEvent(i, out var evt);
                    if (evt.newScene != evt.previousScene)
                    {
                        GetLiveLink(evt.newScene)?.ChangeTracker.MarkReconvertHierarchy(evt.instanceId);
                        GetLiveLink(evt.previousScene)?.ChangeTracker.MarkRemoved(evt.instanceId);
                    }
                    else
                    {
                        GetLiveLink(evt.newScene)?.ChangeTracker.MarkParentChanged(evt.instanceId, evt.newParentInstanceId);
                    }
                    break;
                }

                case ObjectChangeKind.ChangeGameObjectOrComponentProperties:
                {
                    stream.GetChangeGameObjectOrComponentPropertiesEvent(i, out var evt);
                    var target = EditorUtility.InstanceIDToObject(evt.instanceId);
                    if (target is Component c)
                    {
                        GetLiveLink(evt.scene)?.ChangeTracker.MarkComponentChanged(c);
                    }
                    else
                    {
                        GetLiveLink(evt.scene)?.ChangeTracker.MarkChanged(evt.instanceId);
                    }
                    break;
                }

                case ObjectChangeKind.DestroyGameObjectHierarchy:
                {
                    stream.GetDestroyGameObjectHierarchyEvent(i, out var evt);
                    GetLiveLink(evt.scene)?.ChangeTracker.MarkRemoved(evt.instanceId);
                    break;
                }

                case ObjectChangeKind.CreateAssetObject:
                {
                    stream.GetCreateAssetObjectEvent(i, out var evt);
                    MarkAssetChanged(evt.instanceId, evt.scene);
                    break;
                }

                case ObjectChangeKind.DestroyAssetObject:
                {
                    stream.GetDestroyAssetObjectEvent(i, out var evt);
                    MarkAssetChanged(evt.instanceId, evt.scene);
                    break;
                }

                case ObjectChangeKind.ChangeAssetObjectProperties:
                {
                    stream.GetChangeAssetObjectPropertiesEvent(i, out var evt);
                    MarkAssetChanged(evt.instanceId, evt.scene);
                    break;
                }

                case ObjectChangeKind.UpdatePrefabInstances:
                {
                    stream.GetUpdatePrefabInstancesEvent(i, out var evt);
                    var diffGenerator = GetLiveLink(evt.scene);
                    if (diffGenerator != null)
                    {
                        for (int k = 0; k < evt.instanceIds.Length; k++)
                        {
                            diffGenerator.ChangeTracker.MarkReconvertHierarchy(evt.instanceIds[k]);
                        }
                    }
                    break;
                }

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
        }
 void SceneClosed(Scene scene)
 {
     EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
 }
        protected override void OnUpdate()
        {
            List <SubScene> needLiveLinkSync              = null;
            List <SubScene> cleanupScene                  = null;
            List <SubScene> markSceneLoadedFromLiveLink   = null;
            List <SubScene> removeSceneLoadedFromLiveLink = null;

            m_EditingSceneAssets.Clear();

            var liveLinkEnabled = SubSceneInspectorUtility.LiveLinkMode != LiveLinkMode.Disabled;

            // By default all scenes need to have m_GameObjectSceneCullingMask, otherwise they won't show up in game view
            for (int i = 0; i != EditorSceneManager.sceneCount; i++)
            {
                var scene = EditorSceneManager.GetSceneAt(i);
                if (scene.isSubScene)
                {
                    if (liveLinkEnabled)
                    {
                        EditorSceneManager.SetSceneCullingMask(scene, EditorRenderData.LiveLinkEditSceneViewMask);
                    }
                    else
                    {
                        EditorSceneManager.SetSceneCullingMask(scene,
                                                               EditorSceneManager.DefaultSceneCullingMask | EditorRenderData.LiveLinkEditGameViewMask);
                    }

                    var sceneAsset = AssetDatabase.LoadAssetAtPath <SceneAsset>(scene.path);
                    if (scene.isLoaded && sceneAsset != null)
                    {
                        m_EditingSceneAssets.Add(sceneAsset);
                    }
                }
            }

            if (PreviousGlobalDirtyID != GlobalDirtyID)
            {
                Entities.ForEach((SubScene subScene) =>
                {
                    if (subScene.LiveLinkData != null)
                    {
                        subScene.LiveLinkData.RequestCleanConversion();
                    }
                });
                PreviousGlobalDirtyID = GlobalDirtyID;
            }

            Entities.ForEach((SubScene subScene) =>
            {
                var isLoaded = m_EditingSceneAssets.Contains(subScene.SceneAsset);
                // We are editing with live link. Ensure it is active & up to date
                if (isLoaded && liveLinkEnabled)
                {
                    if (subScene.LiveLinkData == null)
                    {
                        AddUnique(ref needLiveLinkSync, subScene);
                    }
                    else
                    {
                        if (subScene.LiveLinkData.LiveLinkDirtyID != GetSceneDirtyID(subScene.LoadedScene) ||
                            subScene.LiveLinkData.DidRequestUpdate())
                        {
                            AddUnique(ref needLiveLinkSync, subScene);
                        }
                    }
                }
                // We are editing without live link.
                // We should have no entity representation loaded for the scene.
                else if (isLoaded && !liveLinkEnabled)
                {
                    var hasAnythingLoaded = false;
                    foreach (var s in subScene._SceneEntities)
                    {
                        hasAnythingLoaded |= EntityManager.HasComponent <SubSceneStreamingSystem.StreamingState>(s) ||
                                             !EntityManager.HasComponent <SubSceneStreamingSystem.IgnoreTag>(s);
                    }

                    if (hasAnythingLoaded)
                    {
                        AddUnique(ref cleanupScene, subScene);
                        AddUnique(ref markSceneLoadedFromLiveLink, subScene);
                    }
                }
                // Scene is not being edited, thus should not be live linked.
                else
                {
                    var isDrivenByLiveLink = false;
                    foreach (var s in subScene._SceneEntities)
                    {
                        isDrivenByLiveLink |= EntityManager.HasComponent <SubSceneStreamingSystem.IgnoreTag>(s);
                    }

                    if (isDrivenByLiveLink || subScene.LiveLinkData != null)
                    {
                        AddUnique(ref cleanupScene, subScene);
                        AddUnique(ref removeSceneLoadedFromLiveLink, subScene);
                    }
                }
            });

            if (needLiveLinkSync != null)
            {
                var shouldDelayLiveLink = SubSceneInspectorUtility.LiveLinkMode == LiveLinkMode.ConvertWithoutDiff;
                // Live link changes to entity world
                foreach (var scene in needLiveLinkSync)
                {
                    if (shouldDelayLiveLink)
                    {
                        EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                    }
                    else
                    {
                        // The current behaviour is that we do incremental conversion until we release the hot control
                        // This is to avoid any unexpected stalls
                        // Optimally the undo system would tell us if only properties have changed, but currently we don't have such an event stream.
                        var sceneDirtyID = GetSceneDirtyID(scene.LoadedScene);
                        if (IsHotControlActive())
                        {
                            if (scene.LiveLinkData != null)
                            {
                                LiveLinkScene.ApplyLiveLink(scene, World, scene.LiveLinkData.LiveLinkDirtyID,
                                                            SubSceneInspectorUtility.LiveLinkMode);
                            }
                            else
                            {
                                EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                            }
                        }
                        else
                        {
                            if (scene.LiveLinkData != null && scene.LiveLinkData.LiveLinkDirtyID != sceneDirtyID)
                            {
                                scene.LiveLinkData.RequestCleanConversion();
                            }
                            LiveLinkScene.ApplyLiveLink(scene, World, sceneDirtyID,
                                                        SubSceneInspectorUtility.LiveLinkMode);
                        }
                    }
                }
            }

            if (cleanupScene != null)
            {
                // Live link changes to entity world
                foreach (var scene in cleanupScene)
                {
                    CleanupScene(scene);
                }
            }

            if (markSceneLoadedFromLiveLink != null)
            {
                foreach (var scene in markSceneLoadedFromLiveLink)
                {
                    foreach (var sceneEntity in scene._SceneEntities)
                    {
                        if (!EntityManager.HasComponent <SubSceneStreamingSystem.IgnoreTag>(sceneEntity))
                        {
                            EntityManager.AddComponentData(sceneEntity, new SubSceneStreamingSystem.IgnoreTag());
                        }
                    }
                }
            }

            if (removeSceneLoadedFromLiveLink != null)
            {
                foreach (var scene in removeSceneLoadedFromLiveLink)
                {
                    foreach (var sceneEntity in scene._SceneEntities)
                    {
                        EntityManager.RemoveComponent <SubSceneStreamingSystem.IgnoreTag>(sceneEntity);
                    }
                }
            }
        }