From beb87504e076afeb37e5f2765c8417f92a044e13 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Tue, 25 Feb 2020 19:26:04 +0100 Subject: [PATCH 1/4] Remove WebSocket defaults from project settings. Can be manually set, let's not pollute them further. Should also be done for WebRTC. --- modules/websocket/emws_client.cpp | 5 +++-- modules/websocket/register_types.cpp | 16 ---------------- modules/websocket/websocket_macros.h | 12 +++--------- modules/websocket/wsl_client.cpp | 8 ++++---- modules/websocket/wsl_server.cpp | 8 ++++---- 5 files changed, 14 insertions(+), 35 deletions(-) diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp index bceb65c315c..bc9d75d3279 100644 --- a/modules/websocket/emws_client.cpp +++ b/modules/websocket/emws_client.cpp @@ -231,8 +231,9 @@ Error EMWSClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffe } EMWSClient::EMWSClient() { - _in_buf_size = nearest_shift((int)GLOBAL_GET(WSC_IN_BUF) - 1) + 10; - _in_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_IN_PKT) - 1); + _in_buf_size = DEF_BUF_SHIFT; + _in_pkt_size = DEF_PKT_SHIFT; + _is_connecting = false; _peer = Ref(memnew(EMWSPeer)); /* clang-format off */ diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp index e389d75ffd8..11b13d4569d 100644 --- a/modules/websocket/register_types.cpp +++ b/modules/websocket/register_types.cpp @@ -42,22 +42,6 @@ #endif void register_websocket_types() { -#define _SET_HINT(NAME, _VAL_, _MAX_) \ - GLOBAL_DEF(NAME, _VAL_); \ - ProjectSettings::get_singleton()->set_custom_property_info(NAME, PropertyInfo(Variant::INT, NAME, PROPERTY_HINT_RANGE, "2," #_MAX_ ",1,or_greater")); - - // Client buffers project settings - _SET_HINT(WSC_IN_BUF, 64, 4096); - _SET_HINT(WSC_IN_PKT, 1024, 16384); - _SET_HINT(WSC_OUT_BUF, 64, 4096); - _SET_HINT(WSC_OUT_PKT, 1024, 16384); - - // Server buffers project settings - _SET_HINT(WSS_IN_BUF, 64, 4096); - _SET_HINT(WSS_IN_PKT, 1024, 16384); - _SET_HINT(WSS_OUT_BUF, 64, 4096); - _SET_HINT(WSS_OUT_PKT, 1024, 16384); - #ifdef JAVASCRIPT_ENABLED EMWSPeer::make_default(); EMWSClient::make_default(); diff --git a/modules/websocket/websocket_macros.h b/modules/websocket/websocket_macros.h index f7eafcff1fe..cf4545b435c 100644 --- a/modules/websocket/websocket_macros.h +++ b/modules/websocket/websocket_macros.h @@ -31,15 +31,9 @@ #ifndef WEBSOCKETMACTOS_H #define WEBSOCKETMACTOS_H -#define WSC_IN_BUF "network/limits/websocket_client/max_in_buffer_kb" -#define WSC_IN_PKT "network/limits/websocket_client/max_in_packets" -#define WSC_OUT_BUF "network/limits/websocket_client/max_out_buffer_kb" -#define WSC_OUT_PKT "network/limits/websocket_client/max_out_packets" - -#define WSS_IN_BUF "network/limits/websocket_server/max_in_buffer_kb" -#define WSS_IN_PKT "network/limits/websocket_server/max_in_packets" -#define WSS_OUT_BUF "network/limits/websocket_server/max_out_buffer_kb" -#define WSS_OUT_PKT "network/limits/websocket_server/max_out_packets" +// Defaults per peer buffers, 1024 packets with a shared 65536 bytes payload. +#define DEF_PKT_SHIFT 10 +#define DEF_BUF_SHIFT 16 /* clang-format off */ #define GDCICLASS(CNAME) \ diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp index 9f05500eb99..0eaafe2d666 100644 --- a/modules/websocket/wsl_client.cpp +++ b/modules/websocket/wsl_client.cpp @@ -336,10 +336,10 @@ Error WSLClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer } WSLClient::WSLClient() { - _in_buf_size = nearest_shift((int)GLOBAL_GET(WSC_IN_BUF) - 1) + 10; - _in_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_IN_PKT) - 1); - _out_buf_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_BUF) - 1) + 10; - _out_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_PKT) - 1); + _in_buf_size = DEF_BUF_SHIFT; + _in_pkt_size = DEF_PKT_SHIFT; + _out_buf_size = DEF_BUF_SHIFT; + _out_pkt_size = DEF_PKT_SHIFT; _peer.instance(); _tcp.instance(); diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp index 6f155a6ffa6..cc4685973ec 100644 --- a/modules/websocket/wsl_server.cpp +++ b/modules/websocket/wsl_server.cpp @@ -298,10 +298,10 @@ Error WSLServer::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer } WSLServer::WSLServer() { - _in_buf_size = nearest_shift((int)GLOBAL_GET(WSS_IN_BUF) - 1) + 10; - _in_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_IN_PKT) - 1); - _out_buf_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_BUF) - 1) + 10; - _out_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_PKT) - 1); + _in_buf_size = DEF_BUF_SHIFT; + _in_pkt_size = DEF_PKT_SHIFT; + _out_buf_size = DEF_BUF_SHIFT; + _out_pkt_size = DEF_PKT_SHIFT; _server.instance(); } From ed225faf31c9b3aa47154260aa1a7826d728acc8 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Wed, 11 Mar 2020 11:23:21 +0100 Subject: [PATCH 2/4] Add support for multiple RemoteDebuggerPeer(s). It is now possible to register protocol handlers (default tcp://) to support additional debugging communication layers (e.g. websocket). --- core/debugger/engine_debugger.cpp | 42 +++++++++++++++++--------- core/debugger/engine_debugger.h | 7 +++++ core/debugger/remote_debugger.cpp | 10 ++---- core/debugger/remote_debugger.h | 2 -- core/debugger/remote_debugger_peer.cpp | 14 +++++---- core/debugger/remote_debugger_peer.h | 4 ++- 6 files changed, 49 insertions(+), 30 deletions(-) diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp index bfe38d0f4a0..04eba84b30d 100644 --- a/core/debugger/engine_debugger.cpp +++ b/core/debugger/engine_debugger.cpp @@ -32,6 +32,7 @@ #include "core/debugger/local_debugger.h" #include "core/debugger/remote_debugger.h" +#include "core/debugger/remote_debugger_peer.h" #include "core/debugger/script_debugger.h" #include "core/os/os.h" @@ -40,6 +41,7 @@ ScriptDebugger *EngineDebugger::script_debugger = nullptr; Map EngineDebugger::profilers; Map EngineDebugger::captures; +Map EngineDebugger::protocols; void EngineDebugger::register_profiler(const StringName &p_name, const Profiler &p_func) { ERR_FAIL_COND_MSG(profilers.has(p_name), "Profiler already registered: " + p_name); @@ -66,6 +68,11 @@ void EngineDebugger::unregister_message_capture(const StringName &p_name) { captures.erase(p_name); } +void EngineDebugger::register_uri_handler(const String &p_protocol, CreatePeerFunc p_func) { + ERR_FAIL_COND_MSG(protocols.has(p_protocol), "Protocol handler already registered: " + p_protocol); + protocols.insert(p_protocol, p_func); +} + void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) { ERR_FAIL_COND_MSG(!profilers.has(p_name), "Can't change profiler state, no profiler: " + p_name); Profiler &p = profilers[p_name]; @@ -125,6 +132,7 @@ void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_idle_ticks, ui } void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Vector p_breakpoints) { + register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more. if (p_uri.empty()) return; if (p_uri == "local://") { @@ -132,10 +140,14 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Ve script_debugger = memnew(ScriptDebugger); // Tell the OS that we want to handle termination signals. OS::get_singleton()->initialize_debugging(); - } else { - singleton = RemoteDebugger::create_for_uri(p_uri); - if (!singleton) + } else if (p_uri.find("://") >= 0) { + const String proto = p_uri.substr(0, p_uri.find("://") + 3); + if (!protocols.has(proto)) return; + RemoteDebuggerPeer *peer = protocols[proto](p_uri); + if (!peer) + return; + singleton = memnew(RemoteDebugger(Ref(peer))); script_debugger = memnew(ScriptDebugger); // Notify editor of our pid (to allow focus stealing). Array msg; @@ -160,22 +172,24 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Ve } void EngineDebugger::deinitialize() { - if (!singleton) - return; + if (singleton) { + // Stop all profilers + for (Map::Element *E = profilers.front(); E; E = E->next()) { + if (E->get().active) + singleton->profiler_enable(E->key(), false); + } - // Stop all profilers - for (Map::Element *E = profilers.front(); E; E = E->next()) { - if (E->get().active) - singleton->profiler_enable(E->key(), false); + // Flush any remaining message + singleton->poll_events(false); + + memdelete(singleton); + singleton = nullptr; } - // Flush any remaining message - singleton->poll_events(false); - - memdelete(singleton); - singleton = nullptr; + // Clear profilers/captuers/protocol handlers. profilers.clear(); captures.clear(); + protocols.clear(); } EngineDebugger::~EngineDebugger() { diff --git a/core/debugger/engine_debugger.h b/core/debugger/engine_debugger.h index 7b6b77ca9b8..8d5ebb2394a 100644 --- a/core/debugger/engine_debugger.h +++ b/core/debugger/engine_debugger.h @@ -38,6 +38,7 @@ #include "core/variant.h" #include "core/vector.h" +class RemoteDebuggerPeer; class ScriptDebugger; class EngineDebugger { @@ -45,8 +46,11 @@ public: typedef void (*ProfilingToggle)(void *p_user, bool p_enable, const Array &p_opts); typedef void (*ProfilingTick)(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time); typedef void (*ProfilingAdd)(void *p_user, const Array &p_arr); + typedef Error (*CaptureFunc)(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured); + typedef RemoteDebuggerPeer *(*CreatePeerFunc)(const String &p_uri); + class Profiler { friend class EngineDebugger; @@ -94,6 +98,7 @@ protected: static Map profilers; static Map captures; + static Map protocols; public: _FORCE_INLINE_ static EngineDebugger *get_singleton() { return singleton; } @@ -113,6 +118,8 @@ public: static void unregister_message_capture(const StringName &p_name); static bool has_capture(const StringName &p_name); + static void register_uri_handler(const String &p_protocol, CreatePeerFunc p_func); + void iteration(uint64_t p_frame_ticks, uint64_t p_idle_ticks, uint64_t p_physics_ticks, float p_physics_frame_time); void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array()); Error capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured); diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 97d5c71b6f9..18c9602eb2a 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -673,6 +673,9 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { ERR_FAIL_COND_MSG(!is_peer_connected(), "Script Debugger failed to connect, but being used anyway."); + if (!peer->can_block()) + return; // Peer does not support blocking IO. We could at least send the error though. + ScriptLanguage *script_lang = script_debugger->get_break_language(); const String error_str = script_lang ? script_lang->debug_get_error() : ""; Array msg; @@ -886,13 +889,6 @@ Error RemoteDebugger::_profiler_capture(const String &p_cmd, const Array &p_data return OK; } -RemoteDebugger *RemoteDebugger::create_for_uri(const String &p_uri) { - Ref peer = RemoteDebuggerPeer::create_from_uri(p_uri); - if (peer.is_valid()) - return memnew(RemoteDebugger(peer)); - return nullptr; -} - RemoteDebugger::RemoteDebugger(Ref p_peer) { peer = p_peer; max_chars_per_second = GLOBAL_GET("network/limits/debugger/max_chars_per_second"); diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h index cac0bc3730b..dc7e4436e1e 100644 --- a/core/debugger/remote_debugger.h +++ b/core/debugger/remote_debugger.h @@ -108,8 +108,6 @@ private: Error _try_capture(const String &p_name, const Array &p_data, bool &r_captured); public: - static RemoteDebugger *create_for_uri(const String &p_uri); - // Overrides void poll_events(bool p_is_idle); void send_message(const String &p_message, const Array &p_args); diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp index ed044311771..458c46df935 100644 --- a/core/debugger/remote_debugger_peer.cpp +++ b/core/debugger/remote_debugger_peer.cpp @@ -218,9 +218,8 @@ void RemoteDebuggerPeerTCP::_poll() { } } -Ref RemoteDebuggerPeer::create_from_uri(const String p_uri) { - if (!p_uri.begins_with("tcp://")) - return Ref(); // Only TCP supported for now, more to come. +RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) { + ERR_FAIL_COND_V(!p_uri.begins_with("tcp://"), nullptr); String debug_host = p_uri.replace("tcp://", ""); uint16_t debug_port = 6007; @@ -230,10 +229,13 @@ Ref RemoteDebuggerPeer::create_from_uri(const String p_uri) debug_port = debug_host.substr(sep_pos + 1).to_int(); debug_host = debug_host.substr(0, sep_pos); } - Ref peer = Ref(memnew(RemoteDebuggerPeerTCP)); + + RemoteDebuggerPeerTCP *peer = memnew(RemoteDebuggerPeerTCP); Error err = peer->connect_to_host(debug_host, debug_port); - if (err != OK) - return Ref(); + if (err != OK) { + memdelete(peer); + return nullptr; + } return peer; } diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h index e4b838f1452..3a75a2a02b8 100644 --- a/core/debugger/remote_debugger_peer.h +++ b/core/debugger/remote_debugger_peer.h @@ -42,7 +42,6 @@ protected: int max_queued_messages = 4096; public: - static Ref create_from_uri(const String p_uri); virtual bool is_peer_connected() = 0; virtual bool has_message() = 0; virtual Error put_message(const Array &p_arr) = 0; @@ -50,6 +49,7 @@ public: virtual void close() = 0; virtual void poll() = 0; virtual int get_max_message_size() const = 0; + virtual bool can_block() const { return true; } // If blocking io is allowed on main thread (debug). RemoteDebuggerPeer(); }; @@ -77,6 +77,8 @@ private: void _read_in(); public: + static RemoteDebuggerPeer *create(const String &p_uri); + Error connect_to_host(const String &p_host, uint16_t p_port); void poll(); From d79e28c3021a4410f41a3bbff111d56b28f155ef Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Mon, 16 Mar 2020 09:37:43 +0100 Subject: [PATCH 3/4] Support multiple debug protocols. --- editor/debugger/editor_debugger_node.cpp | 12 ++----- editor/debugger/editor_debugger_node.h | 2 +- editor/debugger/editor_debugger_server.cpp | 27 +++++++++++++-- editor/debugger/editor_debugger_server.h | 12 ++++++- editor/debugger/script_editor_debugger.cpp | 2 ++ editor/editor_export.cpp | 4 +-- editor/editor_export.h | 1 + editor/editor_node.cpp | 39 ++++++++++++---------- editor/editor_node.h | 3 +- editor/editor_run.cpp | 2 +- editor/editor_run_native.cpp | 4 +-- editor/plugins/debugger_editor_plugin.cpp | 4 +++ main/main.cpp | 7 ++-- 13 files changed, 78 insertions(+), 41 deletions(-) diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 75512143364..5bfb79806e0 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -173,7 +173,7 @@ ScriptEditorDebugger *EditorDebuggerNode::get_default_debugger() const { return Object::cast_to(tabs->get_tab_control(0)); } -Error EditorDebuggerNode::start() { +Error EditorDebuggerNode::start(const String &p_protocol) { stop(); if (EDITOR_GET("run/output/always_open_output_on_play")) { EditorNode::get_singleton()->make_bottom_panel_item_visible(EditorNode::get_log()); @@ -181,7 +181,7 @@ Error EditorDebuggerNode::start() { EditorNode::get_singleton()->make_bottom_panel_item_visible(this); } - server = Ref(EditorDebuggerServer::create_default()); + server = Ref(EditorDebuggerServer::create(p_protocol)); const Error err = server->start(); if (err != OK) { return err; @@ -213,14 +213,6 @@ void EditorDebuggerNode::stop() { void EditorDebuggerNode::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - EditorNode::get_singleton()->connect("play_pressed", callable_mp(this, &EditorDebuggerNode::start)); - EditorNode::get_singleton()->connect("stop_pressed", callable_mp(this, &EditorDebuggerNode::stop)); - } break; - case NOTIFICATION_EXIT_TREE: { - EditorNode::get_singleton()->disconnect("play_pressed", callable_mp(this, &EditorDebuggerNode::start)); - EditorNode::get_singleton()->disconnect("stop_pressed", callable_mp(this, &EditorDebuggerNode::stop)); - } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { if (tabs->get_tab_count() > 1) { add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT)); diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h index 9467442c9a1..7546febd05b 100644 --- a/editor/debugger/editor_debugger_node.h +++ b/editor/debugger/editor_debugger_node.h @@ -183,7 +183,7 @@ public: void set_camera_override(CameraOverride p_override) { camera_override = p_override; } CameraOverride get_camera_override() { return camera_override; } - Error start(); + Error start(const String &p_protocol = "tcp://"); void stop(); }; diff --git a/editor/debugger/editor_debugger_server.cpp b/editor/debugger/editor_debugger_server.cpp index c80988a6621..33f20d9a12e 100644 --- a/editor/debugger/editor_debugger_server.cpp +++ b/editor/debugger/editor_debugger_server.cpp @@ -44,6 +44,7 @@ private: Ref server; public: + static EditorDebuggerServer *create(const String &p_protocol); virtual void poll() {} virtual Error start(); virtual void stop(); @@ -54,6 +55,11 @@ public: EditorDebuggerServerTCP(); }; +EditorDebuggerServer *EditorDebuggerServerTCP::create(const String &p_protocol) { + ERR_FAIL_COND_V(p_protocol != "tcp://", nullptr); + return memnew(EditorDebuggerServerTCP); +} + EditorDebuggerServerTCP::EditorDebuggerServerTCP() { server.instance(); } @@ -85,6 +91,23 @@ Ref EditorDebuggerServerTCP::take_connection() { return memnew(RemoteDebuggerPeerTCP(server->take_connection())); } -EditorDebuggerServer *EditorDebuggerServer::create_default() { - return memnew(EditorDebuggerServerTCP); +/// EditorDebuggerServer +Map EditorDebuggerServer::protocols; + +EditorDebuggerServer *EditorDebuggerServer::create(const String &p_protocol) { + ERR_FAIL_COND_V(!protocols.has(p_protocol), nullptr); + return protocols[p_protocol](p_protocol); +} + +void EditorDebuggerServer::register_protocol_handler(const String &p_protocol, CreateServerFunc p_func) { + ERR_FAIL_COND(protocols.has(p_protocol)); + protocols[p_protocol] = p_func; +} + +void EditorDebuggerServer::initialize() { + register_protocol_handler("tcp://", EditorDebuggerServerTCP::create); +} + +void EditorDebuggerServer::deinitialize() { + protocols.clear(); } diff --git a/editor/debugger/editor_debugger_server.h b/editor/debugger/editor_debugger_server.h index e9798c90b3d..515ffce6289 100644 --- a/editor/debugger/editor_debugger_server.h +++ b/editor/debugger/editor_debugger_server.h @@ -37,7 +37,17 @@ class EditorDebuggerServer : public Reference { public: - static EditorDebuggerServer *create_default(); + typedef EditorDebuggerServer *(*CreateServerFunc)(const String &p_uri); + +private: + static Map protocols; + +public: + static void initialize(); + static void deinitialize(); + + static void register_protocol_handler(const String &p_protocol, CreateServerFunc p_func); + static EditorDebuggerServer *create(const String &p_protocol); virtual void poll() = 0; virtual Error start() = 0; virtual void stop() = 0; diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index af79de2991a..3ed271c7c6e 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -846,6 +846,8 @@ void ScriptEditorDebugger::_notification(int p_what) { if (is_session_active()) { + peer->poll(); + if (camera_override == CameraOverride::OVERRIDE_2D) { CanvasItemEditor *editor = CanvasItemEditor::get_singleton(); diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index e8167070d4c..24a69fe0038 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -284,7 +284,7 @@ void EditorExportPlatform::gen_debug_flags(Vector &r_flags, int p_flags) r_flags.push_back("--remote-debug"); - r_flags.push_back(host + ":" + String::num(remote_port)); + r_flags.push_back(get_debug_protocol() + host + ":" + String::num(remote_port)); List breakpoints; ScriptEditor::get_singleton()->get_breakpoints(&breakpoints); @@ -1127,7 +1127,7 @@ void EditorExportPlatform::gen_export_flags(Vector &r_flags, int p_flags r_flags.push_back("--remote-debug"); - r_flags.push_back(host + ":" + String::num(remote_port)); + r_flags.push_back(get_debug_protocol() + host + ":" + String::num(remote_port)); List breakpoints; ScriptEditor::get_singleton()->get_breakpoints(&breakpoints); diff --git a/editor/editor_export.h b/editor/editor_export.h index f47fe9c95e1..50d1ff66c6b 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -270,6 +270,7 @@ public: virtual Error export_zip(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags = 0); virtual void get_platform_features(List *r_features) = 0; virtual void resolve_platform_feature_priorities(const Ref &p_preset, Set &p_features) = 0; + virtual String get_debug_protocol() const { return "tcp://"; } EditorExportPlatform(); }; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 1b1ce4ec37a..abb639254a1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2072,9 +2072,11 @@ void EditorNode::_run(bool p_current, const String &p_custom) { args = ProjectSettings::get_singleton()->get("editor/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); if (error != OK) { + EditorDebuggerNode::get_singleton()->stop(); show_accept(TTR("Could not start subprocess!"), TTR("OK")); return; } @@ -2096,6 +2098,24 @@ void EditorNode::_run(bool p_current, const String &p_custom) { _playing_edited = p_current; } +void EditorNode::_run_native(const Ref &p_preset) { + + bool autosave = EDITOR_GET("run/auto_save/save_before_running"); + if (autosave) { + _menu_option_confirm(FILE_SAVE_ALL_SCENES, false); + } + if (run_native->is_deploy_debug_remote_enabled()) { + _menu_option_confirm(RUN_STOP, true); + + if (!call_build()) + return; // build failed + + EditorDebuggerNode::get_singleton()->start(p_preset->get_platform()->get_debug_protocol()); + emit_signal("play_pressed"); + editor_run.run_native_notify(); + } +} + void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!p_confirmed) //this may be a hack.. @@ -2464,6 +2484,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } } + EditorDebuggerNode::get_singleton()->stop(); emit_signal("stop_pressed"); } break; @@ -2482,22 +2503,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { _run(true); } break; - case RUN_PLAY_NATIVE: { - - bool autosave = EDITOR_GET("run/auto_save/save_before_running"); - if (autosave) { - _menu_option_confirm(FILE_SAVE_ALL_SCENES, false); - } - if (run_native->is_deploy_debug_remote_enabled()) { - _menu_option_confirm(RUN_STOP, true); - - if (!call_build()) - break; // build failed - - emit_signal("play_pressed"); - editor_run.run_native_notify(); - } - } break; case RUN_SCENE_SETTINGS: { run_settings_dialog->popup_run_settings(); @@ -6346,7 +6351,7 @@ EditorNode::EditorNode() { run_native = memnew(EditorRunNative); play_hb->add_child(run_native); - run_native->connect("native_run", callable_mp(this, &EditorNode::_menu_option), varray(RUN_PLAY_NATIVE)); + run_native->connect("native_run", callable_mp(this, &EditorNode::_run_native)); play_scene_button = memnew(ToolButton); play_hb->add_child(play_scene_button); diff --git a/editor/editor_node.h b/editor/editor_node.h index c6f04b07495..11f40089362 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -32,6 +32,7 @@ #define EDITOR_NODE_H #include "editor/editor_data.h" +#include "editor/editor_export.h" #include "editor/editor_folding.h" #include "editor/editor_run.h" #include "editor/inspector_dock.h" @@ -161,7 +162,6 @@ private: RUN_STOP, RUN_PLAY_SCENE, - RUN_PLAY_NATIVE, RUN_PLAY_CUSTOM_SCENE, RUN_SCENE_SETTINGS, RUN_SETTINGS, @@ -492,6 +492,7 @@ private: void _quick_run(); void _run(bool p_current = false, const String &p_custom = ""); + void _run_native(const Ref &p_preset); void _save_optimized(); void _import_action(const String &p_action); diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp index b4ddb7ebfa3..01156d98094 100644 --- a/editor/editor_run.cpp +++ b/editor/editor_run.cpp @@ -53,7 +53,7 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L } args.push_back("--remote-debug"); - args.push_back(remote_host + ":" + String::num(remote_port)); + args.push_back("tcp://" + remote_host + ":" + String::num(remote_port)); args.push_back("--allow_focus_steal_pid"); args.push_back(itos(OS::get_singleton()->get_process_id())); diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index 464666ac6ae..d4450acea25 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -133,7 +133,7 @@ void EditorRunNative::_run_native(int p_idx, int p_platform) { return; } - emit_signal("native_run"); + emit_signal("native_run", preset); int flags = 0; @@ -160,7 +160,7 @@ void EditorRunNative::resume_run_native() { void EditorRunNative::_bind_methods() { - ADD_SIGNAL(MethodInfo("native_run")); + ADD_SIGNAL(MethodInfo("native_run", PropertyInfo(Variant::OBJECT, "preset", PROPERTY_HINT_RESOURCE_TYPE, "EditorExportPreset"))); } bool EditorRunNative::is_deploy_debug_remote_enabled() const { diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp index 2b0d3f2582b..e0d345663cc 100644 --- a/editor/plugins/debugger_editor_plugin.cpp +++ b/editor/plugins/debugger_editor_plugin.cpp @@ -32,11 +32,14 @@ #include "core/os/keyboard.h" #include "editor/debugger/editor_debugger_node.h" +#include "editor/debugger/editor_debugger_server.h" #include "editor/editor_node.h" #include "editor/fileserver/editor_file_server.h" #include "scene/gui/menu_button.h" DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_debug_menu) { + EditorDebuggerServer::initialize(); + ED_SHORTCUT("debugger/step_into", TTR("Step Into"), KEY_F11); ED_SHORTCUT("debugger/step_over", TTR("Step Over"), KEY_F10); ED_SHORTCUT("debugger/break", TTR("Break")); @@ -96,6 +99,7 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_d } DebuggerEditorPlugin::~DebuggerEditorPlugin() { + EditorDebuggerServer::deinitialize(); memdelete(file_server); } diff --git a/main/main.cpp b/main/main.cpp index 83c3e190a83..958d964b353 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -324,7 +324,7 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(" -b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n"); OS::get_singleton()->print(" --profiling Enable profiling in the script debugger.\n"); OS::get_singleton()->print(" --gpu-abort Abort on GPU errors (usually validation layer errors), may help see the problem if your system freezes.\n"); - OS::get_singleton()->print(" --remote-debug
Remote debug (: address).\n"); + OS::get_singleton()->print(" --remote-debug Remote debug (://[:], e.g. tcp://127.0.0.1:6007).\n"); #if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED) OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n"); OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n"); @@ -844,11 +844,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph if (I->next()) { debug_uri = I->next()->get(); - if (debug_uri.find(":") == -1) { // wrong address - OS::get_singleton()->print("Invalid debug host address, it should be of the form :.\n"); + if (debug_uri.find("://") == -1) { // wrong address + OS::get_singleton()->print("Invalid debug host address, it should be of the form ://:.\n"); goto error; } - debug_uri = "tcp://" + debug_uri; // will support multiple protocols eventually. N = I->next()->next(); } else { OS::get_singleton()->print("Missing remote debug host address, aborting.\n"); From 3097c2da963fe355c81816a74824170b6dce697c Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Mon, 16 Mar 2020 17:02:14 +0100 Subject: [PATCH 4/4] Add WebSocket debugger, use it for Javascript. --- misc/dist/html/fixed-size.html | 3 +- misc/dist/html/full-size.html | 3 +- .../editor_debugger_server_websocket.cpp | 92 ++++++++++++ .../editor_debugger_server_websocket.h | 63 ++++++++ modules/websocket/register_types.cpp | 8 ++ .../remote_debugger_peer_websocket.cpp | 134 ++++++++++++++++++ .../remote_debugger_peer_websocket.h | 66 +++++++++ platform/javascript/export/export.cpp | 16 ++- platform/javascript/os_javascript.cpp | 11 ++ 9 files changed, 390 insertions(+), 6 deletions(-) create mode 100644 modules/websocket/editor_debugger_server_websocket.cpp create mode 100644 modules/websocket/editor_debugger_server_websocket.h create mode 100644 modules/websocket/remote_debugger_peer_websocket.cpp create mode 100644 modules/websocket/remote_debugger_peer_websocket.h diff --git a/misc/dist/html/fixed-size.html b/misc/dist/html/fixed-size.html index e7a23b3f296..a5633115d5a 100644 --- a/misc/dist/html/fixed-size.html +++ b/misc/dist/html/fixed-size.html @@ -232,6 +232,7 @@ $GODOT_HEAD_INCLUDE const EXECUTABLE_NAME = '$GODOT_BASENAME'; const MAIN_PACK = '$GODOT_BASENAME.pck'; + const EXTRA_ARGS = JSON.parse('$GODOT_ARGS'); const DEBUG_ENABLED = $GODOT_DEBUG_ENABLED; const INDETERMINATE_STATUS_STEP_MS = 100; @@ -382,7 +383,7 @@ $GODOT_HEAD_INCLUDE } else { setStatusMode('indeterminate'); engine.setCanvas(canvas); - engine.startGame(EXECUTABLE_NAME, MAIN_PACK).then(() => { + engine.startGame(EXECUTABLE_NAME, MAIN_PACK, EXTRA_ARGS).then(() => { setStatusMode('hidden'); initializing = false; }, displayFailureNotice); diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html index c3b67e0c4af..435013cb5e3 100644 --- a/misc/dist/html/full-size.html +++ b/misc/dist/html/full-size.html @@ -145,6 +145,7 @@ $GODOT_HEAD_INCLUDE const EXECUTABLE_NAME = '$GODOT_BASENAME'; const MAIN_PACK = '$GODOT_BASENAME.pck'; + const EXTRA_ARGS = JSON.parse('$GODOT_ARGS'); const INDETERMINATE_STATUS_STEP_MS = 100; var canvas = document.getElementById('canvas'); @@ -254,7 +255,7 @@ $GODOT_HEAD_INCLUDE } else { setStatusMode('indeterminate'); engine.setCanvas(canvas); - engine.startGame(EXECUTABLE_NAME, MAIN_PACK).then(() => { + engine.startGame(EXECUTABLE_NAME, MAIN_PACK, EXTRA_ARGS).then(() => { setStatusMode('hidden'); initializing = false; }, displayFailureNotice); diff --git a/modules/websocket/editor_debugger_server_websocket.cpp b/modules/websocket/editor_debugger_server_websocket.cpp new file mode 100644 index 00000000000..cc8507227ee --- /dev/null +++ b/modules/websocket/editor_debugger_server_websocket.cpp @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* script_editor_debugger_websocket.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_debugger_server_websocket.h" + +#include "core/project_settings.h" +#include "editor/editor_settings.h" +#include "modules/websocket/remote_debugger_peer_websocket.h" + +void EditorDebuggerServerWebSocket::_peer_connected(int p_id, String _protocol) { + pending_peers.push_back(p_id); +} + +void EditorDebuggerServerWebSocket::_peer_disconnected(int p_id, bool p_was_clean) { + if (pending_peers.find(p_id)) + pending_peers.erase(p_id); +} + +void EditorDebuggerServerWebSocket::poll() { + server->poll(); +} + +Error EditorDebuggerServerWebSocket::start() { + int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); + Vector protocols; + protocols.push_back("binary"); // compatibility with EMSCRIPTEN TCP-to-WebSocket layer. + return server->listen(remote_port, protocols); +} + +void EditorDebuggerServerWebSocket::stop() { + server->stop(); + pending_peers.clear(); +} + +bool EditorDebuggerServerWebSocket::is_active() const { + return server->is_listening(); +} + +bool EditorDebuggerServerWebSocket::is_connection_available() const { + return pending_peers.size() > 0; +} + +Ref EditorDebuggerServerWebSocket::take_connection() { + ERR_FAIL_COND_V(!is_connection_available(), Ref()); + RemoteDebuggerPeer *peer = memnew(RemoteDebuggerPeerWebSocket(server->get_peer(pending_peers[0]))); + pending_peers.pop_front(); + return peer; +} + +EditorDebuggerServerWebSocket::EditorDebuggerServerWebSocket() { + server = Ref(WebSocketServer::create()); + int max_pkts = (int)GLOBAL_GET("network/limits/debugger/max_queued_messages"); + server->set_buffers(8192, max_pkts, 8192, max_pkts); + server->connect("client_connected", callable_mp(this, &EditorDebuggerServerWebSocket::_peer_connected)); + server->connect("client_disconnected", callable_mp(this, &EditorDebuggerServerWebSocket::_peer_disconnected)); +} + +EditorDebuggerServerWebSocket::~EditorDebuggerServerWebSocket() { + stop(); +} + +EditorDebuggerServer *EditorDebuggerServerWebSocket::create(const String &p_protocol) { + ERR_FAIL_COND_V(p_protocol != "ws://", NULL); + return memnew(EditorDebuggerServerWebSocket); +} diff --git a/modules/websocket/editor_debugger_server_websocket.h b/modules/websocket/editor_debugger_server_websocket.h new file mode 100644 index 00000000000..81a31d83647 --- /dev/null +++ b/modules/websocket/editor_debugger_server_websocket.h @@ -0,0 +1,63 @@ +/*************************************************************************/ +/* script_editor_debugger_websocket.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SCRIPT_EDITOR_DEBUGGER_WEBSOCKET_H +#define SCRIPT_EDITOR_DEBUGGER_WEBSOCKET_H + +#include "modules/websocket/websocket_server.h" + +#include "editor/debugger/editor_debugger_server.h" + +class EditorDebuggerServerWebSocket : public EditorDebuggerServer { + + GDCLASS(EditorDebuggerServerWebSocket, EditorDebuggerServer); + +private: + Ref server; + List pending_peers; + +public: + static EditorDebuggerServer *create(const String &p_protocol); + + void _peer_connected(int p_peer, String p_protocol); + void _peer_disconnected(int p_peer, bool p_was_clean); + + void poll(); + Error start(); + void stop(); + bool is_active() const; + bool is_connection_available() const; + Ref take_connection(); + + EditorDebuggerServerWebSocket(); + ~EditorDebuggerServerWebSocket(); +}; + +#endif // SCRIPT_EDITOR_DEBUGGER_WEBSOCKET_H diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp index 11b13d4569d..1ad249e1eb2 100644 --- a/modules/websocket/register_types.cpp +++ b/modules/websocket/register_types.cpp @@ -40,6 +40,10 @@ #include "wsl_client.h" #include "wsl_server.h" #endif +#ifdef TOOLS_ENABLED +#include "editor/debugger/editor_debugger_server.h" +#include "editor_debugger_server_websocket.h" +#endif void register_websocket_types() { #ifdef JAVASCRIPT_ENABLED @@ -56,6 +60,10 @@ void register_websocket_types() { ClassDB::register_custom_instance_class(); ClassDB::register_custom_instance_class(); ClassDB::register_custom_instance_class(); + +#ifdef TOOLS_ENABLED + EditorDebuggerServer::register_protocol_handler("ws://", EditorDebuggerServerWebSocket::create); +#endif } void unregister_websocket_types() {} diff --git a/modules/websocket/remote_debugger_peer_websocket.cpp b/modules/websocket/remote_debugger_peer_websocket.cpp new file mode 100644 index 00000000000..f132b58e05d --- /dev/null +++ b/modules/websocket/remote_debugger_peer_websocket.cpp @@ -0,0 +1,134 @@ +/*************************************************************************/ +/* script_debugger_websocket.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "remote_debugger_peer_websocket.h" + +#include "core/project_settings.h" + +Error RemoteDebuggerPeerWebSocket::connect_to_host(const String &p_uri) { + + Vector protocols; + protocols.push_back("binary"); // Compatibility for emscripten TCP-to-WebSocket. + + ws_client->connect_to_url(p_uri, protocols); + ws_client->poll(); + + if (ws_client->get_connection_status() == WebSocketClient::CONNECTION_DISCONNECTED) { + + ERR_PRINT("Remote Debugger: Unable to connect. Status: " + String::num(ws_client->get_connection_status()) + "."); + return FAILED; + } + + ws_peer = ws_client->get_peer(1); + + return OK; +} + +bool RemoteDebuggerPeerWebSocket::is_peer_connected() { + return ws_peer.is_valid() && ws_peer->is_connected_to_host(); +} + +void RemoteDebuggerPeerWebSocket::poll() { + ws_client->poll(); + + while (ws_peer->is_connected_to_host() && ws_peer->get_available_packet_count() > 0 && in_queue.size() < max_queued_messages) { + Variant var; + Error err = ws_peer->get_var(var); + ERR_CONTINUE(err != OK); + ERR_CONTINUE(var.get_type() != Variant::ARRAY); + in_queue.push_back(var); + } + + while (ws_peer->is_connected_to_host() && out_queue.size() > 0) { + Array var = out_queue[0]; + Error err = ws_peer->put_var(var); + ERR_BREAK(err != OK); // Peer buffer full? + out_queue.pop_front(); + } +} + +int RemoteDebuggerPeerWebSocket::get_max_message_size() const { + return 8 << 20; // 8 Mib +} + +bool RemoteDebuggerPeerWebSocket::has_message() { + return in_queue.size() > 0; +} + +Array RemoteDebuggerPeerWebSocket::get_message() { + ERR_FAIL_COND_V(in_queue.size() < 1, Array()); + Array msg = in_queue[0]; + in_queue.pop_front(); + return msg; +} + +Error RemoteDebuggerPeerWebSocket::put_message(const Array &p_arr) { + if (out_queue.size() >= max_queued_messages) + return ERR_OUT_OF_MEMORY; + out_queue.push_back(p_arr); + return OK; +} + +void RemoteDebuggerPeerWebSocket::close() { + if (ws_peer.is_valid()) { + ws_peer.unref(); + } + ws_client->disconnect_from_host(); +} + +bool RemoteDebuggerPeerWebSocket::can_block() const { +#ifdef JAVASCRIPT_ENABLED + return false; +#else + return true; +#endif +} + +RemoteDebuggerPeerWebSocket::RemoteDebuggerPeerWebSocket(Ref p_peer) { +#ifdef JAVASCRIPT_ENABLED + ws_client = Ref(memnew(EMWSClient)); +#else + ws_client = Ref(memnew(WSLClient)); +#endif + max_queued_messages = (int)GLOBAL_GET("network/limits/debugger/max_queued_messages"); + ws_client->set_buffers(8192, max_queued_messages, 8192, max_queued_messages); + ws_peer = p_peer; +} + +RemoteDebuggerPeer *RemoteDebuggerPeerWebSocket::create(const String &p_uri) { + ERR_FAIL_COND_V(!p_uri.begins_with("ws://") && !p_uri.begins_with("wss://"), NULL); + RemoteDebuggerPeerWebSocket *peer = memnew(RemoteDebuggerPeerWebSocket); + Error err = peer->connect_to_host(p_uri); + if (err != OK) { + memdelete(peer); + return NULL; + } + return peer; +} diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h new file mode 100644 index 00000000000..fe46533beda --- /dev/null +++ b/modules/websocket/remote_debugger_peer_websocket.h @@ -0,0 +1,66 @@ +/*************************************************************************/ +/* script_debugger_websocket.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SCRIPT_DEBUGGER_WEBSOCKET_H +#define SCRIPT_DEBUGGER_WEBSOCKET_H + +#ifdef JAVASCRIPT_ENABLED +#include "modules/websocket/emws_client.h" +#else +#include "modules/websocket/wsl_client.h" +#endif +#include "core/debugger/remote_debugger_peer.h" + +class RemoteDebuggerPeerWebSocket : public RemoteDebuggerPeer { + + Ref ws_client; + Ref ws_peer; + List in_queue; + List out_queue; + + int max_queued_messages; + +public: + static RemoteDebuggerPeer *create(const String &p_uri); + + Error connect_to_host(const String &p_uri); + bool is_peer_connected(); + int get_max_message_size() const; + bool has_message(); + Error put_message(const Array &p_arr); + Array get_message(); + void close(); + void poll(); + bool can_block() const; + + RemoteDebuggerPeerWebSocket(Ref p_peer = Ref()); +}; + +#endif // SCRIPT_DEBUGGER_WEBSOCKET_H diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 36076a2af9f..fbc298a3994 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "core/io/json.h" #include "core/io/tcp_server.h" #include "core/io/zip_io.h" #include "editor/editor_export.h" @@ -198,7 +199,7 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform { Ref stop_icon; int menu_options; - void _fix_html(Vector &p_html, const Ref &p_preset, const String &p_name, bool p_debug); + void _fix_html(Vector &p_html, const Ref &p_preset, const String &p_name, bool p_debug, int p_flags); private: Ref server; @@ -238,15 +239,21 @@ public: virtual void resolve_platform_feature_priorities(const Ref &p_preset, Set &p_features) { } + String get_debug_protocol() const { return "ws://"; } + EditorExportPlatformJavaScript(); ~EditorExportPlatformJavaScript(); }; -void EditorExportPlatformJavaScript::_fix_html(Vector &p_html, const Ref &p_preset, const String &p_name, bool p_debug) { +void EditorExportPlatformJavaScript::_fix_html(Vector &p_html, const Ref &p_preset, const String &p_name, bool p_debug, int p_flags) { String str_template = String::utf8(reinterpret_cast(p_html.ptr()), p_html.size()); String str_export; Vector lines = str_template.split("\n"); + Vector flags; + String flags_json; + gen_export_flags(flags, p_flags); + flags_json = JSON::print(flags); for (int i = 0; i < lines.size(); i++) { @@ -255,6 +262,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector &p_html, const Re current_line = current_line.replace("$GODOT_PROJECT_NAME", ProjectSettings::get_singleton()->get_setting("application/config/name")); current_line = current_line.replace("$GODOT_HEAD_INCLUDE", p_preset->get("html/head_include")); current_line = current_line.replace("$GODOT_DEBUG_ENABLED", p_debug ? "true" : "false"); + current_line = current_line.replace("$GODOT_ARGS", flags_json); str_export += current_line + "\n"; } @@ -430,7 +438,7 @@ Error EditorExportPlatformJavaScript::export_project(const Refget_len()); f->get_buffer(buf.ptrw(), buf.size()); memdelete(f); - _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug); + _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug, p_flags); f = FileAccess::open(p_path, FileAccess::WRITE); if (!f) { diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 205644ce513..1ec23973d6e 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -30,13 +30,19 @@ #include "os_javascript.h" +#include "core/debugger/engine_debugger.h" #include "core/io/file_access_buffered_fa.h" #include "core/io/json.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" #include "main/main.h" +#include "modules/modules_enabled.gen.h" #include "platform/javascript/display_server_javascript.h" +#ifdef MODULE_WEBSOCKET_ENABLED +#include "modules/websocket/remote_debugger_peer_websocket.h" +#endif + #include #include @@ -68,6 +74,11 @@ void OS_JavaScript::initialize() { FileAccess::make_default>(FileAccess::ACCESS_RESOURCES); DisplayServerJavaScript::register_javascript_driver(); +#ifdef MODULE_WEBSOCKET_ENABLED + EngineDebugger::register_uri_handler("ws://", RemoteDebuggerPeerWebSocket::create); + EngineDebugger::register_uri_handler("wss://", RemoteDebuggerPeerWebSocket::create); +#endif + char locale_ptr[16]; /* clang-format off */ EM_ASM({