// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; using FlaxEditor.Content.Settings; using FlaxEditor.SceneGraph; using FlaxEditor.Utilities; using FlaxEngine; using FlaxEngine.Utilities; namespace FlaxEditor.States { /// /// In this state editor is simulating game. /// /// [HideInEditor] public sealed class PlayingState : EditorState { private readonly DuplicateScenes _duplicateScenes = new DuplicateScenes(); private readonly List _selectedObjects = new List(); /// /// Gets a value indicating whether any scene was dirty before entering the play mode. /// public bool WasDirty => _duplicateScenes.WasDirty; /// public override bool CanEditScene => true; /// public override bool CanUseUndoRedo => false; /// public override bool CanEnterPlayMode => true; /// /// Occurs when play mode is starting (before scene duplicating). /// public event Action SceneDuplicating; /// /// Occurs when play mode is starting (after scene duplicating). /// public event Action SceneDuplicated; /// /// Occurs when play mode is applying game settings. Can be used to cache the editor local state of some settings. /// public event Action GameSettingsApplying; /// /// Occurs when play mode applied game settings. Can be used to preserve the editor local state of some settings. /// public event Action GameSettingsApplied; /// /// Occurs when play mode is ending (before scene restoring). /// public event Action SceneRestoring; /// /// Occurs when play mode is ending (after scene restoring). /// public event Action SceneRestored; /// /// Gets or sets a value indicating whether game logic is paused. /// public bool IsPaused { get => Time.GamePaused; set { if (!IsActive) throw new InvalidOperationException(); Time.GamePaused = value; } } internal PlayingState(Editor editor) : base(editor) { SetupEditorEnvOptions(); } private void CacheSelection() { Profiler.BeginEvent("PlayingState.CacheSelection"); _selectedObjects.Clear(); for (int i = 0; i < Editor.SceneEditing.Selection.Count; i++) { _selectedObjects.Add(Editor.SceneEditing.Selection[i].ID); } Profiler.EndEvent(); } private void RestoreSelection() { Profiler.BeginEvent("PlayingState.RestoreSelection"); var count = Editor.SceneEditing.Selection.Count; Editor.SceneEditing.Selection.Clear(); for (int i = 0; i < _selectedObjects.Count; i++) { var node = SceneGraphFactory.FindNode(_selectedObjects[i]); if (node != null) Editor.SceneEditing.Selection.Add(node); } if (Editor.SceneEditing.Selection.Count != count) Editor.SceneEditing.OnSelectionChanged(); Profiler.EndEvent(); } /// public override string Status => "Play Mode!"; /// public override void OnEnter() { Profiler.BeginEvent("PlayingState.OnEnter"); Editor.OnPlayBeginning(); CacheSelection(); // Remove references to the scene objects Editor.Scene.ClearRefsToSceneObjects(); // Apply game settings (user may modify them before the gameplay) GameSettingsApplying?.Invoke(); GameSettings.Apply(); GameSettingsApplied?.Invoke(); // Duplicate editor scene for simulation SceneDuplicating?.Invoke(); _duplicateScenes.GatherSceneData(); Editor.Internal_SetPlayMode(true); IsPaused = false; PluginManager.InitializeGamePlugins(); _duplicateScenes.CreateScenes(); SceneDuplicated?.Invoke(); RestoreSelection(); Editor.OnPlayBegin(); Profiler.EndEvent(); } private void SetupEditorEnvOptions() { Time.TimeScale = 1.0f; Physics.AutoSimulation = true; Screen.CursorVisible = true; Screen.CursorLock = CursorLockMode.None; } /// public override void UpdateFPS() { // Game drives the Time settings } /// public override void OnExit(State nextState) { Profiler.BeginEvent("PlayingState.OnExit"); IsPaused = true; // Remove references to the scene objects Editor.Scene.ClearRefsToSceneObjects(); // Restore editor scene SceneRestoring?.Invoke(); _duplicateScenes.DeletedScenes(); PluginManager.DeinitializeGamePlugins(); Editor.Internal_SetPlayMode(false); _duplicateScenes.RestoreSceneData(); SceneRestored?.Invoke(); // Restore game settings and state for editor environment SetupEditorEnvOptions(); var win = Editor.Windows.GameWin?.Root; if (win != null) win.Cursor = CursorType.Default; IsPaused = true; RestoreSelection(); Editor.OnPlayEnd(); Profiler.EndEvent(); } } }