public LiveLinkScene(World destinationWorld, LiveLinkMode mode) { DestinationWorld = destinationWorld; ConvertedWorld = new World("Clean Entity Conversion World"); LiveLinkDiffer = new EntityManagerDiffer(ConvertedWorld, Allocator.Persistent); LiveLinkPatcher = new EntityManagerPatcher(destinationWorld, Allocator.Persistent); _RequestCleanConversion = true; _LiveLinkMode = mode; }
public static LiveLinkChangeSet UpdateLiveLink(Scene scene, Hash128 sceneGUID, ref LiveLinkDiffGenerator liveLinkData, int sceneDirtyID, LiveLinkMode mode, BuildConfiguration config, out NativeArray <GUID> assetDependencies) { //Debug.Log("ApplyLiveLink: " + scene.SceneName); int framesToRetainBlobAssets = RetainBlobAssetsSetting.GetFramesToRetainBlobAssets(config); var liveLinkEnabled = mode != LiveLinkMode.Disabled; if (liveLinkData != null && liveLinkData._LiveLinkEnabled != liveLinkEnabled) { liveLinkData.Dispose(); liveLinkData = null; } var unloadAllPreviousEntities = liveLinkData == null; if (liveLinkData == null) { liveLinkData = new LiveLinkDiffGenerator(sceneGUID, liveLinkEnabled); } if (!liveLinkEnabled) { assetDependencies = default; return(new LiveLinkChangeSet { UnloadAllPreviousEntities = unloadAllPreviousEntities, SceneName = scene.name, SceneGUID = sceneGUID, FramesToRetainBlobAssets = framesToRetainBlobAssets }); } var flags = GameObjectConversionUtility.ConversionFlags.AddEntityGUID | GameObjectConversionUtility.ConversionFlags.AssignName | GameObjectConversionUtility.ConversionFlags.GameViewLiveLink; if (mode == LiveLinkMode.LiveConvertSceneView) { flags |= GameObjectConversionUtility.ConversionFlags.SceneViewLiveLink; } liveLinkData.Convert(scene, sceneGUID, flags, config, out assetDependencies); var convertedEntityManager = liveLinkData._ConvertedWorld.EntityManager; // We don't know the scene tag of the destination world, so we create a null Scene Tag. // In the patching code this will be translated into the final scene entity. convertedEntityManager.AddSharedComponentData(liveLinkData._MissingSceneQuery, new SceneTag { SceneEntity = Entity.Null }); #if UNITY_2020_1_OR_NEWER convertedEntityManager.AddSharedComponentData(liveLinkData._MissingRenderDataQuery, new EditorRenderData { SceneCullingMask = UnityEditor.SceneManagement.SceneCullingMasks.GameViewObjects, PickableObject = null }); #else convertedEntityManager.AddSharedComponentData(liveLinkData._MissingRenderDataQuery, new EditorRenderData { SceneCullingMask = EditorRenderData.LiveLinkEditGameViewMask, PickableObject = null }); #endif var options = EntityManagerDifferOptions.IncludeForwardChangeSet | EntityManagerDifferOptions.FastForwardShadowWorld | EntityManagerDifferOptions.ValidateUniqueEntityGuid | EntityManagerDifferOptions.ClearMissingReferences; var changes = new LiveLinkChangeSet { Changes = liveLinkData._LiveLinkDiffer.GetChanges(options, Allocator.TempJob).ForwardChangeSet, UnloadAllPreviousEntities = unloadAllPreviousEntities, SceneName = scene.name, SceneGUID = sceneGUID, FramesToRetainBlobAssets = framesToRetainBlobAssets }; liveLinkData.LiveLinkDirtyID = sceneDirtyID; // convertedEntityManager.Debug.CheckInternalConsistency(); return(changes); }
public static LiveLinkChangeSet UpdateLiveLink(Scene scene, Hash128 sceneGUID, ref LiveLinkDiffGenerator liveLinkData, int sceneDirtyID, LiveLinkMode mode, GUID configGUID, BuildConfiguration config) { //Debug.Log("ApplyLiveLink: " + scene.SceneName); int framesToRetainBlobAssets = RetainBlobAssetsSetting.GetFramesToRetainBlobAssets(config); var liveLinkEnabled = mode != LiveLinkMode.Disabled; if (liveLinkData != null && liveLinkData._LiveLinkEnabled != liveLinkEnabled) { liveLinkData.Dispose(); liveLinkData = null; } var unloadAllPreviousEntities = liveLinkData == null; if (liveLinkData == null) { liveLinkData = new LiveLinkDiffGenerator(scene, sceneGUID, configGUID, config, liveLinkEnabled); } else if (liveLinkData._Scene != scene || !ReferenceEquals(liveLinkData._buildConfiguration, config) || liveLinkData._buildConfigurationGUID != configGUID) { liveLinkData._Scene = scene; liveLinkData._buildConfigurationGUID = configGUID; liveLinkData._buildConfiguration = config; liveLinkData._RequestCleanConversion = true; } if (!liveLinkEnabled) { return(new LiveLinkChangeSet { UnloadAllPreviousEntities = unloadAllPreviousEntities, SceneName = scene.name, SceneGUID = sceneGUID, FramesToRetainBlobAssets = framesToRetainBlobAssets }); } var flags = GameObjectConversionUtility.ConversionFlags.AddEntityGUID | GameObjectConversionUtility.ConversionFlags.AssignName | GameObjectConversionUtility.ConversionFlags.GameViewLiveLink; if (mode == LiveLinkMode.LiveConvertSceneView) { flags |= GameObjectConversionUtility.ConversionFlags.SceneViewLiveLink; } if (mode == LiveLinkMode.LiveConvertStandalonePlayer) { flags |= GameObjectConversionUtility.ConversionFlags.IsBuildingForPlayer; } liveLinkData.Convert(flags); const EntityManagerDifferOptions options = EntityManagerDifferOptions.IncludeForwardChangeSet | EntityManagerDifferOptions.FastForwardShadowWorld | EntityManagerDifferOptions.ValidateUniqueEntityGuid | EntityManagerDifferOptions.ClearMissingReferences; var changes = new LiveLinkChangeSet { Changes = liveLinkData._LiveLinkDiffer.GetChanges(options, Allocator.TempJob).ForwardChangeSet, UnloadAllPreviousEntities = unloadAllPreviousEntities, SceneName = scene.name, SceneGUID = sceneGUID, FramesToRetainBlobAssets = framesToRetainBlobAssets }; #if !UNITY_2020_2_OR_NEWER liveLinkData.LiveLinkDirtyID = sceneDirtyID; #endif // convertedEntityManager.Debug.CheckInternalConsistency(); return(changes); }
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); } } }
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); } } } }
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, _BuildConfiguration, out var assetDependencies)); if (assetDependencies.IsCreated) { m_AssetDependencies.Clear(); foreach (var asset in assetDependencies) { m_AssetDependencies.Add(asset, 1); } assetDependencies.Dispose(); } } finally { if (liveLink != null) { _SceneGUIDToLiveLink.Add(sceneGUID, liveLink); } } } }
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) { // TODO: Allocs, needs better API var buildConfigurationDependencyHash = AssetDatabase.GetAssetDependencyHash(AssetDatabase.GUIDToAssetPath(_BuildConfigurationGUID.ToString())); 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 = new GUID(AssetDatabase.AssetPathToGUID(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 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() || liveLink.LiveLinkDirtyID != GetSceneDirtyID(scene)) { AddLiveLinkChangeSet(sceneGuid, changeSets, mode); } } else { if (_SentLoadScenes.Add(sceneGuid)) { loadScenes.Add(sceneGuid); } } } }
public static void ApplyLiveLink(SubScene scene, World dstWorld, int sceneDirtyID, LiveLinkMode mode) { //Debug.Log("ApplyLiveLink: " + scene.SceneName); #if ENABLE_UNITY_COLLECTIONS_CHECKS if (mode == LiveLinkMode.Disabled) { throw new System.ArgumentException("LiveLinkMode must not be disabled"); } #endif // When switching mode, completely unload the previous scene if (scene.LiveLinkData != null && (scene.LiveLinkData._LiveLinkMode == LiveLinkMode.ConvertWithoutDiff || mode == LiveLinkMode.ConvertWithoutDiff || scene.LiveLinkData.DestinationWorld != dstWorld)) { scene.LiveLinkData.Dispose(); scene.LiveLinkData = null; } var unloadAllPreviousEntities = scene.LiveLinkData == null; if (scene.LiveLinkData == null) { scene.LiveLinkData = new LiveLinkScene(dstWorld, mode); } var liveLink = scene.LiveLinkData; var flags = GameObjectConversionUtility.ConversionFlags.AddEntityGUID | GameObjectConversionUtility.ConversionFlags.AssignName | GameObjectConversionUtility.ConversionFlags.GameViewLiveLink; if (mode == LiveLinkMode.LiveConvertSceneView) { flags |= GameObjectConversionUtility.ConversionFlags.SceneViewLiveLink; } liveLink.Convert(scene.LoadedScene, scene.SceneGUID, flags); var streamingSystem = dstWorld.GetExistingSystem <SubSceneStreamingSystem>(); var dstEntities = dstWorld.EntityManager; // Unload scene if (unloadAllPreviousEntities) { foreach (var s in scene._SceneEntities) { streamingSystem.UnloadSceneImmediate(s); dstEntities.DestroyEntity(s); } var sceneEntity = dstEntities.CreateEntity(); dstEntities.SetName(sceneEntity, "Scene (LiveLink): " + scene.SceneName); dstEntities.AddComponentObject(sceneEntity, scene); dstEntities.AddComponentData(sceneEntity, new SubSceneStreamingSystem.StreamingState { Status = SubSceneStreamingSystem.StreamingStatus.Loaded }); dstEntities.AddComponentData(sceneEntity, new SubSceneStreamingSystem.IgnoreTag( )); scene._SceneEntities = new List <Entity>(); scene._SceneEntities.Add(sceneEntity); } var convertedEntityManager = liveLink.ConvertedWorld.EntityManager; var liveLinkSceneEntity = scene._SceneEntities[0]; /// We want to let the live linked scene be able to reference the already existing Scene Entity (Specifically SceneTag should point to the scene Entity after live link completes) // Add Scene tag to all entities using the convertedSceneEntity that will map to the already existing scene entity. using (var missingSceneQuery = convertedEntityManager.CreateEntityQuery(new EntityQueryDesc { None = new ComponentType[] { typeof(SceneTag) }, Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled })) { convertedEntityManager.AddSharedComponentData(missingSceneQuery, new SceneTag { SceneEntity = liveLinkSceneEntity }); } if (mode != LiveLinkMode.ConvertWithoutDiff) { var options = EntityManagerDifferOptions.IncludeForwardChangeSet | EntityManagerDifferOptions.FastForwardShadowWorld | EntityManagerDifferOptions.ValidateUniqueEntityGuid | EntityManagerDifferOptions.ClearMissingReferences; using (var changes = liveLink.LiveLinkDiffer.GetChanges(options, Allocator.TempJob)) { liveLink.LiveLinkPatcher.ApplyChangeSet(changes.ForwardChangeSet); } } else { dstWorld.EntityManager.MoveEntitiesFrom(liveLink.ConvertedWorld.EntityManager); } // convertedEntityManager.Debug.CheckInternalConsistency(); //liveLink.ConvertedShadowWorld.EntityManager.Debug.CheckInternalConsistency(); using (var missingRenderData = dstEntities.CreateEntityQuery(new EntityQueryDesc { All = new ComponentType[] { typeof(SceneTag) }, None = new ComponentType[] { typeof(EditorRenderData) }, Options = EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabled })) { missingRenderData.SetFilter(new SceneTag { SceneEntity = liveLinkSceneEntity }); dstEntities.AddSharedComponentData(missingRenderData, new EditorRenderData() { SceneCullingMask = EditorRenderData.LiveLinkEditGameViewMask, PickableObject = scene.gameObject }); } liveLink.LiveLinkDirtyID = sceneDirtyID; EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); }