Browse Source

Merge pull request #63624 from reduz/commandline-user-args

Add support for command-line user arguments.
Rémi Verschelde 3 years ago
parent
commit
4d4575d386
7 changed files with 41 additions and 6 deletions
  1. 11 0
      core/core_bind.cpp
  2. 1 0
      core/core_bind.h
  3. 2 1
      core/os/os.cpp
  4. 3 1
      core/os/os.h
  5. 11 0
      doc/classes/OS.xml
  6. 12 3
      main/main.cpp
  7. 1 1
      tests/test_main.cpp

+ 11 - 0
core/core_bind.cpp

@@ -331,6 +331,16 @@ Vector<String> OS::get_cmdline_args() {
 	return cmdlinev;
 }
 
+Vector<String> OS::get_cmdline_user_args() {
+	List<String> cmdline = ::OS::get_singleton()->get_cmdline_user_args();
+	Vector<String> cmdlinev;
+	for (const String &E : cmdline) {
+		cmdlinev.push_back(E);
+	}
+
+	return cmdlinev;
+}
+
 String OS::get_locale() const {
 	return ::OS::get_singleton()->get_locale();
 }
@@ -614,6 +624,7 @@ void OS::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name);
 	ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args);
+	ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args);
 
 	ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &OS::delay_usec);
 	ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &OS::delay_msec);

+ 1 - 0
core/core_bind.h

@@ -188,6 +188,7 @@ public:
 
 	String get_name() const;
 	Vector<String> get_cmdline_args();
+	Vector<String> get_cmdline_user_args();
 
 	String get_locale() const;
 	String get_locale_language() const;

+ 2 - 1
core/os/os.cpp

@@ -362,9 +362,10 @@ String OS::get_model_name() const {
 	return "GenericDevice";
 }
 
-void OS::set_cmdline(const char *p_execpath, const List<String> &p_args) {
+void OS::set_cmdline(const char *p_execpath, const List<String> &p_args, const List<String> &p_user_args) {
 	_execpath = String::utf8(p_execpath);
 	_cmdline = p_args;
+	_user_args = p_user_args;
 }
 
 String OS::get_unique_id() const {

+ 3 - 1
core/os/os.h

@@ -46,6 +46,7 @@ class OS {
 	static uint64_t target_ticks;
 	String _execpath;
 	List<String> _cmdline;
+	List<String> _user_args;
 	bool _keep_screen_on = true; // set default value to true, because this had been true before godot 2.0.
 	bool low_processor_usage_mode = false;
 	int low_processor_usage_mode_sleep_usec = 10000;
@@ -106,7 +107,7 @@ protected:
 	virtual void finalize() = 0;
 	virtual void finalize_core() = 0;
 
-	virtual void set_cmdline(const char *p_execpath, const List<String> &p_args);
+	virtual void set_cmdline(const char *p_execpath, const List<String> &p_args, const List<String> &p_user_args);
 
 	virtual bool _check_internal_feature_support(const String &p_feature) = 0;
 
@@ -162,6 +163,7 @@ public:
 
 	virtual String get_name() const = 0;
 	virtual List<String> get_cmdline_args() const { return _cmdline; }
+	virtual List<String> get_cmdline_user_args() const { return _user_args; }
 	virtual List<String> get_cmdline_platform_args() const { return List<String>(); }
 	virtual String get_model_name() const;
 

+ 11 - 0
doc/classes/OS.xml

@@ -198,6 +198,17 @@
 				}
 				[/csharp]
 				[/codeblocks]
+				[b]Note:[/b] Passing custom user arguments directly is not recommended, as the engine may discard or modify them. Instead, the best way is to use the standard UNIX double dash ([code]--[/code]) and then pass custom arguments, which the engine itself will ignore. These can be read via [method get_cmdline_user_args].
+			</description>
+		</method>
+		<method name="get_cmdline_user_args">
+			<return type="PackedStringArray" />
+			<description>
+				Similar to [method get_cmdline_args], but this returns the user arguments (any argument passed after the double dash [code]--[/code] argument). These are left untouched by Godot for the user.
+				For example, in the command line below, [code]--fullscreen[/code] will not be returned in [method get_cmdline_user_args] and [code]--level 1[/code] will only be returned in [method get_cmdline_user_args]:
+				[codeblock]
+				godot --fullscreen -- --level 1
+				[/codeblock]
 			</description>
 		</method>
 		<method name="get_config_dir" qualifiers="const">

+ 12 - 3
main/main.cpp

@@ -285,6 +285,7 @@ void Main::print_help(const char *p_binary) {
 	OS::get_singleton()->print("\n");
 
 	OS::get_singleton()->print("Run options:\n");
+	OS::get_singleton()->print("  --                                           Separator for user-provided arguments. Following arguments are not used by the engine, but can be read from `OS.get_cmdline_user_args()`.\n");
 #ifdef TOOLS_ENABLED
 	OS::get_singleton()->print("  -e, --editor                                 Start the editor instead of running the scene.\n");
 	OS::get_singleton()->print("  -p, --project-manager                        Start the project manager, even if a project is auto-detected.\n");
@@ -623,6 +624,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 	/* argument parsing and main creation */
 	List<String> args;
 	List<String> main_args;
+	List<String> user_args;
+	bool adding_user_args = false;
 	List<String> platform_args = OS::get_singleton()->get_cmdline_platform_args();
 
 	// Add command line arguments.
@@ -695,9 +698,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 			continue;
 		}
 #endif
+
 		List<String>::Element *N = I->next();
 
-		if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help
+		if (adding_user_args) {
+			user_args.push_back(I->get());
+		} else if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help
 
 			show_help = true;
 			exit_code = ERR_HELP; // Hack to force an early exit in `main()` with a success code.
@@ -1200,7 +1206,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 				OS::get_singleton()->print("Missing --xr-mode argument, aborting.\n");
 				goto error;
 			}
-
+		} else if (I->get() == "--") {
+			adding_user_args = true;
 		} else {
 			main_args.push_back(I->get());
 		}
@@ -1377,7 +1384,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 
 	Logger::set_flush_stdout_on_print(ProjectSettings::get_singleton()->get("application/run/flush_stdout_on_print"));
 
-	OS::get_singleton()->set_cmdline(execpath, main_args);
+	OS::get_singleton()->set_cmdline(execpath, main_args, user_args);
 
 	// possibly be worth changing the default from vulkan to something lower spec,
 	// for the project manager, depending on how smooth the fallback is.
@@ -1670,6 +1677,7 @@ error:
 	unregister_core_types();
 
 	OS::get_singleton()->_cmdline.clear();
+	OS::get_singleton()->_user_args.clear();
 
 	if (message_queue) {
 		memdelete(message_queue);
@@ -3001,6 +3009,7 @@ void Main::cleanup(bool p_force) {
 	OS::get_singleton()->delete_main_loop();
 
 	OS::get_singleton()->_cmdline.clear();
+	OS::get_singleton()->_user_args.clear();
 	OS::get_singleton()->_execpath = "";
 	OS::get_singleton()->_local_clipboard = "";
 

+ 1 - 1
tests/test_main.cpp

@@ -105,7 +105,7 @@ int test_main(int argc, char *argv[]) {
 	for (int i = 0; i < argc; i++) {
 		args.push_back(String::utf8(argv[i]));
 	}
-	OS::get_singleton()->set_cmdline("", args);
+	OS::get_singleton()->set_cmdline("", args, List<String>());
 
 	// Run custom test tools.
 	if (test_commands) {