From 848dbdf5325fdea014623d3f5d3b1b69c9ec7b9c Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 4 Dec 2024 18:41:36 +0100 Subject: [PATCH] Add auto-exit command line to editor --- Source/Editor/Editor.cs | 24 +++++++++++++++++------- Source/Editor/Managed/ManagedEditor.cpp | 22 +++++++++++++--------- Source/Editor/Managed/ManagedEditor.h | 11 +++++++++++ Source/Editor/Modules/WindowsModule.cs | 5 ++++- Source/Engine/Engine/CommandLine.cpp | 1 + Source/Engine/Engine/CommandLine.h | 5 +++++ 6 files changed, 51 insertions(+), 17 deletions(-) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index d99a55a08..795f89d55 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -49,9 +49,9 @@ namespace FlaxEditor } private readonly List _modules = new List(16); - private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode; + private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode, _autoExit; private string _projectToOpen; - private float _lastAutoSaveTimer; + private float _lastAutoSaveTimer, _autoExitTimeout = 0.1f; private Button _saveNowButton; private Button _cancelSaveButton; private bool _autoSaveNow; @@ -258,10 +258,11 @@ namespace FlaxEditor Instance = this; } - internal void Init(bool isHeadless, bool skipCompile, bool newProject, Guid startupScene) + internal void Init(StartupFlags flags, Guid startupScene) { Log("Setting up C# Editor..."); - _isHeadlessMode = isHeadless; + _isHeadlessMode = flags.HasFlag(StartupFlags.Headless); + _autoExit = flags.HasFlag(StartupFlags.Exit); _startupSceneCmdLine = startupScene; Profiler.BeginEvent("Projects"); @@ -297,11 +298,11 @@ namespace FlaxEditor StateMachine = new EditorStateMachine(this); Undo = new EditorUndo(this); - if (newProject) + if (flags.HasFlag(StartupFlags.NewProject)) InitProject(); EnsureState(); Log("Editor init"); - if (isHeadless) + if (_isHeadlessMode) Log("Running in headless mode"); // Note: we don't sort modules before Init (optimized) @@ -357,7 +358,7 @@ namespace FlaxEditor InitializationStart?.Invoke(); // Start Editor initialization ending phrase (will wait for scripts compilation result) - StateMachine.LoadingState.StartInitEnding(skipCompile); + StateMachine.LoadingState.StartInitEnding(flags.HasFlag(StartupFlags.SkipCompile)); } internal void RegisterModule(EditorModule module) @@ -486,6 +487,15 @@ namespace FlaxEditor { StateMachine.Update(); UpdateAutoSave(); + if (_autoExit && StateMachine.CurrentState == StateMachine.EditingSceneState) + { + _autoExitTimeout -= Time.UnscaledGameTime; + if (_autoExitTimeout < 0.0f) + { + Log("Auto exit"); + Engine.RequestExit(0); + } + } if (!StateMachine.IsPlayMode) { diff --git a/Source/Editor/Managed/ManagedEditor.cpp b/Source/Editor/Managed/ManagedEditor.cpp index d0b060ffe..9442aa244 100644 --- a/Source/Editor/Managed/ManagedEditor.cpp +++ b/Source/Editor/Managed/ManagedEditor.cpp @@ -176,7 +176,7 @@ ManagedEditor::~ManagedEditor() void ManagedEditor::Init() { // Note: editor modules should perform quite fast init, any longer things should be done in async during 'editor splash screen time - void* args[4]; + void* args[2]; MClass* mclass = GetClass(); if (mclass == nullptr) { @@ -193,18 +193,22 @@ void ManagedEditor::Init() LOG(Fatal, "Failed to create editor instance."); } MObject* exception = nullptr; - bool isHeadless = CommandLine::Options.Headless.IsTrue(); - bool skipCompile = CommandLine::Options.SkipCompile.IsTrue(); - bool newProject = CommandLine::Options.NewProject.IsTrue(); - args[0] = &isHeadless; - args[1] = &skipCompile; - args[2] = &newProject; + StartupFlags flags = StartupFlags::None; + if (CommandLine::Options.Headless.IsTrue()) + flags |= StartupFlags::Headless; + if (CommandLine::Options.SkipCompile.IsTrue()) + flags |= StartupFlags::SkipCompile; + if (CommandLine::Options.NewProject.IsTrue()) + flags |= StartupFlags::NewProject; + if (CommandLine::Options.Exit.IsTrue()) + flags |= StartupFlags::Exit; + args[0] = &flags; Guid sceneId; if (!CommandLine::Options.Play.HasValue() || (CommandLine::Options.Play.HasValue() && Guid::Parse(CommandLine::Options.Play.GetValue(), sceneId))) { sceneId = Guid::Empty; } - args[3] = &sceneId; + args[1] = &sceneId; initMethod->Invoke(instance, args, &exception); if (exception) { @@ -219,7 +223,7 @@ void ManagedEditor::Init() WasExitCalled = false; // Load scripts if auto-load on startup is disabled - if (!ManagedEditorOptions.ForceScriptCompilationOnStartup || skipCompile) + if (!ManagedEditorOptions.ForceScriptCompilationOnStartup || EnumHasAllFlags(flags, StartupFlags::SkipCompile)) { LOG(Info, "Loading managed assemblies (due to disabled compilation on startup)"); Scripting::Load(); diff --git a/Source/Editor/Managed/ManagedEditor.h b/Source/Editor/Managed/ManagedEditor.h index eb1cceef8..4722db997 100644 --- a/Source/Editor/Managed/ManagedEditor.h +++ b/Source/Editor/Managed/ManagedEditor.h @@ -22,6 +22,15 @@ API_CLASS(Namespace="FlaxEditor", Name="Editor", NoSpawn, NoConstructor) class M DECLARE_SCRIPTING_TYPE_NO_SPAWN(ManagedEditor); static Guid ObjectID; + API_ENUM(Attributes="Flags", Internal) enum class StartupFlags + { + None = 0, + Headless = 1, + SkipCompile = 2, + NewProject = 4, + Exit = 8, + }; + struct InternalOptions { byte AutoReloadScriptsOnMainWindowFocus = 1; @@ -258,3 +267,5 @@ public: // [ScriptingObject] void DestroyManaged() override; }; + +DECLARE_ENUM_OPERATORS(ManagedEditor::StartupFlags); diff --git a/Source/Editor/Modules/WindowsModule.cs b/Source/Editor/Modules/WindowsModule.cs index b9f3e246b..fa7a04d9b 100644 --- a/Source/Editor/Modules/WindowsModule.cs +++ b/Source/Editor/Modules/WindowsModule.cs @@ -950,7 +950,10 @@ namespace FlaxEditor.Modules MainWindow = null; // Capture project icon screenshot (not in play mode and if editor was used for some time) - if (!Editor.StateMachine.IsPlayMode && Time.TimeSinceStartup >= 5.0f && GPUDevice.Instance?.RendererType != RendererType.Null) + if (!Editor.StateMachine.IsPlayMode && + Time.TimeSinceStartup >= 5.0f && + !Editor.IsHeadlessMode && + GPUDevice.Instance?.RendererType != RendererType.Null) { Editor.Log("Capture project icon screenshot"); _projectIconScreenshotTimeout = Time.TimeSinceStartup + 0.8f; // wait 800ms for a screenshot task diff --git a/Source/Engine/Engine/CommandLine.cpp b/Source/Engine/Engine/CommandLine.cpp index e2de230ef..efcd73524 100644 --- a/Source/Engine/Engine/CommandLine.cpp +++ b/Source/Engine/Engine/CommandLine.cpp @@ -154,6 +154,7 @@ bool CommandLine::Parse(const Char* cmdLine) PARSE_ARG_SWITCH("-build ", Build); PARSE_BOOL_SWITCH("-skipcompile ", SkipCompile); PARSE_BOOL_SWITCH("-shaderdebug ", ShaderDebug); + PARSE_BOOL_SWITCH("-exit ", Exit); PARSE_ARG_OPT_SWITCH("-play ", Play); #endif #if USE_EDITOR || !BUILD_RELEASE diff --git a/Source/Engine/Engine/CommandLine.h b/Source/Engine/Engine/CommandLine.h index 347e9bebd..4a3bab4c0 100644 --- a/Source/Engine/Engine/CommandLine.h +++ b/Source/Engine/Engine/CommandLine.h @@ -168,6 +168,11 @@ public: /// Nullable ShaderDebug; + /// + /// -exit (exits the editor after startup and performing all queued actions). Usefull when invoking editor from CL/CD. + /// + Nullable Exit; + /// /// -play !guid! ( Scene to play, can be empty to use default ) ///