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.
This commit is contained in:
Nathan Franke 2021-09-29 21:06:28 -05:00
parent 2a9dd654bc
commit de7873c2d8
No known key found for this signature in database
GPG Key ID: 92164DCCF3B1F723
10 changed files with 106 additions and 48 deletions

View File

@ -183,6 +183,11 @@ ScriptEditorDebugger *EditorDebuggerNode::get_default_debugger() const {
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) {
stop();
ERR_FAIL_COND_V(p_uri.find("://") < 0, ERR_INVALID_PARAMETER);

View File

@ -188,8 +188,9 @@ public:
void set_camera_override(CameraOverride p_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 add_debugger_plugin(const Ref<Script> &p_script);

View File

@ -41,15 +41,18 @@
class EditorDebuggerServerTCP : public EditorDebuggerServer {
private:
Ref<TCPServer> server;
String endpoint;
public:
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();
};
@ -63,21 +66,42 @@ EditorDebuggerServerTCP::EditorDebuggerServerTCP() {
server.instantiate();
}
String EditorDebuggerServerTCP::get_uri() const {
return endpoint;
}
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");
int bind_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
// Optionally override
if (!p_uri.is_empty() && p_uri != "tcp://") {
String scheme, 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(!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() {

View File

@ -47,8 +47,10 @@ public:
static void register_protocol_handler(const String &p_protocol, CreateServerFunc p_func);
static EditorDebuggerServer *create(const String &p_protocol);
virtual String get_uri() const = 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 bool is_active() const = 0;
virtual bool is_connection_available() const = 0;

View File

@ -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")));
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())) {
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);
}
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();
Error error = editor_run.run(run_filename, args, breakpoints, skip_breakpoints);
Error error = editor_run.run(run_filename);
if (error != OK) {
EditorDebuggerNode::get_singleton()->stop();
show_accept(TTR("Could not start subprocess!"), TTR("OK"));
show_accept(TTR("Could not start subprocess(es)!"), TTR("OK"));
return;
}

View File

@ -31,6 +31,7 @@
#include "editor_run.h"
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
#include "editor_settings.h"
#include "servers/display_server.h"
@ -42,20 +43,17 @@ String EditorRun::get_running_scene() const {
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;
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(resource_path.replace(" ", "%20"));
}
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(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;
}
if (p_breakpoints.size()) {
List<String> breakpoints;
EditorNode::get_editor_data().get_editor_breakpoints(&breakpoints);
if (!breakpoints.is_empty()) {
args.push_back("--breakpoints");
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");
if (E->next()) {
bpoints += ",";
@ -175,7 +176,7 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
args.push_back(bpoints);
}
if (p_skip_breakpoints) {
if (EditorDebuggerNode::get_singleton()->is_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();
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.
// 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%");
const int placeholder_pos = raw_custom_args.find("%command%");
Vector<String> 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<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) {
exec = exec_args[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.
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++) {
args.push_back(custom_args[i].replace(" ", "%20"));
}
} else {
// 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++) {
args.push_back(custom_args[i].replace(" ", "%20"));
}

View File

@ -50,7 +50,7 @@ private:
public:
Status get_status() 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 stop();

View File

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

View File

@ -31,6 +31,8 @@
#include "editor_debugger_server_websocket.h"
#include "core/config/project_settings.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "modules/websocket/remote_debugger_peer_websocket.h"
@ -48,19 +50,47 @@ void EditorDebuggerServerWebSocket::poll() {
server->poll();
}
String EditorDebuggerServerWebSocket::get_uri() const {
return endpoint;
}
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");
String bind_host = EditorSettings::get_singleton()->get("network/debug/remote_host");
// Optionally override
if (!p_uri.is_empty() && p_uri != "ws://") {
String scheme, 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(!bind_host.is_valid_ip_address() && bind_host != "*", ERR_INVALID_PARAMETER);
}
// Set up the server
server->set_bind_ip(bind_host);
Vector<String> compatible_protocols;
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() {

View File

@ -40,6 +40,7 @@ class EditorDebuggerServerWebSocket : public EditorDebuggerServer {
private:
Ref<WebSocketServer> server;
List<int> pending_peers;
String endpoint;
public:
static EditorDebuggerServer *create(const String &p_protocol);
@ -47,12 +48,13 @@ public:
void _peer_connected(int p_peer, String p_protocol);
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();