diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 0799b2fe687..dc0eb11ebf3 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -1028,6 +1028,8 @@ ProjectSettings::ProjectSettings() {
}
extensions.push_back("shader");
+ GLOBAL_DEF("editor/main_run_args", "");
+
GLOBAL_DEF("editor/search_in_file_extensions", extensions);
custom_prop_info["editor/search_in_file_extensions"] = PropertyInfo(Variant::POOL_STRING_ARRAY, "editor/search_in_file_extensions");
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index cb258bbcf1b..f81a1d9ee9b 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -157,7 +157,7 @@
Returns the command-line arguments passed to the engine.
Command-line arguments can be written in any form, including both [code]--key value[/code] and [code]--key=value[/code] forms so they can be properly parsed, as long as custom command-line arguments do not conflict with engine arguments.
You can also incorporate environment variables using the [method get_environment] method.
- You can set [code]editor/main_run_args[/code] in the Project Settings to define command-line arguments to be passed by the editor when running the project.
+ You can set [member ProjectSettings.editor/main_run_args] to define command-line arguments to be passed by the editor when running the project.
Here's a minimal example on how to parse command-line arguments into a dictionary using the [code]--key=value[/code] form for arguments:
[codeblock]
var arguments = {}
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index fbef3e599df..75694037264 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -514,6 +514,14 @@
If [code]Use Vsync[/code] is enabled and this setting is [code]true[/code], enables vertical synchronization via the operating system's window compositor when in windowed mode and the compositor is enabled. This will prevent stutter in certain situations. (Windows only.)
[b]Note:[/b] This option is experimental and meant to alleviate stutter experienced by some users. However, some users have experienced a Vsync framerate halving (e.g. from 60 FPS to 30 FPS) when using it.
+
+ The command-line arguments to append to Godot's own command line when running the project. This doesn't affect the editor itself.
+ It is possible to make another executable run Godot by using the [code]%command%[/code] placeholder. The placeholder will be replaced with Godot's own command line. Program-specific arguments should be placed [i]before[/i] the placeholder, whereas Godot-specific arguments should be placed [i]after[/i] the placeholder.
+ For example, this can be used to force the project to run on the dedicated GPU in a NVIDIA Optimus system on Linux:
+ [codeblock]
+ prime-run %command%
+ [/codeblock]
+
Search path for project-specific script templates. Godot will search for script templates both in the editor-specific path and in this project-specific path.
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 3de6651c9bb..6d258d792e8 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -5842,8 +5842,6 @@ EditorNode::EditorNode() {
register_exporters();
- GLOBAL_DEF("editor/main_run_args", "");
-
ClassDB::set_class_enabled("RootMotionView", true);
//defs here, use EDITOR_GET in logic
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 743f49451e7..e6f04ea3cd7 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -186,15 +186,50 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
args.push_back(p_scene);
}
+ String exec = OS::get_singleton()->get_executable_path();
+
if (p_custom_args != "") {
- Vector cargs = p_custom_args.split(" ", false);
- for (int i = 0; i < cargs.size(); i++) {
- args.push_back(cargs[i].replace(" ", "%20"));
+ // Allow the user to specify a command to run, similar to Steam's launch options.
+ // In this case, Godot will no longer be run directly; it's up to the underlying command
+ // to run it. For instance, this can be used on Linux to force a running project
+ // to use Optimus using `prime-run` or similar.
+ // Example: `prime-run %command% --time-scale 0.5`
+ const int placeholder_pos = p_custom_args.find("%command%");
+
+ Vector custom_args;
+
+ if (placeholder_pos != -1) {
+ // Prepend executable-specific custom arguments.
+ // If nothing is placed before `%command%`, behave as if no placeholder was specified.
+ Vector exec_args = p_custom_args.substr(0, placeholder_pos).split(" ", false);
+ if (exec_args.size() >= 1) {
+ exec = exec_args[0];
+ exec_args.remove(0);
+
+ // Append the Godot executable name before we append executable arguments
+ // (since the order is reversed when using `push_front()`).
+ args.push_front(OS::get_singleton()->get_executable_path());
+ }
+
+ for (int i = exec_args.size() - 1; i >= 0; i--) {
+ // Iterate backwards as we're pushing items in the reverse order.
+ args.push_front(exec_args[i].replace(" ", "%20"));
+ }
+
+ // Append Godot-specific custom arguments.
+ custom_args = p_custom_args.substr(placeholder_pos + String("%command%").size()).split(" ", false);
+ for (int i = 0; i < custom_args.size(); i++) {
+ args.push_back(custom_args[i].replace(" ", "%20"));
+ }
+ } else {
+ // Append Godot-specific custom arguments.
+ custom_args = p_custom_args.split(" ", false);
+ for (int i = 0; i < custom_args.size(); i++) {
+ args.push_back(custom_args[i].replace(" ", "%20"));
+ }
}
}
- String exec = OS::get_singleton()->get_executable_path();
-
printf("Running: %ls", exec.c_str());
for (List::Element *E = args.front(); E; E = E->next()) {
printf(" %ls", E->get().c_str());