Browse Source

Auto-Increment Debugger Port

Note: This PR also changes the port of the GDScript Language Server from 6008 to 6005. This opens enough ports above the debug port (6007) for this change to be useful.
Nathan Franke 4 năm trước cách đây
mục cha
commit
de7873c2d8

+ 5 - 0
editor/debugger/editor_debugger_node.cpp

@@ -183,6 +183,11 @@ ScriptEditorDebugger *EditorDebuggerNode::get_default_debugger() const {
 	return Object::cast_to<ScriptEditorDebugger>(tabs->get_tab_control(0));
 	return Object::cast_to<ScriptEditorDebugger>(tabs->get_tab_control(0));
 }
 }
 
 
+String EditorDebuggerNode::get_server_uri() const {
+	ERR_FAIL_COND_V(server.is_null(), "");
+	return server->get_uri();
+}
+
 Error EditorDebuggerNode::start(const String &p_uri) {
 Error EditorDebuggerNode::start(const String &p_uri) {
 	stop();
 	stop();
 	ERR_FAIL_COND_V(p_uri.find("://") < 0, ERR_INVALID_PARAMETER);
 	ERR_FAIL_COND_V(p_uri.find("://") < 0, ERR_INVALID_PARAMETER);

+ 2 - 1
editor/debugger/editor_debugger_node.h

@@ -188,8 +188,9 @@ public:
 	void set_camera_override(CameraOverride p_override);
 	void set_camera_override(CameraOverride p_override);
 	CameraOverride get_camera_override();
 	CameraOverride get_camera_override();
 
 
-	Error start(const String &p_uri = "tcp://");
+	String get_server_uri() const;
 
 
+	Error start(const String &p_uri = "tcp://");
 	void stop();
 	void stop();
 
 
 	void add_debugger_plugin(const Ref<Script> &p_script);
 	void add_debugger_plugin(const Ref<Script> &p_script);

+ 36 - 12
editor/debugger/editor_debugger_server.cpp

@@ -41,15 +41,18 @@
 class EditorDebuggerServerTCP : public EditorDebuggerServer {
 class EditorDebuggerServerTCP : public EditorDebuggerServer {
 private:
 private:
 	Ref<TCPServer> server;
 	Ref<TCPServer> server;
+	String endpoint;
 
 
 public:
 public:
 	static EditorDebuggerServer *create(const String &p_protocol);
 	static EditorDebuggerServer *create(const String &p_protocol);
-	virtual void poll() {}
-	virtual Error start(const String &p_uri);
-	virtual void stop();
-	virtual bool is_active() const;
-	virtual bool is_connection_available() const;
-	virtual Ref<RemoteDebuggerPeer> take_connection();
+
+	virtual void poll() override {}
+	virtual String get_uri() const override;
+	virtual Error start(const String &p_uri) override;
+	virtual void stop() override;
+	virtual bool is_active() const override;
+	virtual bool is_connection_available() const override;
+	virtual Ref<RemoteDebuggerPeer> take_connection() override;
 
 
 	EditorDebuggerServerTCP();
 	EditorDebuggerServerTCP();
 };
 };
@@ -63,21 +66,42 @@ EditorDebuggerServerTCP::EditorDebuggerServerTCP() {
 	server.instantiate();
 	server.instantiate();
 }
 }
 
 
+String EditorDebuggerServerTCP::get_uri() const {
+	return endpoint;
+}
+
 Error EditorDebuggerServerTCP::start(const String &p_uri) {
 Error EditorDebuggerServerTCP::start(const String &p_uri) {
-	int bind_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
+	// Default host and port
 	String bind_host = (String)EditorSettings::get_singleton()->get("network/debug/remote_host");
 	String bind_host = (String)EditorSettings::get_singleton()->get("network/debug/remote_host");
+	int bind_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
+
+	// Optionally override
 	if (!p_uri.is_empty() && p_uri != "tcp://") {
 	if (!p_uri.is_empty() && p_uri != "tcp://") {
 		String scheme, path;
 		String scheme, path;
 		Error err = p_uri.parse_url(scheme, bind_host, bind_port, path);
 		Error err = p_uri.parse_url(scheme, bind_host, bind_port, path);
 		ERR_FAIL_COND_V(err != OK, ERR_INVALID_PARAMETER);
 		ERR_FAIL_COND_V(err != OK, ERR_INVALID_PARAMETER);
 		ERR_FAIL_COND_V(!bind_host.is_valid_ip_address() && bind_host != "*", ERR_INVALID_PARAMETER);
 		ERR_FAIL_COND_V(!bind_host.is_valid_ip_address() && bind_host != "*", ERR_INVALID_PARAMETER);
 	}
 	}
-	const Error err = server->listen(bind_port, bind_host);
-	if (err != OK) {
-		EditorNode::get_log()->add_message(String("Error listening on port ") + itos(bind_port), EditorLog::MSG_TYPE_ERROR);
-		return err;
+
+	// Try listening on ports
+	const int max_attempts = 5;
+	for (int attempt = 1;; ++attempt) {
+		const Error err = server->listen(bind_port, bind_host);
+		if (err == OK) {
+			break;
+		}
+		if (attempt >= max_attempts) {
+			EditorNode::get_log()->add_message(vformat("Cannot listen on port %d, remote debugging unavailable.", bind_port), EditorLog::MSG_TYPE_ERROR);
+			return err;
+		}
+		int last_port = bind_port++;
+		EditorNode::get_log()->add_message(vformat("Cannot listen on port %d, trying %d instead.", last_port, bind_port), EditorLog::MSG_TYPE_WARNING);
 	}
 	}
-	return err;
+
+	// Endpoint that the client should connect to
+	endpoint = vformat("tcp://%s:%d", bind_host, bind_port);
+
+	return OK;
 }
 }
 
 
 void EditorDebuggerServerTCP::stop() {
 void EditorDebuggerServerTCP::stop() {

+ 3 - 1
editor/debugger/editor_debugger_server.h

@@ -47,8 +47,10 @@ public:
 
 
 	static void register_protocol_handler(const String &p_protocol, CreateServerFunc p_func);
 	static void register_protocol_handler(const String &p_protocol, CreateServerFunc p_func);
 	static EditorDebuggerServer *create(const String &p_protocol);
 	static EditorDebuggerServer *create(const String &p_protocol);
+
+	virtual String get_uri() const = 0;
 	virtual void poll() = 0;
 	virtual void poll() = 0;
-	virtual Error start(const String &p_uri = "") = 0;
+	virtual Error start(const String &p_uri) = 0;
 	virtual void stop() = 0;
 	virtual void stop() = 0;
 	virtual bool is_active() const = 0;
 	virtual bool is_active() const = 0;
 	virtual bool is_connection_available() const = 0;
 	virtual bool is_connection_available() const = 0;

+ 2 - 10
editor/editor_node.cpp

@@ -2315,8 +2315,6 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
 	play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
 	play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
 
 
 	String run_filename;
 	String run_filename;
-	String args;
-	bool skip_breakpoints;
 
 
 	if (p_current || (editor_data.get_edited_scene_root() && p_custom != String() && p_custom == editor_data.get_edited_scene_root()->get_scene_file_path())) {
 	if (p_current || (editor_data.get_edited_scene_root() && p_custom != String() && p_custom == editor_data.get_edited_scene_root()->get_scene_file_path())) {
 		Node *scene = editor_data.get_edited_scene_root();
 		Node *scene = editor_data.get_edited_scene_root();
@@ -2371,17 +2369,11 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
 		make_bottom_panel_item_visible(log);
 		make_bottom_panel_item_visible(log);
 	}
 	}
 
 
-	List<String> breakpoints;
-	editor_data.get_editor_breakpoints(&breakpoints);
-
-	args = ProjectSettings::get_singleton()->get("editor/run/main_run_args");
-	skip_breakpoints = EditorDebuggerNode::get_singleton()->is_skip_breakpoints();
-
 	EditorDebuggerNode::get_singleton()->start();
 	EditorDebuggerNode::get_singleton()->start();
-	Error error = editor_run.run(run_filename, args, breakpoints, skip_breakpoints);
+	Error error = editor_run.run(run_filename);
 	if (error != OK) {
 	if (error != OK) {
 		EditorDebuggerNode::get_singleton()->stop();
 		EditorDebuggerNode::get_singleton()->stop();
-		show_accept(TTR("Could not start subprocess!"), TTR("OK"));
+		show_accept(TTR("Could not start subprocess(es)!"), TTR("OK"));
 		return;
 		return;
 	}
 	}
 
 

+ 16 - 14
editor/editor_run.cpp

@@ -31,6 +31,7 @@
 #include "editor_run.h"
 #include "editor_run.h"
 
 
 #include "core/config/project_settings.h"
 #include "core/config/project_settings.h"
+#include "editor/editor_node.h"
 #include "editor_settings.h"
 #include "editor_settings.h"
 #include "servers/display_server.h"
 #include "servers/display_server.h"
 
 
@@ -42,20 +43,17 @@ String EditorRun::get_running_scene() const {
 	return running_scene;
 	return running_scene;
 }
 }
 
 
-Error EditorRun::run(const String &p_scene, const String &p_custom_args, const List<String> &p_breakpoints, const bool &p_skip_breakpoints) {
+Error EditorRun::run(const String &p_scene) {
 	List<String> args;
 	List<String> args;
 
 
 	String resource_path = ProjectSettings::get_singleton()->get_resource_path();
 	String resource_path = ProjectSettings::get_singleton()->get_resource_path();
-	String remote_host = EditorSettings::get_singleton()->get("network/debug/remote_host");
-	int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
-
-	if (resource_path != "") {
+	if (!resource_path.is_empty()) {
 		args.push_back("--path");
 		args.push_back("--path");
 		args.push_back(resource_path.replace(" ", "%20"));
 		args.push_back(resource_path.replace(" ", "%20"));
 	}
 	}
 
 
 	args.push_back("--remote-debug");
 	args.push_back("--remote-debug");
-	args.push_back("tcp://" + remote_host + ":" + String::num(remote_port));
+	args.push_back(EditorDebuggerNode::get_singleton()->get_server_uri());
 
 
 	args.push_back("--allow_focus_steal_pid");
 	args.push_back("--allow_focus_steal_pid");
 	args.push_back(itos(OS::get_singleton()->get_process_id()));
 	args.push_back(itos(OS::get_singleton()->get_process_id()));
@@ -162,10 +160,13 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
 		} break;
 		} break;
 	}
 	}
 
 
-	if (p_breakpoints.size()) {
+	List<String> breakpoints;
+	EditorNode::get_editor_data().get_editor_breakpoints(&breakpoints);
+
+	if (!breakpoints.is_empty()) {
 		args.push_back("--breakpoints");
 		args.push_back("--breakpoints");
 		String bpoints;
 		String bpoints;
-		for (const List<String>::Element *E = p_breakpoints.front(); E; E = E->next()) {
+		for (const List<String>::Element *E = breakpoints.front(); E; E = E->next()) {
 			bpoints += E->get().replace(" ", "%20");
 			bpoints += E->get().replace(" ", "%20");
 			if (E->next()) {
 			if (E->next()) {
 				bpoints += ",";
 				bpoints += ",";
@@ -175,7 +176,7 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
 		args.push_back(bpoints);
 		args.push_back(bpoints);
 	}
 	}
 
 
-	if (p_skip_breakpoints) {
+	if (EditorDebuggerNode::get_singleton()->is_skip_breakpoints()) {
 		args.push_back("--skip-breakpoints");
 		args.push_back("--skip-breakpoints");
 	}
 	}
 
 
@@ -185,20 +186,21 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
 
 
 	String exec = OS::get_singleton()->get_executable_path();
 	String exec = OS::get_singleton()->get_executable_path();
 
 
-	if (p_custom_args != "") {
+	const String raw_custom_args = ProjectSettings::get_singleton()->get("editor/run/main_run_args");
+	if (!raw_custom_args.is_empty()) {
 		// Allow the user to specify a command to run, similar to Steam's launch options.
 		// 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
 		// 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 run it. For instance, this can be used on Linux to force a running project
 		// to use Optimus using `prime-run` or similar.
 		// to use Optimus using `prime-run` or similar.
 		// Example: `prime-run %command% --time-scale 0.5`
 		// Example: `prime-run %command% --time-scale 0.5`
-		const int placeholder_pos = p_custom_args.find("%command%");
+		const int placeholder_pos = raw_custom_args.find("%command%");
 
 
 		Vector<String> custom_args;
 		Vector<String> custom_args;
 
 
 		if (placeholder_pos != -1) {
 		if (placeholder_pos != -1) {
 			// Prepend executable-specific custom arguments.
 			// Prepend executable-specific custom arguments.
 			// If nothing is placed before `%command%`, behave as if no placeholder was specified.
 			// If nothing is placed before `%command%`, behave as if no placeholder was specified.
-			Vector<String> exec_args = p_custom_args.substr(0, placeholder_pos).split(" ", false);
+			Vector<String> exec_args = raw_custom_args.substr(0, placeholder_pos).split(" ", false);
 			if (exec_args.size() >= 1) {
 			if (exec_args.size() >= 1) {
 				exec = exec_args[0];
 				exec = exec_args[0];
 				exec_args.remove_at(0);
 				exec_args.remove_at(0);
@@ -214,13 +216,13 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
 			}
 			}
 
 
 			// Append Godot-specific custom arguments.
 			// Append Godot-specific custom arguments.
-			custom_args = p_custom_args.substr(placeholder_pos + String("%command%").size()).split(" ", false);
+			custom_args = raw_custom_args.substr(placeholder_pos + String("%command%").size()).split(" ", false);
 			for (int i = 0; i < custom_args.size(); i++) {
 			for (int i = 0; i < custom_args.size(); i++) {
 				args.push_back(custom_args[i].replace(" ", "%20"));
 				args.push_back(custom_args[i].replace(" ", "%20"));
 			}
 			}
 		} else {
 		} else {
 			// Append Godot-specific custom arguments.
 			// Append Godot-specific custom arguments.
-			custom_args = p_custom_args.split(" ", false);
+			custom_args = raw_custom_args.split(" ", false);
 			for (int i = 0; i < custom_args.size(); i++) {
 			for (int i = 0; i < custom_args.size(); i++) {
 				args.push_back(custom_args[i].replace(" ", "%20"));
 				args.push_back(custom_args[i].replace(" ", "%20"));
 			}
 			}

+ 1 - 1
editor/editor_run.h

@@ -50,7 +50,7 @@ private:
 public:
 public:
 	Status get_status() const;
 	Status get_status() const;
 	String get_running_scene() const;
 	String get_running_scene() const;
-	Error run(const String &p_scene, const String &p_custom_args, const List<String> &p_breakpoints, const bool &p_skip_breakpoints = false);
+	Error run(const String &p_scene);
 	void run_native_notify() { status = STATUS_PLAY; }
 	void run_native_notify() { status = STATUS_PLAY; }
 	void stop();
 	void stop();
 
 

+ 1 - 1
modules/gdscript/language_server/gdscript_language_server.h

@@ -45,7 +45,7 @@ class GDScriptLanguageServer : public EditorPlugin {
 	bool started = false;
 	bool started = false;
 	bool use_thread = false;
 	bool use_thread = false;
 	String host = "127.0.0.1";
 	String host = "127.0.0.1";
-	int port = 6008;
+	int port = 6005;
 	static void thread_main(void *p_userdata);
 	static void thread_main(void *p_userdata);
 
 
 private:
 private:

+ 32 - 2
modules/websocket/editor_debugger_server_websocket.cpp

@@ -31,6 +31,8 @@
 #include "editor_debugger_server_websocket.h"
 #include "editor_debugger_server_websocket.h"
 
 
 #include "core/config/project_settings.h"
 #include "core/config/project_settings.h"
+#include "editor/editor_log.h"
+#include "editor/editor_node.h"
 #include "editor/editor_settings.h"
 #include "editor/editor_settings.h"
 #include "modules/websocket/remote_debugger_peer_websocket.h"
 #include "modules/websocket/remote_debugger_peer_websocket.h"
 
 
@@ -48,19 +50,47 @@ void EditorDebuggerServerWebSocket::poll() {
 	server->poll();
 	server->poll();
 }
 }
 
 
+String EditorDebuggerServerWebSocket::get_uri() const {
+	return endpoint;
+}
+
 Error EditorDebuggerServerWebSocket::start(const String &p_uri) {
 Error EditorDebuggerServerWebSocket::start(const String &p_uri) {
+	// Default host and port
+	String bind_host = (String)EditorSettings::get_singleton()->get("network/debug/remote_host");
 	int bind_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
 	int bind_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
-	String bind_host = EditorSettings::get_singleton()->get("network/debug/remote_host");
+
+	// Optionally override
 	if (!p_uri.is_empty() && p_uri != "ws://") {
 	if (!p_uri.is_empty() && p_uri != "ws://") {
 		String scheme, path;
 		String scheme, path;
 		Error err = p_uri.parse_url(scheme, bind_host, bind_port, path);
 		Error err = p_uri.parse_url(scheme, bind_host, bind_port, path);
 		ERR_FAIL_COND_V(err != OK, ERR_INVALID_PARAMETER);
 		ERR_FAIL_COND_V(err != OK, ERR_INVALID_PARAMETER);
 		ERR_FAIL_COND_V(!bind_host.is_valid_ip_address() && bind_host != "*", ERR_INVALID_PARAMETER);
 		ERR_FAIL_COND_V(!bind_host.is_valid_ip_address() && bind_host != "*", ERR_INVALID_PARAMETER);
 	}
 	}
+
+	// Set up the server
 	server->set_bind_ip(bind_host);
 	server->set_bind_ip(bind_host);
 	Vector<String> compatible_protocols;
 	Vector<String> compatible_protocols;
 	compatible_protocols.push_back("binary"); // compatibility with EMSCRIPTEN TCP-to-WebSocket layer.
 	compatible_protocols.push_back("binary"); // compatibility with EMSCRIPTEN TCP-to-WebSocket layer.
-	return server->listen(bind_port, compatible_protocols);
+
+	// Try listening on ports
+	const int max_attempts = 5;
+	for (int attempt = 1;; ++attempt) {
+		const Error err = server->listen(bind_port, compatible_protocols);
+		if (err == OK) {
+			break;
+		}
+		if (attempt >= max_attempts) {
+			EditorNode::get_log()->add_message(vformat("Cannot listen on port %d, remote debugging unavailable.", bind_port), EditorLog::MSG_TYPE_ERROR);
+			return err;
+		}
+		int last_port = bind_port++;
+		EditorNode::get_log()->add_message(vformat("Cannot listen on port %d, trying %d instead.", last_port, bind_port), EditorLog::MSG_TYPE_WARNING);
+	}
+
+	// Endpoint that the client should connect to
+	endpoint = vformat("ws://%s:%d", bind_host, bind_port);
+
+	return OK;
 }
 }
 
 
 void EditorDebuggerServerWebSocket::stop() {
 void EditorDebuggerServerWebSocket::stop() {

+ 8 - 6
modules/websocket/editor_debugger_server_websocket.h

@@ -40,6 +40,7 @@ class EditorDebuggerServerWebSocket : public EditorDebuggerServer {
 private:
 private:
 	Ref<WebSocketServer> server;
 	Ref<WebSocketServer> server;
 	List<int> pending_peers;
 	List<int> pending_peers;
+	String endpoint;
 
 
 public:
 public:
 	static EditorDebuggerServer *create(const String &p_protocol);
 	static EditorDebuggerServer *create(const String &p_protocol);
@@ -47,12 +48,13 @@ public:
 	void _peer_connected(int p_peer, String p_protocol);
 	void _peer_connected(int p_peer, String p_protocol);
 	void _peer_disconnected(int p_peer, bool p_was_clean);
 	void _peer_disconnected(int p_peer, bool p_was_clean);
 
 
-	void poll() override;
-	Error start(const String &p_uri) override;
-	void stop() override;
-	bool is_active() const override;
-	bool is_connection_available() const override;
-	Ref<RemoteDebuggerPeer> take_connection() override;
+	virtual void poll() override;
+	virtual String get_uri() const override;
+	virtual Error start(const String &p_uri = "") override;
+	virtual void stop() override;
+	virtual bool is_active() const override;
+	virtual bool is_connection_available() const override;
+	virtual Ref<RemoteDebuggerPeer> take_connection() override;
 
 
 	EditorDebuggerServerWebSocket();
 	EditorDebuggerServerWebSocket();
 	~EditorDebuggerServerWebSocket();
 	~EditorDebuggerServerWebSocket();