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); }
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); }
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); }
public static void Register(IEntityHierarchy hierarchy) { var system = World.DefaultGameObjectInjectionWorld.GetExistingSystem <EntityHierarchyDiffSystem>(); system.DoRegister(hierarchy); EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); }
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); } } } }
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); }
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(); }
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(); }
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(); }
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); }
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); } } } }