2023-01-10 14:26:54 +00:00
/**************************************************************************/
/* script_editor_debugger.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
2018-01-04 23:50:27 +00:00
2014-02-13 21:03:28 +00:00
# include "script_editor_debugger.h"
2018-09-28 17:08:31 +00:00
# include "core/io/marshalls.h"
2020-03-15 10:45:39 +00:00
# include "core/os/os.h"
2018-09-11 16:13:45 +00:00
# include "core/project_settings.h"
# include "core/ustring.h"
2021-04-18 00:07:05 +00:00
# include "core/version.h"
2019-11-29 14:06:42 +00:00
# include "editor/editor_log.h"
2022-03-29 03:29:15 +00:00
# include "editor/editor_property_name_processor.h"
2019-04-06 20:55:01 +00:00
# include "editor/plugins/canvas_item_editor_plugin.h"
# include "editor/plugins/spatial_editor_plugin.h"
2019-12-24 07:17:23 +00:00
# include "editor_log.h"
2019-09-01 16:38:58 +00:00
# include "editor_network_profiler.h"
2014-02-13 21:03:28 +00:00
# include "editor_node.h"
2016-05-22 00:18:16 +00:00
# include "editor_profiler.h"
2019-12-24 07:17:23 +00:00
# include "editor_scale.h"
2016-05-22 00:18:16 +00:00
# include "editor_settings.h"
2017-03-05 15:44:50 +00:00
# include "main/performance.h"
# include "property_editor.h"
2019-11-29 14:06:42 +00:00
# include "scene/debugger/script_debugger_remote.h"
2017-03-05 15:44:50 +00:00
# include "scene/gui/dialogs.h"
# include "scene/gui/label.h"
# include "scene/gui/line_edit.h"
# include "scene/gui/margin_container.h"
# include "scene/gui/rich_text_label.h"
# include "scene/gui/separator.h"
# include "scene/gui/split_container.h"
# include "scene/gui/tab_container.h"
# include "scene/gui/texture_button.h"
# include "scene/gui/tree.h"
2018-02-21 15:07:49 +00:00
# include "scene/resources/packed_scene.h"
2014-02-13 21:03:28 +00:00
class ScriptEditorDebuggerVariables : public Object {
2017-03-05 15:44:50 +00:00
GDCLASS ( ScriptEditorDebuggerVariables , Object ) ;
2014-02-13 21:03:28 +00:00
List < PropertyInfo > props ;
2017-03-05 15:44:50 +00:00
Map < StringName , Variant > values ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
protected :
bool _set ( const StringName & p_name , const Variant & p_value ) {
2014-02-13 21:03:28 +00:00
return false ;
}
2017-03-05 15:44:50 +00:00
bool _get ( const StringName & p_name , Variant & r_ret ) const {
2021-05-05 10:44:11 +00:00
if ( ! values . has ( p_name ) ) {
2014-02-13 21:03:28 +00:00
return false ;
2021-05-05 10:44:11 +00:00
}
2017-03-05 15:44:50 +00:00
r_ret = values [ p_name ] ;
2014-02-13 21:03:28 +00:00
return true ;
}
2017-03-05 15:44:50 +00:00
void _get_property_list ( List < PropertyInfo > * p_list ) const {
2021-05-05 10:44:11 +00:00
for ( const List < PropertyInfo > : : Element * E = props . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-13 21:03:28 +00:00
p_list - > push_back ( E - > get ( ) ) ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
}
public :
void clear ( ) {
props . clear ( ) ;
values . clear ( ) ;
}
2017-03-05 15:44:50 +00:00
String get_var_value ( const String & p_var ) const {
for ( Map < StringName , Variant > : : Element * E = values . front ( ) ; E ; E = E - > next ( ) ) {
String v = E - > key ( ) . operator String ( ) . get_slice ( " / " , 1 ) ;
2021-05-05 10:44:11 +00:00
if ( v = = p_var ) {
2014-02-13 21:03:28 +00:00
return E - > get ( ) ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
}
return " " ;
}
2017-05-01 17:27:01 +00:00
void add_property ( const String & p_name , const Variant & p_value , const PropertyHint & p_hint , const String p_hint_string ) {
2014-02-13 21:03:28 +00:00
PropertyInfo pinfo ;
2017-03-05 15:44:50 +00:00
pinfo . name = p_name ;
pinfo . type = p_value . get_type ( ) ;
2017-05-01 17:27:01 +00:00
pinfo . hint = p_hint ;
pinfo . hint_string = p_hint_string ;
2014-02-13 21:03:28 +00:00
props . push_back ( pinfo ) ;
2017-03-05 15:44:50 +00:00
values [ p_name ] = p_value ;
2014-02-13 21:03:28 +00:00
}
void update ( ) {
_change_notify ( ) ;
}
ScriptEditorDebuggerVariables ( ) {
}
} ;
2016-05-22 22:28:37 +00:00
class ScriptEditorDebuggerInspectedObject : public Object {
2017-03-05 15:44:50 +00:00
GDCLASS ( ScriptEditorDebuggerInspectedObject , Object ) ;
2016-05-22 22:28:37 +00:00
protected :
2017-03-05 15:44:50 +00:00
bool _set ( const StringName & p_name , const Variant & p_value ) {
2021-05-05 10:44:11 +00:00
if ( ! prop_values . has ( p_name ) | | String ( p_name ) . begins_with ( " Constants/ " ) ) {
2016-05-22 22:28:37 +00:00
return false ;
2021-05-05 10:44:11 +00:00
}
2016-05-22 22:28:37 +00:00
2017-03-05 15:44:50 +00:00
prop_values [ p_name ] = p_value ;
2018-11-11 12:14:06 +00:00
emit_signal ( " value_edited " , p_name , p_value ) ;
2016-05-22 22:28:37 +00:00
return true ;
}
2017-03-05 15:44:50 +00:00
bool _get ( const StringName & p_name , Variant & r_ret ) const {
2021-05-05 10:44:11 +00:00
if ( ! prop_values . has ( p_name ) ) {
2016-05-22 22:28:37 +00:00
return false ;
2021-05-05 10:44:11 +00:00
}
2016-05-22 22:28:37 +00:00
2017-03-05 15:44:50 +00:00
r_ret = prop_values [ p_name ] ;
2016-05-22 22:28:37 +00:00
return true ;
}
2017-10-17 14:37:25 +00:00
2017-03-05 15:44:50 +00:00
void _get_property_list ( List < PropertyInfo > * p_list ) const {
2021-12-02 00:33:13 +00:00
p_list - > clear ( ) ; // Sorry, no want category.
2017-03-05 15:44:50 +00:00
for ( const List < PropertyInfo > : : Element * E = prop_list . front ( ) ; E ; E = E - > next ( ) ) {
2021-12-02 00:33:13 +00:00
const PropertyInfo & prop = E - > get ( ) ;
if ( prop . name = = " script " ) {
// Skip the script property, it's always added by the non-virtual method.
continue ;
}
p_list - > push_back ( prop ) ;
2016-05-22 22:28:37 +00:00
}
}
static void _bind_methods ( ) {
2017-10-17 14:37:25 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_title " ) , & ScriptEditorDebuggerInspectedObject : : get_title ) ;
ClassDB : : bind_method ( D_METHOD ( " get_variant " ) , & ScriptEditorDebuggerInspectedObject : : get_variant ) ;
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & ScriptEditorDebuggerInspectedObject : : clear ) ;
ClassDB : : bind_method ( D_METHOD ( " get_remote_object_id " ) , & ScriptEditorDebuggerInspectedObject : : get_remote_object_id ) ;
2016-05-22 22:28:37 +00:00
ADD_SIGNAL ( MethodInfo ( " value_edited " ) ) ;
}
public :
2017-10-17 14:37:25 +00:00
String type_name ;
ObjectID remote_object_id ;
2016-05-22 22:28:37 +00:00
List < PropertyInfo > prop_list ;
2017-03-05 15:44:50 +00:00
Map < StringName , Variant > prop_values ;
2016-05-22 22:28:37 +00:00
2017-10-17 14:37:25 +00:00
ObjectID get_remote_object_id ( ) {
return remote_object_id ;
}
String get_title ( ) {
2021-05-05 10:44:11 +00:00
if ( remote_object_id ) {
2022-06-08 09:42:51 +00:00
return vformat ( TTR ( " Remote %s: " ) , String ( type_name ) ) + " " + itos ( remote_object_id ) ;
2021-05-05 10:44:11 +00:00
} else {
2017-10-17 14:37:25 +00:00
return " <null> " ;
2021-05-05 10:44:11 +00:00
}
2017-10-17 14:37:25 +00:00
}
Variant get_variant ( const StringName & p_name ) {
Variant var ;
_get ( p_name , var ) ;
return var ;
}
void clear ( ) {
prop_list . clear ( ) ;
prop_values . clear ( ) ;
}
2016-05-22 22:28:37 +00:00
void update ( ) {
_change_notify ( ) ;
}
2017-03-05 15:44:50 +00:00
void update_single ( const char * p_prop ) {
2016-05-22 22:28:37 +00:00
_change_notify ( p_prop ) ;
}
2017-10-17 14:37:25 +00:00
ScriptEditorDebuggerInspectedObject ( ) {
remote_object_id = 0 ;
}
2016-05-22 22:28:37 +00:00
} ;
2018-02-13 16:46:45 +00:00
void ScriptEditorDebugger : : debug_copy ( ) {
String msg = reason - > get_text ( ) ;
2021-05-05 10:44:11 +00:00
if ( msg = = " " ) {
2021-05-04 12:28:27 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2018-02-13 16:46:45 +00:00
OS : : get_singleton ( ) - > set_clipboard ( msg ) ;
}
2019-07-29 18:09:22 +00:00
void ScriptEditorDebugger : : debug_skip_breakpoints ( ) {
skip_breakpoints_value = ! skip_breakpoints_value ;
2021-05-05 10:44:11 +00:00
if ( skip_breakpoints_value ) {
2019-07-29 18:09:22 +00:00
skip_breakpoints - > set_icon ( get_icon ( " DebugSkipBreakpointsOn " , " EditorIcons " ) ) ;
2021-05-05 10:44:11 +00:00
} else {
2019-07-29 18:09:22 +00:00
skip_breakpoints - > set_icon ( get_icon ( " DebugSkipBreakpointsOff " , " EditorIcons " ) ) ;
2021-05-05 10:44:11 +00:00
}
2019-07-29 18:09:22 +00:00
if ( connection . is_valid ( ) ) {
Array msg ;
msg . push_back ( " set_skip_breakpoints " ) ;
msg . push_back ( skip_breakpoints_value ) ;
ppeer - > put_var ( msg ) ;
}
}
2014-02-13 21:03:28 +00:00
void ScriptEditorDebugger : : debug_next ( ) {
ERR_FAIL_COND ( ! breaked ) ;
ERR_FAIL_COND ( connection . is_null ( ) ) ;
2017-01-14 14:07:57 +00:00
ERR_FAIL_COND ( ! connection - > is_connected_to_host ( ) ) ;
2014-02-13 21:03:28 +00:00
Array msg ;
msg . push_back ( " next " ) ;
ppeer - > put_var ( msg ) ;
2019-04-22 16:20:27 +00:00
_clear_execution ( ) ;
2014-02-13 21:03:28 +00:00
stack_dump - > clear ( ) ;
}
void ScriptEditorDebugger : : debug_step ( ) {
ERR_FAIL_COND ( ! breaked ) ;
ERR_FAIL_COND ( connection . is_null ( ) ) ;
2017-01-14 14:07:57 +00:00
ERR_FAIL_COND ( ! connection - > is_connected_to_host ( ) ) ;
2014-02-13 21:03:28 +00:00
Array msg ;
msg . push_back ( " step " ) ;
ppeer - > put_var ( msg ) ;
2019-04-22 16:20:27 +00:00
_clear_execution ( ) ;
2014-02-13 21:03:28 +00:00
stack_dump - > clear ( ) ;
}
void ScriptEditorDebugger : : debug_break ( ) {
ERR_FAIL_COND ( breaked ) ;
ERR_FAIL_COND ( connection . is_null ( ) ) ;
2017-01-14 14:07:57 +00:00
ERR_FAIL_COND ( ! connection - > is_connected_to_host ( ) ) ;
2014-02-13 21:03:28 +00:00
Array msg ;
msg . push_back ( " break " ) ;
ppeer - > put_var ( msg ) ;
}
void ScriptEditorDebugger : : debug_continue ( ) {
ERR_FAIL_COND ( ! breaked ) ;
ERR_FAIL_COND ( connection . is_null ( ) ) ;
2017-01-14 14:07:57 +00:00
ERR_FAIL_COND ( ! connection - > is_connected_to_host ( ) ) ;
2014-02-13 21:03:28 +00:00
2016-09-14 02:02:18 +00:00
OS : : get_singleton ( ) - > enable_for_stealing_focus ( EditorNode : : get_singleton ( ) - > get_child_process_id ( ) ) ;
2014-02-13 21:03:28 +00:00
Array msg ;
2019-04-22 16:20:27 +00:00
_clear_execution ( ) ;
2014-02-13 21:03:28 +00:00
msg . push_back ( " continue " ) ;
ppeer - > put_var ( msg ) ;
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : _scene_tree_folded ( Object * obj ) {
2016-05-22 22:28:37 +00:00
if ( updating_scene_tree ) {
return ;
}
2017-08-24 20:58:51 +00:00
TreeItem * item = Object : : cast_to < TreeItem > ( obj ) ;
2016-05-22 22:28:37 +00:00
2021-05-05 10:44:11 +00:00
if ( ! item ) {
2016-05-22 22:28:37 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2016-05-22 22:28:37 +00:00
ObjectID id = item - > get_metadata ( 0 ) ;
2019-01-31 14:40:27 +00:00
if ( unfold_cache . has ( id ) ) {
2016-05-22 22:28:37 +00:00
unfold_cache . erase ( id ) ;
} else {
unfold_cache . insert ( id ) ;
}
}
void ScriptEditorDebugger : : _scene_tree_selected ( ) {
if ( updating_scene_tree ) {
return ;
}
TreeItem * item = inspect_scene_tree - > get_selected ( ) ;
if ( ! item ) {
return ;
}
inspected_object_id = item - > get_metadata ( 0 ) ;
Array msg ;
msg . push_back ( " inspect_object " ) ;
msg . push_back ( inspected_object_id ) ;
ppeer - > put_var ( msg ) ;
}
2018-02-21 15:07:49 +00:00
void ScriptEditorDebugger : : _scene_tree_rmb_selected ( const Vector2 & p_position ) {
TreeItem * item = inspect_scene_tree - > get_item_at_position ( p_position ) ;
2021-05-05 10:44:11 +00:00
if ( ! item ) {
2018-02-21 15:07:49 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2018-02-21 15:07:49 +00:00
item - > select ( 0 ) ;
item_menu - > clear ( ) ;
item_menu - > add_icon_item ( get_icon ( " CreateNewSceneFrom " , " EditorIcons " ) , TTR ( " Save Branch as Scene " ) , ITEM_MENU_SAVE_REMOTE_NODE ) ;
2019-05-05 07:59:10 +00:00
item_menu - > add_icon_item ( get_icon ( " CopyNodePath " , " EditorIcons " ) , TTR ( " Copy Node Path " ) , ITEM_MENU_COPY_NODE_PATH ) ;
2018-02-21 15:07:49 +00:00
item_menu - > set_global_position ( get_global_mouse_position ( ) ) ;
item_menu - > popup ( ) ;
}
void ScriptEditorDebugger : : _file_selected ( const String & p_file ) {
2019-06-20 14:59:48 +00:00
switch ( file_dialog_mode ) {
case SAVE_NODE : {
Array msg ;
msg . push_back ( " save_node " ) ;
msg . push_back ( inspected_object_id ) ;
msg . push_back ( p_file ) ;
ppeer - > put_var ( msg ) ;
} break ;
2020-03-17 11:49:31 +00:00
case SAVE_MONITORS_CSV : {
2019-06-20 14:59:48 +00:00
Error err ;
FileAccessRef file = FileAccess : : open ( p_file , FileAccess : : WRITE , & err ) ;
if ( err ! = OK ) {
2021-06-16 10:56:25 +00:00
ERR_PRINT ( " Failed to open " + p_file ) ;
2019-06-20 14:59:48 +00:00
return ;
}
Vector < String > line ;
line . resize ( Performance : : MONITOR_MAX ) ;
2019-02-18 00:25:26 +00:00
2019-06-20 14:59:48 +00:00
// signatures
for ( int i = 0 ; i < Performance : : MONITOR_MAX ; i + + ) {
line . write [ i ] = Performance : : get_singleton ( ) - > get_monitor_name ( Performance : : Monitor ( i ) ) ;
}
file - > store_csv_line ( line ) ;
2019-02-18 00:25:26 +00:00
2019-06-20 14:59:48 +00:00
// values
2021-05-04 12:20:36 +00:00
List < Vector < float > > : : Element * E = perf_history . back ( ) ;
2019-06-20 14:59:48 +00:00
while ( E ) {
Vector < float > & perf_data = E - > get ( ) ;
for ( int i = 0 ; i < perf_data . size ( ) ; i + + ) {
line . write [ i ] = String : : num_real ( perf_data [ i ] ) ;
}
file - > store_csv_line ( line ) ;
E = E - > prev ( ) ;
}
file - > store_string ( " \n " ) ;
2019-02-18 00:25:26 +00:00
2021-05-04 12:20:36 +00:00
Vector < Vector < String > > profiler_data = profiler - > get_data_as_csv ( ) ;
2019-06-20 14:59:48 +00:00
for ( int i = 0 ; i < profiler_data . size ( ) ; i + + ) {
file - > store_csv_line ( profiler_data [ i ] ) ;
2019-02-18 00:25:26 +00:00
}
2019-06-20 14:59:48 +00:00
} break ;
2020-03-17 11:49:31 +00:00
case SAVE_VRAM_CSV : {
Error err ;
FileAccessRef file = FileAccess : : open ( p_file , FileAccess : : WRITE , & err ) ;
if ( err ! = OK ) {
2021-06-16 10:56:25 +00:00
ERR_PRINT ( " Failed to open " + p_file ) ;
2020-03-17 11:49:31 +00:00
return ;
}
Vector < String > headers ;
headers . resize ( vmem_tree - > get_columns ( ) ) ;
for ( int i = 0 ; i < vmem_tree - > get_columns ( ) ; + + i ) {
headers . write [ i ] = vmem_tree - > get_column_title ( i ) ;
}
file - > store_csv_line ( headers ) ;
if ( vmem_tree - > get_root ( ) ) {
TreeItem * ti = vmem_tree - > get_root ( ) - > get_children ( ) ;
while ( ti ) {
Vector < String > values ;
values . resize ( vmem_tree - > get_columns ( ) ) ;
for ( int i = 0 ; i < vmem_tree - > get_columns ( ) ; + + i ) {
values . write [ i ] = ti - > get_text ( i ) ;
}
file - > store_csv_line ( values ) ;
ti = ti - > get_next ( ) ;
}
}
} break ;
2018-02-21 15:07:49 +00:00
}
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : _scene_tree_property_value_edited ( const String & p_prop , const Variant & p_value ) {
2016-05-22 22:28:37 +00:00
Array msg ;
msg . push_back ( " set_object_property " ) ;
msg . push_back ( inspected_object_id ) ;
msg . push_back ( p_prop ) ;
msg . push_back ( p_value ) ;
ppeer - > put_var ( msg ) ;
2017-03-05 15:44:50 +00:00
inspect_edited_object_timeout = 0.7 ; //avoid annoyance, don't request soon after editing
2016-05-22 22:28:37 +00:00
}
void ScriptEditorDebugger : : _scene_tree_property_select_object ( ObjectID p_object ) {
2017-03-05 15:44:50 +00:00
inspected_object_id = p_object ;
2016-05-22 22:28:37 +00:00
Array msg ;
msg . push_back ( " inspect_object " ) ;
msg . push_back ( inspected_object_id ) ;
ppeer - > put_var ( msg ) ;
}
2014-02-13 21:03:28 +00:00
void ScriptEditorDebugger : : _scene_tree_request ( ) {
ERR_FAIL_COND ( connection . is_null ( ) ) ;
2017-01-14 14:07:57 +00:00
ERR_FAIL_COND ( ! connection - > is_connected_to_host ( ) ) ;
2014-02-13 21:03:28 +00:00
Array msg ;
msg . push_back ( " request_scene_tree " ) ;
ppeer - > put_var ( msg ) ;
}
2018-10-25 08:39:02 +00:00
/// Populates inspect_scene_tree recursively given data in nodes.
/// Nodes is an array containing 4 elements for each node, it follows this pattern:
/// nodes[i] == number of direct children of this node
/// nodes[i + 1] == node name
/// nodes[i + 2] == node class
/// nodes[i + 3] == node instance id
///
/// Returns the number of items parsed in nodes from current_index.
///
/// Given a nodes array like [R,A,B,C,D,E] the following Tree will be generated, assuming
/// filter is an empty String, R and A child count are 2, B is 1 and C, D and E are 0.
///
/// R
/// |-A
/// | |-B
/// | | |-C
/// | |
/// | |-D
/// |
/// |-E
///
int ScriptEditorDebugger : : _update_scene_tree ( TreeItem * parent , const Array & nodes , int current_index ) {
String filter = EditorNode : : get_singleton ( ) - > get_scene_tree_dock ( ) - > get_filter ( ) ;
String item_text = nodes [ current_index + 1 ] ;
2019-09-09 05:03:38 +00:00
String item_type = nodes [ current_index + 2 ] ;
2018-10-25 08:39:02 +00:00
bool keep = filter . is_subsequence_ofi ( item_text ) ;
TreeItem * item = inspect_scene_tree - > create_item ( parent ) ;
item - > set_text ( 0 , item_text ) ;
2019-09-09 05:03:38 +00:00
item - > set_tooltip ( 0 , TTR ( " Type: " ) + " " + item_type ) ;
2018-10-25 08:39:02 +00:00
ObjectID id = ObjectID ( nodes [ current_index + 3 ] ) ;
Ref < Texture > icon = EditorNode : : get_singleton ( ) - > get_class_icon ( nodes [ current_index + 2 ] , " " ) ;
if ( icon . is_valid ( ) ) {
item - > set_icon ( 0 , icon ) ;
}
item - > set_metadata ( 0 , id ) ;
2021-02-08 00:31:43 +00:00
bool scroll = false ;
2019-09-09 02:52:37 +00:00
if ( id = = inspected_object_id ) {
TreeItem * cti = item - > get_parent ( ) ;
while ( cti ) {
cti - > set_collapsed ( false ) ;
cti = cti - > get_parent ( ) ;
}
item - > select ( 0 ) ;
2021-02-08 00:31:43 +00:00
scroll = filter ! = last_filter ;
2019-09-09 02:52:37 +00:00
}
2019-07-30 13:11:13 +00:00
// Set current item as collapsed if necessary
if ( parent ) {
if ( ! unfold_cache . has ( id ) ) {
item - > set_collapsed ( true ) ;
}
}
2018-10-25 08:39:02 +00:00
int children_count = nodes [ current_index ] ;
// Tracks the total number of items parsed in nodes, this is used to skips nodes that
// are not direct children of the current node since we can't know in advance the total
// number of children, direct and not, of a node without traversing the nodes array previously.
// Keeping track of this allows us to build our remote scene tree by traversing the node
// array just once.
int items_count = 1 ;
for ( int i = 0 ; i < children_count ; i + + ) {
// Called for each direct child of item.
// Direct children of current item might not be adjacent so items_count must
// be incremented by the number of items parsed until now, otherwise we would not
// be able to access the next child of the current item.
// items_count is multiplied by 4 since that's the number of elements in the nodes
// array needed to represent a single node.
items_count + = _update_scene_tree ( item , nodes , current_index + items_count * 4 ) ;
}
// If item has not children and should not be kept delete it
if ( ! keep & & ! item - > get_children ( ) & & parent ) {
parent - > remove_child ( item ) ;
memdelete ( item ) ;
2021-02-08 00:31:43 +00:00
} else if ( scroll ) {
inspect_scene_tree - > call_deferred ( " scroll_to_item " , item ) ;
}
if ( ! parent ) {
last_filter = filter ;
2018-10-25 08:39:02 +00:00
}
return items_count ;
}
2015-10-21 12:50:44 +00:00
void ScriptEditorDebugger : : _video_mem_request ( ) {
2019-11-28 15:37:15 +00:00
if ( connection . is_null ( ) | | ! connection - > is_connected_to_host ( ) ) {
// Video RAM usage is only available while a project is being debugged.
return ;
}
2015-10-21 12:50:44 +00:00
Array msg ;
msg . push_back ( " request_video_mem " ) ;
ppeer - > put_var ( msg ) ;
}
2020-03-17 11:49:31 +00:00
void ScriptEditorDebugger : : _video_mem_export ( ) {
file_dialog - > set_mode ( EditorFileDialog : : MODE_SAVE_FILE ) ;
file_dialog - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
file_dialog - > clear_filters ( ) ;
file_dialog_mode = SAVE_VRAM_CSV ;
file_dialog - > popup_centered_ratio ( ) ;
}
2014-02-13 21:03:28 +00:00
Size2 ScriptEditorDebugger : : get_minimum_size ( ) const {
2019-11-18 08:42:28 +00:00
Size2 ms = MarginContainer : : get_minimum_size ( ) ;
2018-10-20 20:05:11 +00:00
ms . y = MAX ( ms . y , 250 * EDSCALE ) ;
2014-02-13 21:03:28 +00:00
return ms ;
}
2019-05-05 07:59:10 +00:00
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : _parse_message ( const String & p_msg , const Array & p_data ) {
if ( p_msg = = " debug_enter " ) {
2014-02-13 21:03:28 +00:00
Array msg ;
msg . push_back ( " get_stack_dump " ) ;
ppeer - > put_var ( msg ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( p_data . size ( ) ! = 2 ) ;
bool can_continue = p_data [ 0 ] ;
2014-02-13 21:03:28 +00:00
String error = p_data [ 1 ] ;
step - > set_disabled ( ! can_continue ) ;
next - > set_disabled ( ! can_continue ) ;
2017-08-22 19:16:08 +00:00
_set_reason_text ( error , MESSAGE_ERROR ) ;
2018-02-13 16:46:45 +00:00
copy - > set_disabled ( false ) ;
2017-03-05 15:44:50 +00:00
breaked = true ;
2014-02-13 21:03:28 +00:00
dobreak - > set_disabled ( true ) ;
docontinue - > set_disabled ( false ) ;
2017-03-05 15:44:50 +00:00
emit_signal ( " breaked " , true , can_continue ) ;
2014-02-13 21:03:28 +00:00
OS : : get_singleton ( ) - > move_window_to_foreground ( ) ;
2017-03-05 15:44:50 +00:00
if ( error ! = " " ) {
2016-05-22 00:18:16 +00:00
tabs - > set_current_tab ( 0 ) ;
2016-07-17 12:17:35 +00:00
}
2016-05-22 00:18:16 +00:00
profiler - > set_enabled ( false ) ;
EditorNode : : get_singleton ( ) - > get_pause_button ( ) - > set_pressed ( true ) ;
2016-01-17 23:03:57 +00:00
EditorNode : : get_singleton ( ) - > make_bottom_panel_item_visible ( this ) ;
2017-10-17 14:37:25 +00:00
_clear_remote_objects ( ) ;
2016-01-17 23:03:57 +00:00
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " debug_exit " ) {
breaked = false ;
2019-04-22 16:20:27 +00:00
_clear_execution ( ) ;
2018-02-13 16:46:45 +00:00
copy - > set_disabled ( true ) ;
2014-02-13 21:03:28 +00:00
step - > set_disabled ( true ) ;
next - > set_disabled ( true ) ;
reason - > set_text ( " " ) ;
reason - > set_tooltip ( " " ) ;
back - > set_disabled ( true ) ;
forward - > set_disabled ( true ) ;
dobreak - > set_disabled ( false ) ;
docontinue - > set_disabled ( true ) ;
2017-03-05 15:44:50 +00:00
emit_signal ( " breaked " , false , false , Variant ( ) ) ;
2016-05-22 00:18:16 +00:00
profiler - > set_enabled ( true ) ;
profiler - > disable_seeking ( ) ;
EditorNode : : get_singleton ( ) - > get_pause_button ( ) - > set_pressed ( false ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " message:click_ctrl " ) {
2014-02-13 21:03:28 +00:00
clicked_ctrl - > set_text ( p_data [ 0 ] ) ;
clicked_ctrl_type - > set_text ( p_data [ 1 ] ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " message:scene_tree " ) {
2016-05-22 22:28:37 +00:00
inspect_scene_tree - > clear ( ) ;
2017-03-05 15:44:50 +00:00
Map < int , TreeItem * > lv ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
updating_scene_tree = true ;
2016-05-22 22:28:37 +00:00
2021-05-04 14:00:45 +00:00
_update_scene_tree ( nullptr , p_data , 0 ) ;
2016-05-22 22:28:37 +00:00
2017-03-05 15:44:50 +00:00
updating_scene_tree = false ;
2014-02-13 21:03:28 +00:00
2015-08-02 15:29:37 +00:00
le_clear - > set_disabled ( false ) ;
le_set - > set_disabled ( false ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " message:inspect_object " ) {
2022-07-25 12:29:33 +00:00
ScriptEditorDebuggerInspectedObject * debug_obj = nullptr ;
2017-10-17 14:37:25 +00:00
2016-05-22 22:28:37 +00:00
ObjectID id = p_data [ 0 ] ;
String type = p_data [ 1 ] ;
2017-10-17 14:37:25 +00:00
Array properties = p_data [ 2 ] ;
2016-05-22 22:28:37 +00:00
2017-10-17 14:37:25 +00:00
if ( remote_objects . has ( id ) ) {
2022-07-25 12:29:33 +00:00
debug_obj = remote_objects [ id ] ;
2017-10-17 14:37:25 +00:00
} else {
2022-07-25 12:29:33 +00:00
debug_obj = memnew ( ScriptEditorDebuggerInspectedObject ) ;
debug_obj - > remote_object_id = id ;
debug_obj - > type_name = type ;
remote_objects [ id ] = debug_obj ;
debug_obj - > connect ( " value_edited " , this , " _scene_tree_property_value_edited " ) ;
2016-05-22 22:28:37 +00:00
}
2022-07-25 12:29:33 +00:00
int old_prop_size = debug_obj - > prop_list . size ( ) ;
2018-11-11 12:14:06 +00:00
2022-07-25 12:29:33 +00:00
debug_obj - > prop_list . clear ( ) ;
2018-11-11 12:14:06 +00:00
int new_props_added = 0 ;
Set < String > changed ;
2017-10-17 14:37:25 +00:00
for ( int i = 0 ; i < properties . size ( ) ; i + + ) {
Array prop = properties [ i ] ;
2021-05-05 10:44:11 +00:00
if ( prop . size ( ) ! = 6 ) {
2017-10-17 14:37:25 +00:00
continue ;
2021-05-05 10:44:11 +00:00
}
2016-05-22 22:28:37 +00:00
PropertyInfo pinfo ;
2017-10-17 14:37:25 +00:00
pinfo . name = prop [ 0 ] ;
pinfo . type = Variant : : Type ( int ( prop [ 1 ] ) ) ;
pinfo . hint = PropertyHint ( int ( prop [ 2 ] ) ) ;
pinfo . hint_string = prop [ 3 ] ;
pinfo . usage = PropertyUsageFlags ( int ( prop [ 4 ] ) ) ;
Variant var = prop [ 5 ] ;
2018-10-03 23:59:24 +00:00
if ( pinfo . type = = Variant : : OBJECT ) {
if ( var . is_zero ( ) ) {
var = RES ( ) ;
} else if ( var . get_type ( ) = = Variant : : STRING ) {
2019-10-23 15:53:29 +00:00
String path = var ;
if ( path . find ( " :: " ) ! = - 1 ) {
// built-in resource
String base_path = path . get_slice ( " :: " , 0 ) ;
2020-05-22 19:50:16 +00:00
RES dependency = ResourceLoader : : load ( base_path ) ;
if ( dependency . is_valid ( ) ) {
remote_dependencies . insert ( dependency ) ;
2019-10-23 15:53:29 +00:00
}
}
var = ResourceLoader : : load ( path ) ;
2018-10-03 23:59:24 +00:00
2019-10-28 17:18:43 +00:00
if ( pinfo . hint_string = = " Script " ) {
2022-07-25 12:29:33 +00:00
if ( debug_obj - > get_script ( ) ! = var ) {
debug_obj - > set_script ( RefPtr ( ) ) ;
2019-10-28 17:18:43 +00:00
Ref < Script > script ( var ) ;
if ( ! script . is_null ( ) ) {
2022-07-25 12:29:33 +00:00
ScriptInstance * script_instance = script - > placeholder_instance_create ( debug_obj ) ;
if ( script_instance ) {
debug_obj - > set_script_and_instance ( var , script_instance ) ;
}
2019-10-28 17:18:43 +00:00
}
}
}
2018-10-03 23:59:24 +00:00
} else if ( var . get_type ( ) = = Variant : : OBJECT ) {
if ( ( ( Object * ) var ) - > is_class ( " EncodedObjectAsID " ) ) {
var = Object : : cast_to < EncodedObjectAsID > ( var ) - > get_object_id ( ) ;
pinfo . type = var . get_type ( ) ;
pinfo . hint = PROPERTY_HINT_OBJECT_ID ;
pinfo . hint_string = " Object " ;
}
}
}
2018-11-11 12:14:06 +00:00
//always add the property, since props may have been added or removed
2022-07-25 12:29:33 +00:00
debug_obj - > prop_list . push_back ( pinfo ) ;
2018-11-11 12:14:06 +00:00
2022-07-25 12:29:33 +00:00
if ( ! debug_obj - > prop_values . has ( pinfo . name ) ) {
2018-11-11 12:14:06 +00:00
new_props_added + + ;
2022-07-25 12:29:33 +00:00
debug_obj - > prop_values [ pinfo . name ] = var ;
2018-11-11 12:14:06 +00:00
} else {
2022-05-03 22:49:34 +00:00
// Compare using `deep_equal` so dictionaries/arrays will be compared by value.
2022-07-25 12:29:33 +00:00
if ( ! debug_obj - > prop_values [ pinfo . name ] . deep_equal ( var ) ) {
debug_obj - > prop_values [ pinfo . name ] = var ;
2018-11-11 12:14:06 +00:00
changed . insert ( pinfo . name ) ;
}
}
2016-05-22 22:28:37 +00:00
}
2022-07-25 12:29:33 +00:00
if ( editor - > get_editor_history ( ) - > get_current ( ) ! = debug_obj - > get_instance_id ( ) ) {
editor - > push_item ( debug_obj , " " ) ;
2017-10-17 14:37:25 +00:00
} else {
2022-07-25 12:29:33 +00:00
if ( old_prop_size = = debug_obj - > prop_list . size ( ) & & new_props_added = = 0 ) {
2018-11-11 12:14:06 +00:00
//only some may have changed, if so, then update those, if exist
for ( Set < String > : : Element * E = changed . front ( ) ; E ; E = E - > next ( ) ) {
EditorNode : : get_singleton ( ) - > get_inspector ( ) - > update_property ( E - > get ( ) ) ;
}
} else {
//full update, because props were added or removed
2022-07-25 12:29:33 +00:00
debug_obj - > update ( ) ;
2018-11-11 12:14:06 +00:00
}
2016-05-22 22:28:37 +00:00
}
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " message:video_mem " ) {
2015-10-21 12:50:44 +00:00
vmem_tree - > clear ( ) ;
2017-03-05 15:44:50 +00:00
TreeItem * root = vmem_tree - > create_item ( ) ;
2015-10-21 12:50:44 +00:00
2021-03-09 09:51:17 +00:00
uint64_t total = 0 ;
2015-10-21 12:50:44 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_data . size ( ) ; i + = 4 ) {
2015-10-21 12:50:44 +00:00
TreeItem * it = vmem_tree - > create_item ( root ) ;
2017-03-05 15:44:50 +00:00
String type = p_data [ i + 1 ] ;
int bytes = p_data [ i + 3 ] . operator int ( ) ;
it - > set_text ( 0 , p_data [ i + 0 ] ) ; //path
it - > set_text ( 1 , type ) ; //type
it - > set_text ( 2 , p_data [ i + 2 ] ) ; //type
it - > set_text ( 3 , String : : humanize_size ( bytes ) ) ; //type
total + = bytes ;
2021-05-05 10:44:11 +00:00
if ( has_icon ( type , " EditorIcons " ) ) {
2017-03-05 15:44:50 +00:00
it - > set_icon ( 0 , get_icon ( type , " EditorIcons " ) ) ;
2021-05-05 10:44:11 +00:00
}
2015-10-21 12:50:44 +00:00
}
2017-03-05 15:44:50 +00:00
vmem_total - > set_tooltip ( TTR ( " Bytes: " ) + " " + itos ( total ) ) ;
2015-10-21 12:50:44 +00:00
vmem_total - > set_text ( String : : humanize_size ( total ) ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " stack_dump " ) {
2014-02-13 21:03:28 +00:00
stack_dump - > clear ( ) ;
TreeItem * r = stack_dump - > create_item ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_data . size ( ) ; i + + ) {
2014-02-13 21:03:28 +00:00
Dictionary d = p_data [ i ] ;
ERR_CONTINUE ( ! d . has ( " function " ) ) ;
ERR_CONTINUE ( ! d . has ( " file " ) ) ;
ERR_CONTINUE ( ! d . has ( " line " ) ) ;
ERR_CONTINUE ( ! d . has ( " id " ) ) ;
TreeItem * s = stack_dump - > create_item ( r ) ;
2017-03-05 15:44:50 +00:00
d [ " frame " ] = i ;
s - > set_metadata ( 0 , d ) ;
2014-02-13 21:03:28 +00:00
2019-05-10 19:39:39 +00:00
String line = itos ( i ) + " - " + String ( d [ " file " ] ) + " : " + itos ( d [ " line " ] ) + " - at function: " + d [ " function " ] ;
2017-03-05 15:44:50 +00:00
s - > set_text ( 0 , line ) ;
2014-02-13 21:03:28 +00:00
2021-05-05 10:44:11 +00:00
if ( i = = 0 ) {
2014-02-13 21:03:28 +00:00
s - > select ( 0 ) ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " stack_frame_vars " ) {
2014-02-13 21:03:28 +00:00
variables - > clear ( ) ;
2017-03-05 15:44:50 +00:00
int ofs = 0 ;
2014-02-13 21:03:28 +00:00
int mcount = p_data [ ofs ] ;
ofs + + ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < mcount ; i + + ) {
String n = p_data [ ofs + i * 2 + 0 ] ;
Variant v = p_data [ ofs + i * 2 + 1 ] ;
2018-11-22 01:10:27 +00:00
2017-05-01 17:27:01 +00:00
PropertyHint h = PROPERTY_HINT_NONE ;
String hs = String ( ) ;
2014-02-13 21:03:28 +00:00
2018-09-19 10:06:34 +00:00
if ( v . get_type ( ) = = Variant : : OBJECT ) {
2018-09-28 22:23:20 +00:00
v = Object : : cast_to < EncodedObjectAsID > ( v ) - > get_object_id ( ) ;
2017-05-01 17:27:01 +00:00
h = PROPERTY_HINT_OBJECT_ID ;
2018-09-28 22:23:20 +00:00
hs = " Object " ;
2014-02-13 21:03:28 +00:00
}
2017-10-17 14:37:25 +00:00
variables - > add_property ( " Locals/ " + n , v , h , hs ) ;
2014-02-13 21:03:28 +00:00
}
2017-10-17 14:37:25 +00:00
ofs + = mcount * 2 ;
2014-02-13 21:03:28 +00:00
mcount = p_data [ ofs ] ;
2017-10-17 14:37:25 +00:00
ofs + + ;
for ( int i = 0 ; i < mcount ; i + + ) {
String n = p_data [ ofs + i * 2 + 0 ] ;
Variant v = p_data [ ofs + i * 2 + 1 ] ;
PropertyHint h = PROPERTY_HINT_NONE ;
String hs = String ( ) ;
2018-09-19 10:06:34 +00:00
if ( v . get_type ( ) = = Variant : : OBJECT ) {
2018-09-28 22:23:20 +00:00
v = Object : : cast_to < EncodedObjectAsID > ( v ) - > get_object_id ( ) ;
2017-10-17 14:37:25 +00:00
h = PROPERTY_HINT_OBJECT_ID ;
2018-09-28 22:23:20 +00:00
hs = " Object " ;
2017-10-17 14:37:25 +00:00
}
variables - > add_property ( " Members/ " + n , v , h , hs ) ;
2019-10-02 10:38:31 +00:00
if ( n = = " self " ) {
_scene_tree_property_select_object ( v ) ;
}
2017-10-17 14:37:25 +00:00
}
2014-02-13 21:03:28 +00:00
2017-10-17 14:37:25 +00:00
ofs + = mcount * 2 ;
mcount = p_data [ ofs ] ;
2014-02-13 21:03:28 +00:00
ofs + + ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < mcount ; i + + ) {
String n = p_data [ ofs + i * 2 + 0 ] ;
Variant v = p_data [ ofs + i * 2 + 1 ] ;
2017-05-01 17:27:01 +00:00
PropertyHint h = PROPERTY_HINT_NONE ;
String hs = String ( ) ;
2014-02-13 21:03:28 +00:00
2018-09-19 10:06:34 +00:00
if ( v . get_type ( ) = = Variant : : OBJECT ) {
2018-09-28 22:23:20 +00:00
v = Object : : cast_to < EncodedObjectAsID > ( v ) - > get_object_id ( ) ;
2017-05-01 17:27:01 +00:00
h = PROPERTY_HINT_OBJECT_ID ;
2018-09-28 22:23:20 +00:00
hs = " Object " ;
2014-02-13 21:03:28 +00:00
}
2017-10-17 14:37:25 +00:00
variables - > add_property ( " Globals/ " + n , v , h , hs ) ;
2014-02-13 21:03:28 +00:00
}
variables - > update ( ) ;
inspector - > edit ( variables ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " output " ) {
2014-02-13 21:03:28 +00:00
//OUT
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_data . size ( ) ; i + + ) {
2019-11-29 14:06:42 +00:00
Array output = p_data [ i ] ;
ERR_FAIL_COND_MSG ( output . size ( ) < 2 , " Malformed output message from script debugger. " ) ;
String str = output [ 0 ] ;
ScriptDebuggerRemote : : MessageType type = ( ScriptDebuggerRemote : : MessageType ) ( int ) ( output [ 1 ] ) ;
EditorLog : : MessageType msg_type ;
switch ( type ) {
case ScriptDebuggerRemote : : MESSAGE_TYPE_LOG : {
msg_type = EditorLog : : MSG_TYPE_STD ;
} break ;
case ScriptDebuggerRemote : : MESSAGE_TYPE_ERROR : {
msg_type = EditorLog : : MSG_TYPE_ERROR ;
} break ;
default : {
2021-06-18 11:26:58 +00:00
WARN_PRINT ( " Unhandled script debugger message type: " + itos ( type ) ) ;
2019-11-29 14:06:42 +00:00
msg_type = EditorLog : : MSG_TYPE_STD ;
} break ;
}
2014-02-13 21:03:28 +00:00
//LOG
2017-01-13 13:45:50 +00:00
if ( ! EditorNode : : get_log ( ) - > is_visible ( ) ) {
2016-01-24 15:26:03 +00:00
if ( EditorNode : : get_singleton ( ) - > are_bottom_panels_hidden ( ) ) {
2018-01-19 13:35:34 +00:00
if ( EDITOR_GET ( " run/output/always_open_output_on_play " ) ) {
EditorNode : : get_singleton ( ) - > make_bottom_panel_item_visible ( EditorNode : : get_log ( ) ) ;
}
2016-01-24 15:26:03 +00:00
}
2014-02-13 21:03:28 +00:00
}
2019-11-29 14:06:42 +00:00
EditorNode : : get_log ( ) - > add_message ( str , msg_type ) ;
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " performance " ) {
2014-02-13 21:03:28 +00:00
Array arr = p_data [ 0 ] ;
Vector < float > p ;
p . resize ( arr . size ( ) ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < arr . size ( ) ; i + + ) {
2018-07-25 01:11:03 +00:00
p . write [ i ] = arr [ i ] ;
2017-03-05 15:44:50 +00:00
if ( i < perf_items . size ( ) ) {
2020-01-24 11:07:38 +00:00
const float value = p [ i ] ;
String label = rtos ( value ) ;
String tooltip = label ;
2017-10-23 06:59:04 +00:00
switch ( Performance : : MonitorType ( ( int ) perf_items [ i ] - > get_metadata ( 1 ) ) ) {
case Performance : : MONITOR_TYPE_MEMORY : {
2020-01-24 11:07:38 +00:00
label = String : : humanize_size ( value ) ;
tooltip = label ;
2017-10-23 06:59:04 +00:00
} break ;
case Performance : : MONITOR_TYPE_TIME : {
2020-01-24 11:07:38 +00:00
label = rtos ( value * 1000 ) . pad_decimals ( 2 ) + " ms " ;
tooltip = label ;
2017-10-23 06:59:04 +00:00
} break ;
default : {
2020-01-24 11:07:38 +00:00
tooltip + = " " + perf_items [ i ] - > get_text ( 0 ) ;
2017-10-23 06:59:04 +00:00
} break ;
}
2020-01-24 11:07:38 +00:00
perf_items [ i ] - > set_text ( 1 , label ) ;
perf_items [ i ] - > set_tooltip ( 1 , tooltip ) ;
2021-05-05 10:44:11 +00:00
if ( p [ i ] > perf_max [ i ] ) {
2018-07-25 01:11:03 +00:00
perf_max . write [ i ] = p [ i ] ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
}
}
perf_history . push_front ( p ) ;
perf_draw - > update ( ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " error " ) {
2019-09-25 08:47:41 +00:00
// Should have at least two elements, error array and stack items count.
ERR_FAIL_COND_MSG ( p_data . size ( ) < 2 , " Malformed error message from script debugger. " ) ;
2015-08-04 12:47:32 +00:00
2019-09-25 08:47:41 +00:00
// Error or warning data.
Array err = p_data [ 0 ] ;
ERR_FAIL_COND_MSG ( err . size ( ) < 10 , " Malformed error message from script debugger. " ) ;
// Format time.
Array time_vals ;
time_vals . push_back ( err [ 0 ] ) ;
time_vals . push_back ( err [ 1 ] ) ;
time_vals . push_back ( err [ 2 ] ) ;
time_vals . push_back ( err [ 3 ] ) ;
2015-08-04 12:47:32 +00:00
bool e ;
2019-12-02 17:53:39 +00:00
String time = String ( " %d:%02d:%02d.%03d " ) . sprintf ( time_vals , & e ) ;
2015-08-04 12:47:32 +00:00
2019-09-25 08:47:41 +00:00
// Rest of the error data.
String method = err [ 4 ] ;
String source_file = err [ 5 ] ;
String source_line = err [ 6 ] ;
String error_cond = err [ 7 ] ;
String error_msg = err [ 8 ] ;
bool is_warning = err [ 9 ] ;
bool has_method = ! method . empty ( ) ;
bool has_error_msg = ! error_msg . empty ( ) ;
bool source_is_project_file = source_file . begins_with ( " res:// " ) ;
// Metadata to highlight error line in scripts.
Array source_meta ;
source_meta . push_back ( source_file ) ;
source_meta . push_back ( source_line ) ;
// Create error tree to display above error or warning details.
2018-09-08 23:31:49 +00:00
TreeItem * r = error_tree - > get_root ( ) ;
if ( ! r ) {
r = error_tree - > create_item ( ) ;
}
2015-08-04 12:47:32 +00:00
2019-09-25 08:47:41 +00:00
// Also provide the relevant details as tooltip to quickly check without
// uncollapsing the tree.
String tooltip = is_warning ? TTR ( " Warning: " ) : TTR ( " Error: " ) ;
2018-09-08 23:31:49 +00:00
TreeItem * error = error_tree - > create_item ( r ) ;
error - > set_collapsed ( true ) ;
2015-08-04 12:47:32 +00:00
2019-09-25 08:47:41 +00:00
error - > set_icon ( 0 , get_icon ( is_warning ? " Warning " : " Error " , " EditorIcons " ) ) ;
2018-09-08 23:31:49 +00:00
error - > set_text ( 0 , time ) ;
error - > set_text_align ( 0 , TreeItem : : ALIGN_LEFT ) ;
2021-09-24 13:53:41 +00:00
const Color color = get_color ( is_warning ? " warning_color " : " error_color " , " Editor " ) ;
error - > set_custom_color ( 0 , color ) ;
error - > set_custom_color ( 1 , color ) ;
2019-09-25 08:47:41 +00:00
String error_title ;
// Include method name, when given, in error title.
2021-05-05 10:44:11 +00:00
if ( has_method ) {
2019-09-25 08:47:41 +00:00
error_title + = method + " : " ;
2021-05-05 10:44:11 +00:00
}
2019-09-25 08:47:41 +00:00
// If we have a (custom) error message, use it as title, and add a C++ Error
// item with the original error condition.
error_title + = error_msg . empty ( ) ? error_cond : error_msg ;
error - > set_text ( 1 , error_title ) ;
tooltip + = " " + error_title + " \n " ;
if ( has_error_msg ) {
// Add item for C++ error condition.
TreeItem * cpp_cond = error_tree - > create_item ( error ) ;
cpp_cond - > set_text ( 0 , " < " + TTR ( " C++ Error " ) + " > " ) ;
cpp_cond - > set_text ( 1 , error_cond ) ;
cpp_cond - > set_text_align ( 0 , TreeItem : : ALIGN_LEFT ) ;
tooltip + = TTR ( " C++ Error: " ) + " " + error_cond + " \n " ;
2021-05-05 10:44:11 +00:00
if ( source_is_project_file ) {
2019-09-25 08:47:41 +00:00
cpp_cond - > set_metadata ( 0 , source_meta ) ;
2021-05-05 10:44:11 +00:00
}
2019-09-25 08:47:41 +00:00
}
2018-09-08 23:31:49 +00:00
2019-09-25 08:47:41 +00:00
// Source of the error.
String source_txt = ( source_is_project_file ? source_file . get_file ( ) : source_file ) + " : " + source_line ;
2021-05-05 10:44:11 +00:00
if ( has_method ) {
2019-09-25 08:47:41 +00:00
source_txt + = " @ " + method + " () " ;
2021-05-05 10:44:11 +00:00
}
2015-08-04 12:47:32 +00:00
2019-09-25 08:47:41 +00:00
TreeItem * cpp_source = error_tree - > create_item ( error ) ;
cpp_source - > set_text ( 0 , " < " + ( source_is_project_file ? TTR ( " Source " ) : TTR ( " C++ Source " ) ) + " > " ) ;
cpp_source - > set_text ( 1 , source_txt ) ;
cpp_source - > set_text_align ( 0 , TreeItem : : ALIGN_LEFT ) ;
tooltip + = ( source_is_project_file ? TTR ( " Source: " ) : TTR ( " C++ Source: " ) ) + " " + source_txt + " \n " ;
2018-09-08 23:31:49 +00:00
2019-09-25 08:47:41 +00:00
// Set metadata to highlight error line in scripts.
2018-09-08 23:31:49 +00:00
if ( source_is_project_file ) {
2019-09-25 08:47:41 +00:00
error - > set_metadata ( 0 , source_meta ) ;
cpp_source - > set_metadata ( 0 , source_meta ) ;
2015-08-04 12:47:32 +00:00
}
2019-09-25 08:47:41 +00:00
error - > set_tooltip ( 0 , tooltip ) ;
error - > set_tooltip ( 1 , tooltip ) ;
// Format stack trace.
// stack_items_count is the number of elements to parse, with 3 items per frame
// of the stack trace (script, method, line).
int stack_items_count = p_data [ 1 ] ;
2018-09-08 23:31:49 +00:00
2019-09-25 08:47:41 +00:00
for ( int i = 0 ; i < stack_items_count ; i + = 3 ) {
2018-09-08 23:31:49 +00:00
String script = p_data [ 2 + i ] ;
2019-02-12 20:10:08 +00:00
String method2 = p_data [ 3 + i ] ;
2018-09-08 23:31:49 +00:00
int line = p_data [ 4 + i ] ;
TreeItem * stack_trace = error_tree - > create_item ( error ) ;
Array meta ;
meta . push_back ( script ) ;
meta . push_back ( line ) ;
stack_trace - > set_metadata ( 0 , meta ) ;
if ( i = = 0 ) {
stack_trace - > set_text ( 0 , " < " + TTR ( " Stack Trace " ) + " > " ) ;
stack_trace - > set_text_align ( 0 , TreeItem : : ALIGN_LEFT ) ;
error - > set_metadata ( 0 , meta ) ;
}
2019-02-12 20:10:08 +00:00
stack_trace - > set_text ( 1 , script . get_file ( ) + " : " + itos ( line ) + " @ " + method2 + " () " ) ;
2018-09-08 23:31:49 +00:00
}
2015-08-04 12:47:32 +00:00
2021-05-05 10:44:11 +00:00
if ( is_warning ) {
2018-08-16 05:41:03 +00:00
warning_count + + ;
2021-05-05 10:44:11 +00:00
} else {
2018-08-16 05:41:03 +00:00
error_count + + ;
2021-05-05 10:44:11 +00:00
}
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " profile_sig " ) {
2016-05-22 00:18:16 +00:00
//cache a signature
2017-03-05 15:44:50 +00:00
profiler_signature [ p_data [ 1 ] ] = p_data [ 0 ] ;
} else if ( p_msg = = " profile_frame " | | p_msg = = " profile_total " ) {
2016-05-22 00:18:16 +00:00
EditorProfiler : : Metric metric ;
2017-03-05 15:44:50 +00:00
metric . valid = true ;
metric . frame_number = p_data [ 0 ] ;
metric . frame_time = p_data [ 1 ] ;
2022-05-06 17:28:55 +00:00
metric . process_time = p_data [ 2 ] ;
2017-09-30 14:19:07 +00:00
metric . physics_time = p_data [ 3 ] ;
metric . physics_frame_time = p_data [ 4 ] ;
2016-05-22 00:18:16 +00:00
int frame_data_amount = p_data [ 6 ] ;
int frame_function_amount = p_data [ 7 ] ;
if ( frame_data_amount ) {
EditorProfiler : : Metric : : Category frame_time ;
2017-03-05 15:44:50 +00:00
frame_time . signature = " category_frame_time " ;
frame_time . name = " Frame Time " ;
frame_time . total_time = metric . frame_time ;
2016-05-22 00:18:16 +00:00
EditorProfiler : : Metric : : Category : : Item item ;
2017-03-05 15:44:50 +00:00
item . calls = 1 ;
item . line = 0 ;
2018-04-19 11:04:41 +00:00
2017-10-21 14:28:08 +00:00
item . name = " Physics Time " ;
2017-09-30 14:19:07 +00:00
item . total = metric . physics_time ;
2017-03-05 15:44:50 +00:00
item . self = item . total ;
2017-09-30 14:19:07 +00:00
item . signature = " physics_time " ;
2016-05-22 00:18:16 +00:00
frame_time . items . push_back ( item ) ;
2022-05-06 17:28:55 +00:00
item . name = " Process Time " ;
item . total = metric . process_time ;
2017-03-05 15:44:50 +00:00
item . self = item . total ;
2022-05-06 17:28:55 +00:00
item . signature = " process_time " ;
2016-05-22 00:18:16 +00:00
frame_time . items . push_back ( item ) ;
2017-10-21 14:28:08 +00:00
item . name = " Physics Frame Time " ;
2017-09-30 14:19:07 +00:00
item . total = metric . physics_frame_time ;
2017-03-05 15:44:50 +00:00
item . self = item . total ;
2017-09-30 14:19:07 +00:00
item . signature = " physics_frame_time " ;
2016-05-22 00:18:16 +00:00
frame_time . items . push_back ( item ) ;
metric . categories . push_back ( frame_time ) ;
}
2017-03-05 15:44:50 +00:00
int idx = 8 ;
for ( int i = 0 ; i < frame_data_amount ; i + + ) {
2016-05-22 00:18:16 +00:00
EditorProfiler : : Metric : : Category c ;
2017-03-05 15:44:50 +00:00
String name = p_data [ idx + + ] ;
Array values = p_data [ idx + + ] ;
2022-03-29 03:29:15 +00:00
c . name = EditorPropertyNameProcessor : : get_singleton ( ) - > process_name ( name , EditorPropertyNameProcessor : : STYLE_CAPITALIZED ) ;
2017-03-05 15:44:50 +00:00
c . items . resize ( values . size ( ) / 2 ) ;
c . total_time = 0 ;
c . signature = " categ:: " + name ;
2019-02-12 20:10:08 +00:00
for ( int j = 0 ; j < values . size ( ) ; j + = 2 ) {
2016-05-22 00:18:16 +00:00
EditorProfiler : : Metric : : Category : : Item item ;
2017-03-05 15:44:50 +00:00
item . calls = 1 ;
2018-04-19 11:04:41 +00:00
item . line = 0 ;
2019-02-12 20:10:08 +00:00
item . name = values [ j ] ;
item . self = values [ j + 1 ] ;
2017-03-05 15:44:50 +00:00
item . total = item . self ;
item . signature = " categ:: " + name + " :: " + item . name ;
item . name = item . name . capitalize ( ) ;
c . total_time + = item . total ;
2019-02-12 20:10:08 +00:00
c . items . write [ j / 2 ] = item ;
2016-05-22 00:18:16 +00:00
}
metric . categories . push_back ( c ) ;
}
EditorProfiler : : Metric : : Category funcs ;
2017-03-05 15:44:50 +00:00
funcs . total_time = p_data [ 5 ] ; //script time
2016-05-22 00:18:16 +00:00
funcs . items . resize ( frame_function_amount ) ;
2017-03-05 15:44:50 +00:00
funcs . name = " Script Functions " ;
funcs . signature = " script_functions " ;
for ( int i = 0 ; i < frame_function_amount ; i + + ) {
2016-05-22 00:18:16 +00:00
int signature = p_data [ idx + + ] ;
int calls = p_data [ idx + + ] ;
float total = p_data [ idx + + ] ;
float self = p_data [ idx + + ] ;
EditorProfiler : : Metric : : Category : : Item item ;
if ( profiler_signature . has ( signature ) ) {
2017-03-05 15:44:50 +00:00
item . signature = profiler_signature [ signature ] ;
2016-05-22 00:18:16 +00:00
String name = profiler_signature [ signature ] ;
Vector < String > strings = name . split ( " :: " ) ;
2017-03-05 15:44:50 +00:00
if ( strings . size ( ) = = 3 ) {
item . name = strings [ 2 ] ;
item . script = strings [ 0 ] ;
item . line = strings [ 1 ] . to_int ( ) ;
2019-01-25 01:19:06 +00:00
} else if ( strings . size ( ) = = 4 ) { //Built-in scripts have an :: in their name
item . name = strings [ 3 ] ;
item . script = strings [ 0 ] + " :: " + strings [ 1 ] ;
item . line = strings [ 2 ] . to_int ( ) ;
2016-05-22 00:18:16 +00:00
}
} else {
2017-03-05 15:44:50 +00:00
item . name = " SigErr " + itos ( signature ) ;
2016-05-22 00:18:16 +00:00
}
2017-03-05 15:44:50 +00:00
item . calls = calls ;
item . self = self ;
item . total = total ;
2018-07-25 01:11:03 +00:00
funcs . items . write [ i ] = item ;
2016-05-22 00:18:16 +00:00
}
metric . categories . push_back ( funcs ) ;
2021-05-05 10:44:11 +00:00
if ( p_msg = = " profile_frame " ) {
2017-03-05 15:44:50 +00:00
profiler - > add_frame_metric ( metric , false ) ;
2021-05-05 10:44:11 +00:00
} else {
2017-03-05 15:44:50 +00:00
profiler - > add_frame_metric ( metric , true ) ;
2021-05-05 10:44:11 +00:00
}
2019-09-01 16:38:58 +00:00
} else if ( p_msg = = " network_profile " ) {
int frame_size = 6 ;
for ( int i = 0 ; i < p_data . size ( ) ; i + = frame_size ) {
MultiplayerAPI : : ProfilingInfo pi ;
pi . node = p_data [ i + 0 ] ;
pi . node_path = p_data [ i + 1 ] ;
pi . incoming_rpc = p_data [ i + 2 ] ;
pi . incoming_rset = p_data [ i + 3 ] ;
pi . outgoing_rpc = p_data [ i + 4 ] ;
pi . outgoing_rset = p_data [ i + 5 ] ;
network_profiler - > add_node_frame_data ( pi ) ;
}
} else if ( p_msg = = " network_bandwidth " ) {
network_profiler - > set_bandwidth ( p_data [ 0 ] , p_data [ 1 ] ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_msg = = " kill_me " ) {
2014-02-13 21:03:28 +00:00
editor - > call_deferred ( " stop_child_process " ) ;
}
}
2017-08-22 19:16:08 +00:00
void ScriptEditorDebugger : : _set_reason_text ( const String & p_reason , MessageType p_type ) {
switch ( p_type ) {
case MESSAGE_ERROR :
reason - > add_color_override ( " font_color " , get_color ( " error_color " , " Editor " ) ) ;
break ;
case MESSAGE_WARNING :
reason - > add_color_override ( " font_color " , get_color ( " warning_color " , " Editor " ) ) ;
break ;
default :
reason - > add_color_override ( " font_color " , get_color ( " success_color " , " Editor " ) ) ;
}
reason - > set_text ( p_reason ) ;
2018-05-26 11:50:46 +00:00
reason - > set_tooltip ( p_reason . word_wrap ( 80 ) ) ;
2017-08-22 19:16:08 +00:00
}
2017-10-23 08:11:46 +00:00
void ScriptEditorDebugger : : _performance_select ( ) {
2014-02-13 21:03:28 +00:00
perf_draw - > update ( ) ;
}
void ScriptEditorDebugger : : _performance_draw ( ) {
Vector < int > which ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < perf_items . size ( ) ; i + + ) {
2021-05-05 10:44:11 +00:00
if ( perf_items [ i ] - > is_checked ( 0 ) ) {
2014-02-13 21:03:28 +00:00
which . push_back ( i ) ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
}
2017-08-26 16:02:52 +00:00
if ( which . empty ( ) ) {
2019-09-04 05:20:57 +00:00
info_message - > show ( ) ;
2014-02-13 21:03:28 +00:00
return ;
2017-08-26 16:02:52 +00:00
}
2014-02-13 21:03:28 +00:00
2019-09-04 05:20:57 +00:00
info_message - > hide ( ) ;
2020-06-05 23:30:29 +00:00
const Ref < StyleBox > graph_sb = get_stylebox ( " normal " , " TextEdit " ) ;
const Ref < Font > graph_font = get_font ( " font " , " TextEdit " ) ;
2014-02-13 21:03:28 +00:00
2020-06-05 23:30:29 +00:00
const int cols = Math : : ceil ( Math : : sqrt ( ( float ) which . size ( ) ) ) ;
2017-08-26 16:02:52 +00:00
int rows = Math : : ceil ( ( float ) which . size ( ) / cols ) ;
2020-06-05 23:30:29 +00:00
if ( which . size ( ) = = 1 ) {
2017-03-05 15:44:50 +00:00
rows = 1 ;
2020-06-05 23:30:29 +00:00
}
2017-03-05 15:44:50 +00:00
2020-06-05 23:30:29 +00:00
const int margin = 3 ;
const int point_sep = 5 ;
const Size2i s = Size2i ( perf_draw - > get_size ( ) ) / Size2i ( cols , rows ) ;
2017-03-05 15:44:50 +00:00
2020-06-05 23:30:29 +00:00
for ( int i = 0 ; i < which . size ( ) ; i + + ) {
2017-03-05 15:44:50 +00:00
Point2i p ( i % cols , i / cols ) ;
Rect2i r ( p * s , s ) ;
2017-06-03 22:25:13 +00:00
r . position + = Point2 ( margin , margin ) ;
2017-03-05 15:44:50 +00:00
r . size - = Point2 ( margin , margin ) * 2.0 ;
perf_draw - > draw_style_box ( graph_sb , r ) ;
2017-06-03 22:25:13 +00:00
r . position + = graph_sb - > get_offset ( ) ;
2017-03-05 15:44:50 +00:00
r . size - = graph_sb - > get_minimum_size ( ) ;
2020-06-05 23:30:29 +00:00
const int pi = which [ i ] ;
// Draw horizontal lines with labels.
int nb_lines = 5 ;
// Draw less lines if the monitor isn't tall enough to display 5 labels.
if ( r . size . height < = 160 * EDSCALE ) {
nb_lines = 3 ;
} else if ( r . size . height < = 240 * EDSCALE ) {
nb_lines = 4 ;
}
const float inv_nb_lines = 1.0 / nb_lines ;
for ( int line = 0 ; line < nb_lines ; line + = 1 ) {
const int from_x = r . position . x ;
const int to_x = r . position . x + r . size . width ;
const int y = r . position . y + ( r . size . height * inv_nb_lines + line * inv_nb_lines * r . size . height ) ;
perf_draw - > draw_line (
Point2 ( from_x , y ) ,
Point2i ( to_x , y ) ,
Color ( 0.5 , 0.5 , 0.5 , 0.25 ) ,
Math : : round ( EDSCALE ) ) ;
String label ;
switch ( Performance : : MonitorType ( ( int ) perf_items [ pi ] - > get_metadata ( 1 ) ) ) {
case Performance : : MONITOR_TYPE_MEMORY : {
label = String : : humanize_size ( Math : : ceil ( ( 1 - inv_nb_lines - inv_nb_lines * line ) * perf_max [ pi ] ) ) ;
} break ;
case Performance : : MONITOR_TYPE_TIME : {
label = rtos ( ( 1 - inv_nb_lines - inv_nb_lines * line ) * perf_max [ pi ] * 1000 ) . pad_decimals ( 2 ) + " ms " ;
} break ;
default : {
label = itos ( Math : : ceil ( ( 1 - inv_nb_lines - inv_nb_lines * line ) * perf_max [ pi ] ) ) ;
} break ;
}
perf_draw - > draw_string (
graph_font ,
Point2 ( from_x , y - graph_font - > get_ascent ( ) * 0.25 ) ,
label ,
Color ( 0.5 , 0.5 , 0.5 , 1.0 ) ) ;
}
const float h = ( float ) which [ i ] / ( float ) ( perf_items . size ( ) ) ;
// Use a darker color on light backgrounds for better visibility.
const float value_multiplier = EditorSettings : : get_singleton ( ) - > is_dark_theme ( ) ? 1.4 : 0.55 ;
Color color = get_color ( " accent_color " , " Editor " ) ;
color . set_hsv ( Math : : fmod ( h + 0.4 , 0.9 ) , color . get_s ( ) * 0.9 , color . get_v ( ) * value_multiplier ) ;
// Draw the monitor name in the top-left corner.
color . a = 0.6 ;
perf_draw - > draw_string (
graph_font ,
r . position + Point2 ( 0 , graph_font - > get_ascent ( ) ) ,
perf_items [ pi ] - > get_text ( 0 ) ,
color ,
r . size . x ) ;
// Draw the monitor value in the top-left corner, just below the name.
color . a = 0.9 ;
perf_draw - > draw_string (
graph_font ,
r . position + Point2 ( 0 , graph_font - > get_ascent ( ) + graph_font - > get_height ( ) ) ,
perf_items [ pi ] - > get_text ( 1 ) ,
color ,
r . size . y ) ;
const float spacing = point_sep / float ( cols ) ;
2014-02-13 21:03:28 +00:00
float from = r . size . width ;
2021-05-04 12:20:36 +00:00
const List < Vector < float > > : : Element * E = perf_history . front ( ) ;
2017-03-05 15:44:50 +00:00
float prev = - 1 ;
while ( from > = 0 & & E ) {
2014-02-13 21:03:28 +00:00
float m = perf_max [ pi ] ;
2020-06-05 23:30:29 +00:00
if ( m = = 0 ) {
2017-03-05 15:44:50 +00:00
m = 0.00001 ;
2020-06-05 23:30:29 +00:00
}
2019-02-12 20:10:08 +00:00
float h2 = E - > get ( ) [ pi ] / m ;
h2 = ( 1.0 - h2 ) * r . size . y ;
2017-03-05 15:44:50 +00:00
2020-06-05 23:30:29 +00:00
if ( E ! = perf_history . front ( ) ) {
perf_draw - > draw_line (
r . position + Point2 ( from , h2 ) ,
r . position + Point2 ( from + spacing , prev ) ,
color ,
Math : : round ( EDSCALE ) ) ;
}
2019-02-12 20:10:08 +00:00
prev = h2 ;
2017-03-05 15:44:50 +00:00
E = E - > next ( ) ;
from - = spacing ;
2014-02-13 21:03:28 +00:00
}
}
}
void ScriptEditorDebugger : : _notification ( int p_what ) {
2017-03-05 15:44:50 +00:00
switch ( p_what ) {
2014-11-06 00:20:42 +00:00
case NOTIFICATION_ENTER_TREE : {
2016-01-23 22:51:51 +00:00
inspector - > edit ( variables ) ;
2019-07-29 18:09:22 +00:00
skip_breakpoints - > set_icon ( get_icon ( " DebugSkipBreakpointsOff " , " EditorIcons " ) ) ;
2018-02-22 07:50:38 +00:00
copy - > set_icon ( get_icon ( " ActionCopy " , " EditorIcons " ) ) ;
2018-02-13 16:46:45 +00:00
2017-03-05 15:44:50 +00:00
step - > set_icon ( get_icon ( " DebugStep " , " EditorIcons " ) ) ;
next - > set_icon ( get_icon ( " DebugNext " , " EditorIcons " ) ) ;
back - > set_icon ( get_icon ( " Back " , " EditorIcons " ) ) ;
forward - > set_icon ( get_icon ( " Forward " , " EditorIcons " ) ) ;
dobreak - > set_icon ( get_icon ( " Pause " , " EditorIcons " ) ) ;
docontinue - > set_icon ( get_icon ( " DebugContinue " , " EditorIcons " ) ) ;
le_set - > connect ( " pressed " , this , " _live_edit_set " ) ;
le_clear - > connect ( " pressed " , this , " _live_edit_clear " ) ;
2018-09-08 23:31:49 +00:00
error_tree - > connect ( " item_selected " , this , " _error_selected " ) ;
error_tree - > connect ( " item_activated " , this , " _error_activated " ) ;
2017-03-05 15:44:50 +00:00
vmem_refresh - > set_icon ( get_icon ( " Reload " , " EditorIcons " ) ) ;
2020-03-17 11:49:31 +00:00
vmem_export - > set_icon ( get_icon ( " Save " , " EditorIcons " ) ) ;
2022-03-07 10:57:30 +00:00
search - > set_right_icon ( get_icon ( " Search " , " EditorIcons " ) ) ;
2014-02-13 21:03:28 +00:00
2017-08-08 02:55:24 +00:00
reason - > add_color_override ( " font_color " , get_color ( " error_color " , " Editor " ) ) ;
2014-02-13 21:03:28 +00:00
} break ;
case NOTIFICATION_PROCESS : {
2016-05-22 22:28:37 +00:00
if ( connection . is_valid ( ) ) {
2017-03-05 15:44:50 +00:00
inspect_scene_tree_timeout - = get_process_delta_time ( ) ;
if ( inspect_scene_tree_timeout < 0 ) {
2017-11-22 13:50:54 +00:00
inspect_scene_tree_timeout = EditorSettings : : get_singleton ( ) - > get ( " debugger/remote_scene_tree_refresh_interval " ) ;
2017-01-13 13:45:50 +00:00
if ( inspect_scene_tree - > is_visible_in_tree ( ) ) {
2016-05-22 22:28:37 +00:00
_scene_tree_request ( ) ;
}
}
2017-03-05 15:44:50 +00:00
inspect_edited_object_timeout - = get_process_delta_time ( ) ;
if ( inspect_edited_object_timeout < 0 ) {
inspect_edited_object_timeout = EditorSettings : : get_singleton ( ) - > get ( " debugger/remote_inspect_refresh_interval " ) ;
2017-11-23 07:23:24 +00:00
if ( inspected_object_id ) {
if ( ScriptEditorDebuggerInspectedObject * obj = Object : : cast_to < ScriptEditorDebuggerInspectedObject > ( ObjectDB : : get_instance ( editor - > get_editor_history ( ) - > get_current ( ) ) ) ) {
if ( obj - > remote_object_id = = inspected_object_id ) {
//take the chance and re-inspect selected object
Array msg ;
msg . push_back ( " inspect_object " ) ;
msg . push_back ( inspected_object_id ) ;
ppeer - > put_var ( msg ) ;
}
}
2016-05-22 22:28:37 +00:00
}
}
2019-04-06 20:55:01 +00:00
if ( camera_override = = OVERRIDE_2D ) {
CanvasItemEditor * editor = CanvasItemEditor : : get_singleton ( ) ;
Dictionary state = editor - > get_state ( ) ;
float zoom = state [ " zoom " ] ;
Point2 offset = state [ " ofs " ] ;
Transform2D transform ;
transform . scale_basis ( Size2 ( zoom , zoom ) ) ;
transform . elements [ 2 ] = - offset * zoom ;
Array msg ;
msg . push_back ( " override_camera_2D:transform " ) ;
msg . push_back ( transform ) ;
ppeer - > put_var ( msg ) ;
} else if ( camera_override > = OVERRIDE_3D_1 ) {
int viewport_idx = camera_override - OVERRIDE_3D_1 ;
SpatialEditorViewport * viewport = SpatialEditor : : get_singleton ( ) - > get_editor_viewport ( viewport_idx ) ;
Camera * const cam = viewport - > get_camera ( ) ;
Array msg ;
msg . push_back ( " override_camera_3D:transform " ) ;
msg . push_back ( cam - > get_camera_transform ( ) ) ;
if ( cam - > get_projection ( ) = = Camera : : PROJECTION_ORTHOGONAL ) {
msg . push_back ( false ) ;
msg . push_back ( cam - > get_size ( ) ) ;
} else {
msg . push_back ( true ) ;
msg . push_back ( cam - > get_fov ( ) ) ;
}
msg . push_back ( cam - > get_znear ( ) ) ;
msg . push_back ( cam - > get_zfar ( ) ) ;
ppeer - > put_var ( msg ) ;
}
2016-05-22 22:28:37 +00:00
}
2018-08-16 05:41:03 +00:00
if ( error_count ! = last_error_count | | warning_count ! = last_warning_count ) {
if ( error_count = = 0 & & warning_count = = 0 ) {
2019-02-28 21:12:14 +00:00
errors_tab - > set_name ( TTR ( " Errors " ) ) ;
2016-05-04 01:25:37 +00:00
debugger_button - > set_text ( TTR ( " Debugger " ) ) ;
2021-09-24 15:11:57 +00:00
debugger_button - > add_color_override ( " font_color " , get_color ( " font_color " , " Editor " ) ) ;
2016-01-17 23:03:57 +00:00
debugger_button - > set_icon ( Ref < Texture > ( ) ) ;
2019-02-28 21:12:14 +00:00
tabs - > set_tab_icon ( errors_tab - > get_index ( ) , Ref < Texture > ( ) ) ;
2015-08-04 12:47:32 +00:00
} else {
2019-02-28 21:12:14 +00:00
errors_tab - > set_name ( TTR ( " Errors " ) + " ( " + itos ( error_count + warning_count ) + " ) " ) ;
2018-08-16 05:41:03 +00:00
debugger_button - > set_text ( TTR ( " Debugger " ) + " ( " + itos ( error_count + warning_count ) + " ) " ) ;
2020-05-09 13:29:13 +00:00
if ( error_count > = 1 & & warning_count > = 1 ) {
debugger_button - > set_icon ( get_icon ( " ErrorWarning " , " EditorIcons " ) ) ;
2021-09-24 15:11:57 +00:00
// Use error color to represent the highest level of severity reported.
debugger_button - > add_color_override ( " font_color " , get_color ( " error_color " , " Editor " ) ) ;
2020-05-09 13:29:13 +00:00
tabs - > set_tab_icon ( errors_tab - > get_index ( ) , get_icon ( " ErrorWarning " , " EditorIcons " ) ) ;
} else if ( error_count > = 1 ) {
2018-08-16 05:41:03 +00:00
debugger_button - > set_icon ( get_icon ( " Error " , " EditorIcons " ) ) ;
2021-09-24 15:11:57 +00:00
debugger_button - > add_color_override ( " font_color " , get_color ( " error_color " , " Editor " ) ) ;
2019-02-28 21:12:14 +00:00
tabs - > set_tab_icon ( errors_tab - > get_index ( ) , get_icon ( " Error " , " EditorIcons " ) ) ;
2020-05-09 13:29:13 +00:00
} else {
debugger_button - > set_icon ( get_icon ( " Warning " , " EditorIcons " ) ) ;
2021-09-24 15:11:57 +00:00
debugger_button - > add_color_override ( " font_color " , get_color ( " warning_color " , " Editor " ) ) ;
2020-05-09 13:29:13 +00:00
tabs - > set_tab_icon ( errors_tab - > get_index ( ) , get_icon ( " Warning " , " EditorIcons " ) ) ;
2018-08-16 05:41:03 +00:00
}
2015-08-04 12:47:32 +00:00
}
2017-03-05 15:44:50 +00:00
last_error_count = error_count ;
2018-08-16 05:41:03 +00:00
last_warning_count = warning_count ;
2015-08-04 12:47:32 +00:00
}
2016-05-23 20:10:26 +00:00
2019-06-04 05:37:57 +00:00
if ( server - > is_connection_available ( ) ) {
if ( connection . is_valid ( ) ) {
// We already have a valid connection. Disconnecting any new connecting client to prevent it from hanging.
// (If we don't keep a reference to the connection it will be destroyed and disconnect_from_host will be called internally)
server - > take_connection ( ) ;
} else {
// We just got the first connection.
2014-02-13 21:03:28 +00:00
connection = server - > take_connection ( ) ;
2021-05-05 10:44:11 +00:00
if ( connection . is_null ( ) ) {
2014-02-13 21:03:28 +00:00
break ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
2019-09-19 23:56:09 +00:00
EditorNode : : get_log ( ) - > add_message ( " --- Debugging process started --- " , EditorLog : : MSG_TYPE_EDITOR ) ;
2014-02-13 21:03:28 +00:00
ppeer - > set_stream_peer ( connection ) ;
2016-01-17 23:03:57 +00:00
//EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
//emit_signal("show_debugger",true);
2015-12-12 13:00:12 +00:00
2014-02-13 21:03:28 +00:00
dobreak - > set_disabled ( false ) ;
tabs - > set_current_tab ( 0 ) ;
2019-09-19 23:56:09 +00:00
_set_reason_text ( TTR ( " Child process connected. " ) , MESSAGE_SUCCESS ) ;
2016-05-22 00:18:16 +00:00
profiler - > clear ( ) ;
2016-05-22 22:28:37 +00:00
inspect_scene_tree - > clear ( ) ;
2015-08-02 15:29:37 +00:00
le_set - > set_disabled ( true ) ;
le_clear - > set_disabled ( false ) ;
2019-11-28 15:37:15 +00:00
vmem_refresh - > set_disabled ( false ) ;
2018-09-08 23:31:49 +00:00
error_tree - > clear ( ) ;
2017-03-05 15:44:50 +00:00
error_count = 0 ;
2018-08-16 05:41:03 +00:00
warning_count = 0 ;
2016-05-22 00:18:16 +00:00
profiler_signature . clear ( ) ;
2015-08-02 15:29:37 +00:00
//live_edit_root->set_text("/root");
2016-05-22 00:18:16 +00:00
EditorNode : : get_singleton ( ) - > get_pause_button ( ) - > set_pressed ( false ) ;
EditorNode : : get_singleton ( ) - > get_pause_button ( ) - > set_disabled ( false ) ;
2015-08-02 15:29:37 +00:00
update_live_edit_root ( ) ;
2016-05-22 00:18:16 +00:00
if ( profiler - > is_profiling ( ) ) {
_profiler_activate ( true ) ;
}
2019-09-01 16:38:58 +00:00
if ( network_profiler - > is_profiling ( ) ) {
_network_profiler_activate ( true ) ;
}
2014-02-13 21:03:28 +00:00
}
2019-06-04 05:37:57 +00:00
}
2021-05-05 10:44:11 +00:00
if ( connection . is_null ( ) ) {
2019-06-04 05:37:57 +00:00
break ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
2017-01-14 14:07:57 +00:00
if ( ! connection - > is_connected_to_host ( ) ) {
2014-02-13 21:03:28 +00:00
stop ( ) ;
editor - > notify_child_process_exited ( ) ; //somehow, exited
break ;
} ;
if ( ppeer - > get_available_packet_count ( ) < = 0 ) {
break ;
} ;
2018-01-03 14:59:10 +00:00
const uint64_t until = OS : : get_singleton ( ) - > get_ticks_msec ( ) + 20 ;
2017-03-05 15:44:50 +00:00
while ( ppeer - > get_available_packet_count ( ) > 0 ) {
2014-02-13 21:03:28 +00:00
if ( pending_in_queue ) {
2017-03-05 15:44:50 +00:00
int todo = MIN ( ppeer - > get_available_packet_count ( ) , pending_in_queue ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < todo ; i + + ) {
2014-02-13 21:03:28 +00:00
Variant cmd ;
Error ret = ppeer - > get_var ( cmd ) ;
2017-03-05 15:44:50 +00:00
if ( ret ! = OK ) {
2014-02-13 21:03:28 +00:00
stop ( ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( ret ! = OK ) ;
2014-02-13 21:03:28 +00:00
}
message . push_back ( cmd ) ;
pending_in_queue - - ;
}
2017-03-05 15:44:50 +00:00
if ( pending_in_queue = = 0 ) {
_parse_message ( message_type , message ) ;
2014-02-13 21:03:28 +00:00
message . clear ( ) ;
}
} else {
2017-03-05 15:44:50 +00:00
if ( ppeer - > get_available_packet_count ( ) > = 2 ) {
2014-02-13 21:03:28 +00:00
Variant cmd ;
Error ret = ppeer - > get_var ( cmd ) ;
2017-03-05 15:44:50 +00:00
if ( ret ! = OK ) {
2014-02-13 21:03:28 +00:00
stop ( ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( ret ! = OK ) ;
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
if ( cmd . get_type ( ) ! = Variant : : STRING ) {
2014-02-13 21:03:28 +00:00
stop ( ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( cmd . get_type ( ) ! = Variant : : STRING ) ;
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
message_type = cmd ;
2014-02-13 21:03:28 +00:00
ret = ppeer - > get_var ( cmd ) ;
2017-03-05 15:44:50 +00:00
if ( ret ! = OK ) {
2014-02-13 21:03:28 +00:00
stop ( ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( ret ! = OK ) ;
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
if ( cmd . get_type ( ) ! = Variant : : INT ) {
2014-02-13 21:03:28 +00:00
stop ( ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( cmd . get_type ( ) ! = Variant : : INT ) ;
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
pending_in_queue = cmd ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
if ( pending_in_queue = = 0 ) {
_parse_message ( message_type , Array ( ) ) ;
2014-02-13 21:03:28 +00:00
message . clear ( ) ;
}
} else {
break ;
}
}
2018-01-03 14:59:10 +00:00
2021-05-05 10:44:11 +00:00
if ( OS : : get_singleton ( ) - > get_ticks_msec ( ) > until ) {
2018-01-03 14:59:10 +00:00
break ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
}
} break ;
2017-05-02 20:13:12 +00:00
case EditorSettings : : NOTIFICATION_EDITOR_SETTINGS_CHANGED : {
2019-11-18 08:42:28 +00:00
add_constant_override ( " margin_left " , - EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_stylebox ( " BottomPanelDebuggerOverride " , " EditorStyles " ) - > get_margin ( MARGIN_LEFT ) ) ;
add_constant_override ( " margin_right " , - EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_stylebox ( " BottomPanelDebuggerOverride " , " EditorStyles " ) - > get_margin ( MARGIN_RIGHT ) ) ;
2017-05-02 20:13:12 +00:00
tabs - > add_style_override ( " panel " , editor - > get_gui_base ( ) - > get_stylebox ( " DebuggerPanel " , " EditorStyles " ) ) ;
tabs - > add_style_override ( " tab_fg " , editor - > get_gui_base ( ) - > get_stylebox ( " DebuggerTabFG " , " EditorStyles " ) ) ;
tabs - > add_style_override ( " tab_bg " , editor - > get_gui_base ( ) - > get_stylebox ( " DebuggerTabBG " , " EditorStyles " ) ) ;
2017-11-21 20:20:57 +00:00
2018-02-25 16:04:16 +00:00
copy - > set_icon ( get_icon ( " ActionCopy " , " EditorIcons " ) ) ;
step - > set_icon ( get_icon ( " DebugStep " , " EditorIcons " ) ) ;
next - > set_icon ( get_icon ( " DebugNext " , " EditorIcons " ) ) ;
back - > set_icon ( get_icon ( " Back " , " EditorIcons " ) ) ;
forward - > set_icon ( get_icon ( " Forward " , " EditorIcons " ) ) ;
dobreak - > set_icon ( get_icon ( " Pause " , " EditorIcons " ) ) ;
docontinue - > set_icon ( get_icon ( " DebugContinue " , " EditorIcons " ) ) ;
vmem_refresh - > set_icon ( get_icon ( " Reload " , " EditorIcons " ) ) ;
2020-03-17 11:49:31 +00:00
vmem_export - > set_icon ( get_icon ( " Save " , " EditorIcons " ) ) ;
2022-03-07 10:57:30 +00:00
search - > set_right_icon ( get_icon ( " Search " , " EditorIcons " ) ) ;
2017-05-02 20:13:12 +00:00
} break ;
2014-02-13 21:03:28 +00:00
}
}
2019-04-22 16:20:27 +00:00
void ScriptEditorDebugger : : _clear_execution ( ) {
TreeItem * ti = stack_dump - > get_selected ( ) ;
2021-05-05 10:44:11 +00:00
if ( ! ti ) {
2019-04-22 16:20:27 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2019-04-22 16:20:27 +00:00
Dictionary d = ti - > get_metadata ( 0 ) ;
stack_script = ResourceLoader : : load ( d [ " file " ] ) ;
emit_signal ( " clear_execution " , stack_script ) ;
stack_script . unref ( ) ;
}
2022-05-06 11:53:20 +00:00
void ScriptEditorDebugger : : start ( int p_port , const IP_Address & p_bind_address ) {
if ( is_inside_tree ( ) ) {
stop ( ) ;
}
2014-02-13 21:03:28 +00:00
2017-01-13 13:45:50 +00:00
if ( is_visible_in_tree ( ) ) {
2016-12-24 21:52:43 +00:00
EditorNode : : get_singleton ( ) - > make_bottom_panel_item_visible ( this ) ;
2016-09-05 23:44:33 +00:00
}
2014-02-13 21:03:28 +00:00
perf_history . clear ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < Performance : : MONITOR_MAX ; i + + ) {
2018-07-25 01:11:03 +00:00
perf_max . write [ i ] = 0 ;
2014-02-13 21:03:28 +00:00
}
2020-03-15 10:45:39 +00:00
const int max_tries = 6 ;
2022-05-06 11:53:20 +00:00
if ( p_port < 0 ) {
remote_port = ( int ) EditorSettings : : get_singleton ( ) - > get ( " network/debug/remote_port " ) ;
} else {
remote_port = p_port ;
}
2020-03-15 10:45:39 +00:00
int current_try = 0 ;
// Find first available port.
Error err = server - > listen ( remote_port ) ;
while ( err ! = OK & & current_try < max_tries ) {
EditorNode : : get_log ( ) - > add_message ( String ( " Remote debugger failed listening on port: " ) + itos ( remote_port ) + String ( " Retrying on new port: " + itos ( remote_port + 1 ) ) , EditorLog : : MSG_TYPE_WARNING ) ;
current_try + + ;
remote_port + + ;
OS : : get_singleton ( ) - > delay_usec ( 1000 ) ;
2022-05-06 11:53:20 +00:00
err = server - > listen ( remote_port , p_bind_address ) ;
2020-03-15 10:45:39 +00:00
}
// No suitable port found.
if ( err ! = OK ) {
2018-08-13 15:04:38 +00:00
EditorNode : : get_log ( ) - > add_message ( String ( " Error listening on port " ) + itos ( remote_port ) , EditorLog : : MSG_TYPE_ERROR ) ;
2020-03-15 10:45:39 +00:00
EditorNode : : get_log ( ) - > add_message ( String ( " Remote debugger error listening for connections. No free port " ) , EditorLog : : MSG_TYPE_ERROR ) ;
2017-06-08 19:24:36 +00:00
}
2017-11-22 13:50:54 +00:00
EditorNode : : get_singleton ( ) - > get_scene_tree_dock ( ) - > show_tab_buttons ( ) ;
2020-03-15 10:45:39 +00:00
2017-11-22 13:50:54 +00:00
auto_switch_remote_scene_tree = ( bool ) EditorSettings : : get_singleton ( ) - > get ( " debugger/auto_switch_to_remote_scene_tree " ) ;
2022-05-06 11:53:20 +00:00
if ( is_inside_tree ( ) & & auto_switch_remote_scene_tree ) {
2017-11-22 13:50:54 +00:00
EditorNode : : get_singleton ( ) - > get_scene_tree_dock ( ) - > show_remote_tree ( ) ;
}
2014-02-13 21:03:28 +00:00
set_process ( true ) ;
2018-01-07 12:00:15 +00:00
breaked = false ;
2019-04-06 20:55:01 +00:00
camera_override = OVERRIDE_NONE ;
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : pause ( ) {
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : unpause ( ) {
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : stop ( ) {
2014-02-13 21:03:28 +00:00
set_process ( false ) ;
2018-01-07 12:00:15 +00:00
breaked = false ;
2019-04-22 16:20:27 +00:00
_clear_execution ( ) ;
2014-02-13 21:03:28 +00:00
server - > stop ( ) ;
2018-10-11 14:02:55 +00:00
_clear_remote_objects ( ) ;
2014-02-13 21:03:28 +00:00
ppeer - > set_stream_peer ( Ref < StreamPeer > ( ) ) ;
if ( connection . is_valid ( ) ) {
2019-09-19 23:56:09 +00:00
EditorNode : : get_log ( ) - > add_message ( " --- Debugging process stopped --- " , EditorLog : : MSG_TYPE_EDITOR ) ;
2014-02-13 21:03:28 +00:00
connection . unref ( ) ;
2018-08-20 18:46:14 +00:00
reason - > set_text ( " " ) ;
reason - > set_tooltip ( " " ) ;
2014-02-13 21:03:28 +00:00
}
2020-03-15 10:45:39 +00:00
remote_port = 0 ;
2017-03-05 15:44:50 +00:00
pending_in_queue = 0 ;
2014-02-13 21:03:28 +00:00
message . clear ( ) ;
2015-08-02 15:29:37 +00:00
node_path_cache . clear ( ) ;
res_path_cache . clear ( ) ;
2016-05-22 00:18:16 +00:00
profiler_signature . clear ( ) ;
2015-08-02 15:29:37 +00:00
le_clear - > set_disabled ( false ) ;
le_set - > set_disabled ( true ) ;
2016-05-22 00:18:16 +00:00
profiler - > set_enabled ( true ) ;
2019-11-28 15:37:15 +00:00
vmem_refresh - > set_disabled ( true ) ;
2016-05-22 00:18:16 +00:00
2016-05-22 22:28:37 +00:00
inspect_scene_tree - > clear ( ) ;
2021-05-04 14:00:45 +00:00
inspector - > edit ( nullptr ) ;
2016-05-22 00:18:16 +00:00
EditorNode : : get_singleton ( ) - > get_pause_button ( ) - > set_pressed ( false ) ;
EditorNode : : get_singleton ( ) - > get_pause_button ( ) - > set_disabled ( true ) ;
2017-11-16 09:18:36 +00:00
EditorNode : : get_singleton ( ) - > get_scene_tree_dock ( ) - > hide_remote_tree ( ) ;
2017-11-22 13:50:54 +00:00
EditorNode : : get_singleton ( ) - > get_scene_tree_dock ( ) - > hide_tab_buttons ( ) ;
2016-05-22 00:18:16 +00:00
2015-12-12 13:09:50 +00:00
if ( hide_on_stop ) {
2021-05-05 10:44:11 +00:00
if ( is_visible_in_tree ( ) ) {
2016-01-17 23:03:57 +00:00
EditorNode : : get_singleton ( ) - > hide_bottom_panel ( ) ;
2021-05-05 10:44:11 +00:00
}
2017-03-05 15:44:50 +00:00
emit_signal ( " show_debugger " , false ) ;
2015-12-12 13:09:50 +00:00
}
2014-02-13 21:03:28 +00:00
}
2016-05-22 00:18:16 +00:00
void ScriptEditorDebugger : : _profiler_activate ( bool p_enable ) {
2021-05-05 10:44:11 +00:00
if ( ! connection . is_valid ( ) ) {
2016-05-22 00:18:16 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2016-05-22 00:18:16 +00:00
if ( p_enable ) {
profiler_signature . clear ( ) ;
Array msg ;
msg . push_back ( " start_profiling " ) ;
int max_funcs = EditorSettings : : get_singleton ( ) - > get ( " debugger/profiler_frame_max_functions " ) ;
2017-03-05 15:44:50 +00:00
max_funcs = CLAMP ( max_funcs , 16 , 512 ) ;
2016-05-22 00:18:16 +00:00
msg . push_back ( max_funcs ) ;
ppeer - > put_var ( msg ) ;
2018-08-24 07:35:07 +00:00
print_verbose ( " Starting profiling. " ) ;
2016-05-22 00:18:16 +00:00
} else {
Array msg ;
msg . push_back ( " stop_profiling " ) ;
ppeer - > put_var ( msg ) ;
2018-08-24 07:35:07 +00:00
print_verbose ( " Ending profiling. " ) ;
2016-05-22 00:18:16 +00:00
}
}
2019-09-01 16:38:58 +00:00
void ScriptEditorDebugger : : _network_profiler_activate ( bool p_enable ) {
2021-05-05 10:44:11 +00:00
if ( ! connection . is_valid ( ) ) {
2019-09-01 16:38:58 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2019-09-01 16:38:58 +00:00
if ( p_enable ) {
Array msg ;
msg . push_back ( " start_network_profiling " ) ;
ppeer - > put_var ( msg ) ;
print_verbose ( " Starting network profiling. " ) ;
} else {
Array msg ;
msg . push_back ( " stop_network_profiling " ) ;
ppeer - > put_var ( msg ) ;
print_verbose ( " Ending network profiling. " ) ;
}
}
2016-05-22 00:18:16 +00:00
void ScriptEditorDebugger : : _profiler_seeked ( ) {
2021-05-05 10:44:11 +00:00
if ( ! connection . is_valid ( ) | | ! connection - > is_connected_to_host ( ) ) {
2016-05-22 00:18:16 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2016-05-22 00:18:16 +00:00
2021-05-05 10:44:11 +00:00
if ( breaked ) {
2016-05-22 00:18:16 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2017-01-14 17:03:38 +00:00
debug_break ( ) ;
2016-05-22 00:18:16 +00:00
}
2014-02-13 21:03:28 +00:00
void ScriptEditorDebugger : : _stack_dump_frame_selected ( ) {
TreeItem * ti = stack_dump - > get_selected ( ) ;
2021-05-05 10:44:11 +00:00
if ( ! ti ) {
2014-02-13 21:03:28 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
Dictionary d = ti - > get_metadata ( 0 ) ;
2017-06-25 09:20:01 +00:00
stack_script = ResourceLoader : : load ( d [ " file " ] ) ;
emit_signal ( " goto_script_line " , stack_script , int ( d [ " line " ] ) - 1 ) ;
2019-04-22 16:20:27 +00:00
emit_signal ( " set_execution " , stack_script , int ( d [ " line " ] ) - 1 ) ;
2017-06-25 09:20:01 +00:00
stack_script . unref ( ) ;
2014-02-13 21:03:28 +00:00
2018-02-21 11:28:26 +00:00
if ( connection . is_valid ( ) & & connection - > is_connected_to_host ( ) ) {
Array msg ;
msg . push_back ( " get_stack_frame_vars " ) ;
msg . push_back ( d [ " frame " ] ) ;
ppeer - > put_var ( msg ) ;
} else {
2021-05-04 14:00:45 +00:00
inspector - > edit ( nullptr ) ;
2018-02-21 11:28:26 +00:00
}
2014-02-13 21:03:28 +00:00
}
void ScriptEditorDebugger : : _output_clear ( ) {
//output->clear();
//output->push_color(Color(0,0,0));
}
2019-02-18 00:25:26 +00:00
void ScriptEditorDebugger : : _export_csv ( ) {
file_dialog - > set_mode ( EditorFileDialog : : MODE_SAVE_FILE ) ;
2020-01-24 11:18:00 +00:00
file_dialog - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
2020-03-17 11:49:31 +00:00
file_dialog - > clear_filters ( ) ;
file_dialog_mode = SAVE_MONITORS_CSV ;
2019-02-18 00:25:26 +00:00
file_dialog - > popup_centered_ratio ( ) ;
}
2017-03-05 15:44:50 +00:00
String ScriptEditorDebugger : : get_var_value ( const String & p_var ) const {
2021-05-05 10:44:11 +00:00
if ( ! breaked ) {
2014-02-13 21:03:28 +00:00
return String ( ) ;
2021-05-05 10:44:11 +00:00
}
2014-02-13 21:03:28 +00:00
return variables - > get_var_value ( p_var ) ;
}
2017-03-05 15:44:50 +00:00
int ScriptEditorDebugger : : _get_node_path_cache ( const NodePath & p_path ) {
2015-08-02 15:29:37 +00:00
const int * r = node_path_cache . getptr ( p_path ) ;
2021-05-05 10:44:11 +00:00
if ( r ) {
2015-08-02 15:29:37 +00:00
return * r ;
2021-05-05 10:44:11 +00:00
}
2015-08-02 15:29:37 +00:00
last_path_id + + ;
2017-03-05 15:44:50 +00:00
node_path_cache [ p_path ] = last_path_id ;
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_node_path " ) ;
msg . push_back ( p_path ) ;
msg . push_back ( last_path_id ) ;
ppeer - > put_var ( msg ) ;
return last_path_id ;
}
2017-03-05 15:44:50 +00:00
int ScriptEditorDebugger : : _get_res_path_cache ( const String & p_path ) {
Map < String , int > : : Element * E = res_path_cache . find ( p_path ) ;
2015-08-02 15:29:37 +00:00
2021-05-05 10:44:11 +00:00
if ( E ) {
2015-08-02 15:29:37 +00:00
return E - > get ( ) ;
2021-05-05 10:44:11 +00:00
}
2015-08-02 15:29:37 +00:00
last_path_id + + ;
2017-03-05 15:44:50 +00:00
res_path_cache [ p_path ] = last_path_id ;
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_res_path " ) ;
msg . push_back ( p_path ) ;
msg . push_back ( last_path_id ) ;
ppeer - > put_var ( msg ) ;
return last_path_id ;
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : _method_changed ( Object * p_base , const StringName & p_name , VARIANT_ARG_DECLARE ) {
2021-05-05 10:44:11 +00:00
if ( ! p_base | | ! live_debug | | ! connection . is_valid ( ) | | ! editor - > get_edited_scene ( ) ) {
2015-08-02 15:29:37 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2015-08-02 15:29:37 +00:00
2017-08-24 20:58:51 +00:00
Node * node = Object : : cast_to < Node > ( p_base ) ;
2015-08-02 15:29:37 +00:00
VARIANT_ARGPTRS
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
2015-08-02 15:29:37 +00:00
//no pointers, sorry
2021-05-05 10:44:11 +00:00
if ( argptr [ i ] & & ( argptr [ i ] - > get_type ( ) = = Variant : : OBJECT | | argptr [ i ] - > get_type ( ) = = Variant : : _RID ) ) {
2015-08-02 15:29:37 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2015-08-02 15:29:37 +00:00
}
if ( node ) {
NodePath path = editor - > get_edited_scene ( ) - > get_path_to ( node ) ;
int pathid = _get_node_path_cache ( path ) ;
Array msg ;
msg . push_back ( " live_node_call " ) ;
msg . push_back ( pathid ) ;
msg . push_back ( p_name ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
2015-08-02 15:29:37 +00:00
//no pointers, sorry
msg . push_back ( * argptr [ i ] ) ;
}
ppeer - > put_var ( msg ) ;
return ;
}
2017-08-24 20:58:51 +00:00
Resource * res = Object : : cast_to < Resource > ( p_base ) ;
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
if ( res & & res - > get_path ( ) ! = String ( ) ) {
2015-08-02 15:29:37 +00:00
String respath = res - > get_path ( ) ;
int pathid = _get_res_path_cache ( respath ) ;
Array msg ;
msg . push_back ( " live_res_call " ) ;
msg . push_back ( pathid ) ;
msg . push_back ( p_name ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
2015-08-02 15:29:37 +00:00
//no pointers, sorry
msg . push_back ( * argptr [ i ] ) ;
}
ppeer - > put_var ( msg ) ;
return ;
}
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : _property_changed ( Object * p_base , const StringName & p_property , const Variant & p_value ) {
2021-05-05 10:44:11 +00:00
if ( ! p_base | | ! live_debug | | ! connection . is_valid ( ) | | ! editor - > get_edited_scene ( ) ) {
2015-08-02 15:29:37 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2015-08-02 15:29:37 +00:00
2017-08-24 20:58:51 +00:00
Node * node = Object : : cast_to < Node > ( p_base ) ;
2015-08-02 15:29:37 +00:00
if ( node ) {
NodePath path = editor - > get_edited_scene ( ) - > get_path_to ( node ) ;
int pathid = _get_node_path_cache ( path ) ;
if ( p_value . is_ref ( ) ) {
Ref < Resource > res = p_value ;
2017-03-05 15:44:50 +00:00
if ( res . is_valid ( ) & & res - > get_path ( ) ! = String ( ) ) {
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_node_prop_res " ) ;
msg . push_back ( pathid ) ;
msg . push_back ( p_property ) ;
msg . push_back ( res - > get_path ( ) ) ;
ppeer - > put_var ( msg ) ;
}
} else {
Array msg ;
msg . push_back ( " live_node_prop " ) ;
msg . push_back ( pathid ) ;
msg . push_back ( p_property ) ;
msg . push_back ( p_value ) ;
ppeer - > put_var ( msg ) ;
}
return ;
}
2017-08-24 20:58:51 +00:00
Resource * res = Object : : cast_to < Resource > ( p_base ) ;
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
if ( res & & res - > get_path ( ) ! = String ( ) ) {
2015-08-02 15:29:37 +00:00
String respath = res - > get_path ( ) ;
int pathid = _get_res_path_cache ( respath ) ;
if ( p_value . is_ref ( ) ) {
2019-02-12 20:10:08 +00:00
Ref < Resource > res2 = p_value ;
if ( res2 . is_valid ( ) & & res2 - > get_path ( ) ! = String ( ) ) {
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_res_prop_res " ) ;
msg . push_back ( pathid ) ;
msg . push_back ( p_property ) ;
2019-02-12 20:10:08 +00:00
msg . push_back ( res2 - > get_path ( ) ) ;
2015-08-02 15:29:37 +00:00
ppeer - > put_var ( msg ) ;
}
} else {
Array msg ;
msg . push_back ( " live_res_prop " ) ;
msg . push_back ( pathid ) ;
msg . push_back ( p_property ) ;
msg . push_back ( p_value ) ;
ppeer - > put_var ( msg ) ;
}
return ;
}
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : _method_changeds ( void * p_ud , Object * p_base , const StringName & p_name , VARIANT_ARG_DECLARE ) {
ScriptEditorDebugger * sed = ( ScriptEditorDebugger * ) p_ud ;
sed - > _method_changed ( p_base , p_name , VARIANT_ARG_PASS ) ;
2015-08-02 15:29:37 +00:00
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : _property_changeds ( void * p_ud , Object * p_base , const StringName & p_property , const Variant & p_value ) {
ScriptEditorDebugger * sed = ( ScriptEditorDebugger * ) p_ud ;
sed - > _property_changed ( p_base , p_property , p_value ) ;
2015-08-02 15:29:37 +00:00
}
void ScriptEditorDebugger : : set_live_debugging ( bool p_enable ) {
2017-03-05 15:44:50 +00:00
live_debug = p_enable ;
2015-08-02 15:29:37 +00:00
}
void ScriptEditorDebugger : : _live_edit_set ( ) {
2021-05-05 10:44:11 +00:00
if ( ! connection . is_valid ( ) ) {
2015-08-02 15:29:37 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
TreeItem * ti = inspect_scene_tree - > get_selected ( ) ;
2021-05-05 10:44:11 +00:00
if ( ! ti ) {
2015-08-02 15:29:37 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2015-08-02 15:29:37 +00:00
String path ;
2017-03-05 15:44:50 +00:00
while ( ti ) {
String lp = ti - > get_text ( 0 ) ;
path = " / " + lp + path ;
ti = ti - > get_parent ( ) ;
2015-08-02 15:29:37 +00:00
}
NodePath np = path ;
editor - > get_editor_data ( ) . set_edited_scene_live_edit_root ( np ) ;
update_live_edit_root ( ) ;
}
void ScriptEditorDebugger : : _live_edit_clear ( ) {
NodePath np = NodePath ( " /root " ) ;
editor - > get_editor_data ( ) . set_edited_scene_live_edit_root ( np ) ;
update_live_edit_root ( ) ;
}
void ScriptEditorDebugger : : update_live_edit_root ( ) {
NodePath np = editor - > get_editor_data ( ) . get_edited_scene_live_edit_root ( ) ;
if ( connection . is_valid ( ) ) {
Array msg ;
msg . push_back ( " live_set_root " ) ;
msg . push_back ( np ) ;
2021-05-05 10:44:11 +00:00
if ( editor - > get_edited_scene ( ) ) {
2015-08-02 15:29:37 +00:00
msg . push_back ( editor - > get_edited_scene ( ) - > get_filename ( ) ) ;
2021-05-05 10:44:11 +00:00
} else {
2015-08-02 15:29:37 +00:00
msg . push_back ( " " ) ;
2021-05-05 10:44:11 +00:00
}
2015-08-02 15:29:37 +00:00
ppeer - > put_var ( msg ) ;
}
live_edit_root - > set_text ( np ) ;
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : live_debug_create_node ( const NodePath & p_parent , const String & p_type , const String & p_name ) {
2015-08-02 23:28:10 +00:00
if ( live_debug & & connection . is_valid ( ) ) {
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_create_node " ) ;
msg . push_back ( p_parent ) ;
msg . push_back ( p_type ) ;
msg . push_back ( p_name ) ;
ppeer - > put_var ( msg ) ;
}
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : live_debug_instance_node ( const NodePath & p_parent , const String & p_path , const String & p_name ) {
2015-08-02 23:28:10 +00:00
if ( live_debug & & connection . is_valid ( ) ) {
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_instance_node " ) ;
msg . push_back ( p_parent ) ;
msg . push_back ( p_path ) ;
msg . push_back ( p_name ) ;
ppeer - > put_var ( msg ) ;
}
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : live_debug_remove_node ( const NodePath & p_at ) {
2015-08-02 23:28:10 +00:00
if ( live_debug & & connection . is_valid ( ) ) {
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_remove_node " ) ;
msg . push_back ( p_at ) ;
ppeer - > put_var ( msg ) ;
}
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : live_debug_remove_and_keep_node ( const NodePath & p_at , ObjectID p_keep_id ) {
2015-08-02 23:28:10 +00:00
if ( live_debug & & connection . is_valid ( ) ) {
2015-08-02 15:29:37 +00:00
Array msg ;
2015-08-02 23:28:10 +00:00
msg . push_back ( " live_remove_and_keep_node " ) ;
2015-08-02 15:29:37 +00:00
msg . push_back ( p_at ) ;
msg . push_back ( p_keep_id ) ;
ppeer - > put_var ( msg ) ;
}
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : live_debug_restore_node ( ObjectID p_id , const NodePath & p_at , int p_at_pos ) {
2015-08-02 23:28:10 +00:00
if ( live_debug & & connection . is_valid ( ) ) {
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_restore_node " ) ;
msg . push_back ( p_id ) ;
msg . push_back ( p_at ) ;
msg . push_back ( p_at_pos ) ;
ppeer - > put_var ( msg ) ;
}
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : live_debug_duplicate_node ( const NodePath & p_at , const String & p_new_name ) {
2015-08-02 23:28:10 +00:00
if ( live_debug & & connection . is_valid ( ) ) {
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_duplicate_node " ) ;
msg . push_back ( p_at ) ;
msg . push_back ( p_new_name ) ;
ppeer - > put_var ( msg ) ;
}
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : live_debug_reparent_node ( const NodePath & p_at , const NodePath & p_new_place , const String & p_new_name , int p_at_pos ) {
2015-08-02 23:28:10 +00:00
if ( live_debug & & connection . is_valid ( ) ) {
2015-08-02 15:29:37 +00:00
Array msg ;
msg . push_back ( " live_reparent_node " ) ;
msg . push_back ( p_at ) ;
msg . push_back ( p_new_place ) ;
msg . push_back ( p_new_name ) ;
2015-08-02 23:28:10 +00:00
msg . push_back ( p_at_pos ) ;
2015-08-02 15:29:37 +00:00
ppeer - > put_var ( msg ) ;
}
}
2019-04-06 20:55:01 +00:00
ScriptEditorDebugger : : CameraOverride ScriptEditorDebugger : : get_camera_override ( ) const {
return camera_override ;
}
void ScriptEditorDebugger : : set_camera_override ( CameraOverride p_override ) {
if ( p_override = = OVERRIDE_2D & & camera_override ! = OVERRIDE_2D ) {
if ( connection . is_valid ( ) ) {
Array msg ;
msg . push_back ( " override_camera_2D:set " ) ;
msg . push_back ( true ) ;
ppeer - > put_var ( msg ) ;
}
} else if ( p_override ! = OVERRIDE_2D & & camera_override = = OVERRIDE_2D ) {
if ( connection . is_valid ( ) ) {
Array msg ;
msg . push_back ( " override_camera_2D:set " ) ;
msg . push_back ( false ) ;
ppeer - > put_var ( msg ) ;
}
} else if ( p_override > = OVERRIDE_3D_1 & & camera_override < OVERRIDE_3D_1 ) {
if ( connection . is_valid ( ) ) {
Array msg ;
msg . push_back ( " override_camera_3D:set " ) ;
msg . push_back ( true ) ;
ppeer - > put_var ( msg ) ;
}
} else if ( p_override < OVERRIDE_3D_1 & & camera_override > = OVERRIDE_3D_1 ) {
if ( connection . is_valid ( ) ) {
Array msg ;
msg . push_back ( " override_camera_3D:set " ) ;
msg . push_back ( false ) ;
ppeer - > put_var ( msg ) ;
}
}
camera_override = p_override ;
}
2017-03-05 15:44:50 +00:00
void ScriptEditorDebugger : : set_breakpoint ( const String & p_path , int p_line , bool p_enabled ) {
2015-08-04 23:17:13 +00:00
if ( connection . is_valid ( ) ) {
2017-03-05 15:44:50 +00:00
Array msg ;
msg . push_back ( " breakpoint " ) ;
msg . push_back ( p_path ) ;
msg . push_back ( p_line ) ;
msg . push_back ( p_enabled ) ;
ppeer - > put_var ( msg ) ;
}
2015-08-04 23:17:13 +00:00
}
2016-06-01 23:22:02 +00:00
void ScriptEditorDebugger : : reload_scripts ( ) {
if ( connection . is_valid ( ) ) {
2017-03-05 15:44:50 +00:00
Array msg ;
msg . push_back ( " reload_scripts " ) ;
ppeer - > put_var ( msg ) ;
}
2016-06-01 23:22:02 +00:00
}
2019-07-29 18:09:22 +00:00
bool ScriptEditorDebugger : : is_skip_breakpoints ( ) {
return skip_breakpoints_value ;
}
2018-09-08 23:31:49 +00:00
void ScriptEditorDebugger : : _error_activated ( ) {
TreeItem * selected = error_tree - > get_selected ( ) ;
2015-08-04 12:47:32 +00:00
2018-09-08 23:31:49 +00:00
TreeItem * ci = selected - > get_children ( ) ;
if ( ci ) {
selected - > set_collapsed ( ! selected - > is_collapsed ( ) ) ;
2015-08-04 12:47:32 +00:00
}
}
2018-09-08 23:31:49 +00:00
void ScriptEditorDebugger : : _error_selected ( ) {
TreeItem * selected = error_tree - > get_selected ( ) ;
2015-08-04 12:47:32 +00:00
2018-09-08 23:31:49 +00:00
Array meta = selected - > get_metadata ( 0 ) ;
if ( meta . size ( ) = = 0 ) {
2015-08-04 12:47:32 +00:00
return ;
2018-09-08 23:31:49 +00:00
}
2015-08-04 12:47:32 +00:00
2018-09-08 23:31:49 +00:00
Ref < Script > s = ResourceLoader : : load ( meta [ 0 ] ) ;
emit_signal ( " goto_script_line " , s , int ( meta [ 1 ] ) - 1 ) ;
2015-08-04 12:47:32 +00:00
}
2018-09-13 02:53:10 +00:00
void ScriptEditorDebugger : : _expand_errors_list ( ) {
TreeItem * root = error_tree - > get_root ( ) ;
2021-05-05 10:44:11 +00:00
if ( ! root ) {
2018-09-13 02:53:10 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2018-09-13 02:53:10 +00:00
TreeItem * item = root - > get_children ( ) ;
while ( item ) {
item - > set_collapsed ( false ) ;
item = item - > get_next ( ) ;
}
}
void ScriptEditorDebugger : : _collapse_errors_list ( ) {
TreeItem * root = error_tree - > get_root ( ) ;
2021-05-05 10:44:11 +00:00
if ( ! root ) {
2018-09-13 02:53:10 +00:00
return ;
2021-05-05 10:44:11 +00:00
}
2018-09-13 02:53:10 +00:00
TreeItem * item = root - > get_children ( ) ;
while ( item ) {
item - > set_collapsed ( true ) ;
item = item - > get_next ( ) ;
}
}
2015-12-12 13:09:50 +00:00
void ScriptEditorDebugger : : set_hide_on_stop ( bool p_hide ) {
2017-03-05 15:44:50 +00:00
hide_on_stop = p_hide ;
2015-12-12 13:09:50 +00:00
}
2015-08-02 15:29:37 +00:00
2017-06-25 09:20:01 +00:00
bool ScriptEditorDebugger : : get_debug_with_external_editor ( ) const {
return enable_external_editor ;
}
2020-03-15 10:45:39 +00:00
String ScriptEditorDebugger : : get_connection_string ( ) const {
String remote_host = EditorSettings : : get_singleton ( ) - > get ( " network/debug/remote_host " ) ;
return remote_port ? remote_host + " : " + itos ( remote_port ) : " " ;
}
2017-06-25 09:20:01 +00:00
void ScriptEditorDebugger : : set_debug_with_external_editor ( bool p_enabled ) {
enable_external_editor = p_enabled ;
}
Ref < Script > ScriptEditorDebugger : : get_dump_stack_script ( ) const {
return stack_script ;
}
2016-05-22 00:18:16 +00:00
void ScriptEditorDebugger : : _paused ( ) {
ERR_FAIL_COND ( connection . is_null ( ) ) ;
2017-01-14 14:07:57 +00:00
ERR_FAIL_COND ( ! connection - > is_connected_to_host ( ) ) ;
2016-05-22 00:18:16 +00:00
if ( ! breaked & & EditorNode : : get_singleton ( ) - > get_pause_button ( ) - > is_pressed ( ) ) {
debug_break ( ) ;
}
if ( breaked & & ! EditorNode : : get_singleton ( ) - > get_pause_button ( ) - > is_pressed ( ) ) {
debug_continue ( ) ;
}
}
2017-10-17 14:37:25 +00:00
void ScriptEditorDebugger : : _set_remote_object ( ObjectID p_id , ScriptEditorDebuggerInspectedObject * p_obj ) {
2021-05-05 10:44:11 +00:00
if ( remote_objects . has ( p_id ) ) {
2017-10-17 14:37:25 +00:00
memdelete ( remote_objects [ p_id ] ) ;
2021-05-05 10:44:11 +00:00
}
2017-10-17 14:37:25 +00:00
remote_objects [ p_id ] = p_obj ;
}
void ScriptEditorDebugger : : _clear_remote_objects ( ) {
for ( Map < ObjectID , ScriptEditorDebuggerInspectedObject * > : : Element * E = remote_objects . front ( ) ; E ; E = E - > next ( ) ) {
2017-11-16 09:18:36 +00:00
if ( editor - > get_editor_history ( ) - > get_current ( ) = = E - > value ( ) - > get_instance_id ( ) ) {
2021-05-04 14:00:45 +00:00
editor - > push_item ( nullptr ) ;
2017-11-16 09:18:36 +00:00
}
2017-10-17 14:37:25 +00:00
memdelete ( E - > value ( ) ) ;
}
remote_objects . clear ( ) ;
2020-05-22 19:50:16 +00:00
remote_dependencies . clear ( ) ;
2017-10-17 14:37:25 +00:00
}
2017-12-17 22:16:11 +00:00
void ScriptEditorDebugger : : _clear_errors_list ( ) {
2018-09-08 23:31:49 +00:00
error_tree - > clear ( ) ;
2017-12-17 22:16:11 +00:00
error_count = 0 ;
2018-08-16 05:41:03 +00:00
warning_count = 0 ;
2017-12-17 22:16:11 +00:00
_notification ( NOTIFICATION_PROCESS ) ;
}
// Right click on specific file(s) or folder(s).
2018-09-08 23:31:49 +00:00
void ScriptEditorDebugger : : _error_tree_item_rmb_selected ( const Vector2 & p_pos ) {
2017-12-17 22:16:11 +00:00
item_menu - > clear ( ) ;
item_menu - > set_size ( Size2 ( 1 , 1 ) ) ;
2018-09-08 23:31:49 +00:00
if ( error_tree - > is_anything_selected ( ) ) {
2018-02-20 17:25:17 +00:00
item_menu - > add_icon_item ( get_icon ( " ActionCopy " , " EditorIcons " ) , TTR ( " Copy Error " ) , ITEM_MENU_COPY_ERROR ) ;
2022-04-24 15:21:14 +00:00
item_menu - > add_icon_item ( get_icon ( " ExternalLink " , " EditorIcons " ) , TTR ( " Open C++ Source on GitHub " ) , ITEM_MENU_OPEN_SOURCE ) ;
2017-12-17 22:16:11 +00:00
}
if ( item_menu - > get_item_count ( ) > 0 ) {
2018-09-08 23:31:49 +00:00
item_menu - > set_position ( error_tree - > get_global_position ( ) + p_pos ) ;
2017-12-17 22:16:11 +00:00
item_menu - > popup ( ) ;
}
}
void ScriptEditorDebugger : : _item_menu_id_pressed ( int p_option ) {
switch ( p_option ) {
case ITEM_MENU_COPY_ERROR : {
2018-09-08 23:31:49 +00:00
TreeItem * ti = error_tree - > get_selected ( ) ;
2021-05-05 10:44:11 +00:00
while ( ti - > get_parent ( ) ! = error_tree - > get_root ( ) ) {
2018-09-08 23:31:49 +00:00
ti = ti - > get_parent ( ) ;
2021-05-05 10:44:11 +00:00
}
2018-09-08 23:31:49 +00:00
String type ;
if ( ti - > get_icon ( 0 ) = = get_icon ( " Warning " , " EditorIcons " ) ) {
type = " W " ;
} else if ( ti - > get_icon ( 0 ) = = get_icon ( " Error " , " EditorIcons " ) ) {
type = " E " ;
}
String text = ti - > get_text ( 0 ) + " " ;
int rpad_len = text . length ( ) ;
text = type + text + ti - > get_text ( 1 ) + " \n " ;
TreeItem * ci = ti - > get_children ( ) ;
while ( ci ) {
text + = " " + ci - > get_text ( 0 ) . rpad ( rpad_len ) + ci - > get_text ( 1 ) + " \n " ;
ci = ci - > get_next ( ) ;
}
OS : : get_singleton ( ) - > set_clipboard ( text ) ;
2017-12-17 22:16:11 +00:00
} break ;
2018-02-21 15:07:49 +00:00
case ITEM_MENU_SAVE_REMOTE_NODE : {
file_dialog - > set_access ( EditorFileDialog : : ACCESS_RESOURCES ) ;
file_dialog - > set_mode ( EditorFileDialog : : MODE_SAVE_FILE ) ;
2019-02-18 00:25:26 +00:00
file_dialog_mode = SAVE_NODE ;
2018-02-21 15:07:49 +00:00
List < String > extensions ;
Ref < PackedScene > sd = memnew ( PackedScene ) ;
ResourceSaver : : get_recognized_extensions ( sd , & extensions ) ;
file_dialog - > clear_filters ( ) ;
for ( int i = 0 ; i < extensions . size ( ) ; i + + ) {
file_dialog - > add_filter ( " *. " + extensions [ i ] + " ; " + extensions [ i ] . to_upper ( ) ) ;
}
file_dialog - > popup_centered_ratio ( ) ;
} break ;
2019-05-05 07:59:10 +00:00
case ITEM_MENU_COPY_NODE_PATH : {
TreeItem * ti = inspect_scene_tree - > get_selected ( ) ;
String text = ti - > get_text ( 0 ) ;
2021-05-04 14:00:45 +00:00
if ( ti - > get_parent ( ) = = nullptr ) {
2019-05-05 07:59:10 +00:00
text = " . " ;
2021-05-04 14:00:45 +00:00
} else if ( ti - > get_parent ( ) - > get_parent ( ) = = nullptr ) {
2019-05-05 07:59:10 +00:00
text = " . " ;
} else {
while ( ti - > get_parent ( ) - > get_parent ( ) ! = inspect_scene_tree - > get_root ( ) ) {
ti = ti - > get_parent ( ) ;
text = ti - > get_text ( 0 ) + " / " + text ;
}
}
OS : : get_singleton ( ) - > set_clipboard ( text ) ;
} break ;
2021-04-18 00:07:05 +00:00
case ITEM_MENU_OPEN_SOURCE : {
TreeItem * ti = error_tree - > get_selected ( ) ;
while ( ti - > get_parent ( ) ! = error_tree - > get_root ( ) ) {
ti = ti - > get_parent ( ) ;
}
2022-10-06 09:45:27 +00:00
// Find the child with the "C++ Source".
// It's not at a fixed position as "C++ Error" may come first.
2021-04-18 00:07:05 +00:00
TreeItem * ci = ti - > get_children ( ) ;
2022-10-06 09:45:27 +00:00
const String cpp_source = " < " + TTR ( " C++ Source " ) + " > " ;
while ( ci ) {
if ( ci - > get_text ( 0 ) = = cpp_source ) {
break ;
}
ci = ci - > get_next ( ) ;
}
if ( ! ci ) {
WARN_PRINT ( " No C++ source reference is available for this error. " ) ;
return ;
}
2021-04-18 00:07:05 +00:00
// Parse back the `file:line @ method()` string.
const Vector < String > file_line_number = ci - > get_text ( 1 ) . split ( " @ " ) [ 0 ] . strip_edges ( ) . split ( " : " ) ;
ERR_FAIL_COND_MSG ( file_line_number . size ( ) < 2 , " Incorrect C++ source stack trace file:line format (please report). " ) ;
const String file = file_line_number [ 0 ] ;
const int line_number = file_line_number [ 1 ] . to_int ( ) ;
// Construct a GitHub repository URL and open it in the user's default web browser.
2022-02-08 19:50:37 +00:00
// If the commit hash is available, use it for greater accuracy. Otherwise fall back to tagged release.
String git_ref = String ( VERSION_HASH ) . empty ( ) ? String ( VERSION_NUMBER ) + " -stable " : String ( VERSION_HASH ) ;
OS : : get_singleton ( ) - > shell_open ( vformat ( " https://github.com/godotengine/godot/blob/%s/%s#L%d " ,
git_ref , file , line_number ) ) ;
2021-04-18 00:07:05 +00:00
} break ;
2017-12-17 22:16:11 +00:00
}
}
2019-11-28 15:37:15 +00:00
void ScriptEditorDebugger : : _tab_changed ( int p_tab ) {
if ( tabs - > get_tab_title ( p_tab ) = = TTR ( " Video RAM " ) ) {
2020-09-18 12:09:51 +00:00
// "Video RAM" tab was clicked, refresh the data it's displaying when entering the tab.
2019-11-28 15:37:15 +00:00
_video_mem_request ( ) ;
}
}
2014-02-13 21:03:28 +00:00
void ScriptEditorDebugger : : _bind_methods ( ) {
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _stack_dump_frame_selected " ) , & ScriptEditorDebugger : : _stack_dump_frame_selected ) ;
2018-02-13 16:46:45 +00:00
2019-07-29 18:09:22 +00:00
ClassDB : : bind_method ( D_METHOD ( " debug_skip_breakpoints " ) , & ScriptEditorDebugger : : debug_skip_breakpoints ) ;
2018-02-13 16:46:45 +00:00
ClassDB : : bind_method ( D_METHOD ( " debug_copy " ) , & ScriptEditorDebugger : : debug_copy ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " debug_next " ) , & ScriptEditorDebugger : : debug_next ) ;
ClassDB : : bind_method ( D_METHOD ( " debug_step " ) , & ScriptEditorDebugger : : debug_step ) ;
ClassDB : : bind_method ( D_METHOD ( " debug_break " ) , & ScriptEditorDebugger : : debug_break ) ;
ClassDB : : bind_method ( D_METHOD ( " debug_continue " ) , & ScriptEditorDebugger : : debug_continue ) ;
ClassDB : : bind_method ( D_METHOD ( " _output_clear " ) , & ScriptEditorDebugger : : _output_clear ) ;
2019-02-18 00:25:26 +00:00
ClassDB : : bind_method ( D_METHOD ( " _export_csv " ) , & ScriptEditorDebugger : : _export_csv ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _performance_draw " ) , & ScriptEditorDebugger : : _performance_draw ) ;
ClassDB : : bind_method ( D_METHOD ( " _performance_select " ) , & ScriptEditorDebugger : : _performance_select ) ;
ClassDB : : bind_method ( D_METHOD ( " _scene_tree_request " ) , & ScriptEditorDebugger : : _scene_tree_request ) ;
ClassDB : : bind_method ( D_METHOD ( " _video_mem_request " ) , & ScriptEditorDebugger : : _video_mem_request ) ;
2020-03-17 11:49:31 +00:00
ClassDB : : bind_method ( D_METHOD ( " _video_mem_export " ) , & ScriptEditorDebugger : : _video_mem_export ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _live_edit_set " ) , & ScriptEditorDebugger : : _live_edit_set ) ;
ClassDB : : bind_method ( D_METHOD ( " _live_edit_clear " ) , & ScriptEditorDebugger : : _live_edit_clear ) ;
ClassDB : : bind_method ( D_METHOD ( " _error_selected " ) , & ScriptEditorDebugger : : _error_selected ) ;
2018-09-08 23:31:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " _error_activated " ) , & ScriptEditorDebugger : : _error_activated ) ;
2018-09-13 02:53:10 +00:00
ClassDB : : bind_method ( D_METHOD ( " _expand_errors_list " ) , & ScriptEditorDebugger : : _expand_errors_list ) ;
ClassDB : : bind_method ( D_METHOD ( " _collapse_errors_list " ) , & ScriptEditorDebugger : : _collapse_errors_list ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _profiler_activate " ) , & ScriptEditorDebugger : : _profiler_activate ) ;
2019-09-01 16:38:58 +00:00
ClassDB : : bind_method ( D_METHOD ( " _network_profiler_activate " ) , & ScriptEditorDebugger : : _network_profiler_activate ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _profiler_seeked " ) , & ScriptEditorDebugger : : _profiler_seeked ) ;
2017-12-17 22:16:11 +00:00
ClassDB : : bind_method ( D_METHOD ( " _clear_errors_list " ) , & ScriptEditorDebugger : : _clear_errors_list ) ;
2018-09-08 23:31:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " _error_tree_item_rmb_selected " ) , & ScriptEditorDebugger : : _error_tree_item_rmb_selected ) ;
2017-12-17 22:16:11 +00:00
ClassDB : : bind_method ( D_METHOD ( " _item_menu_id_pressed " ) , & ScriptEditorDebugger : : _item_menu_id_pressed ) ;
2019-11-28 15:37:15 +00:00
ClassDB : : bind_method ( D_METHOD ( " _tab_changed " ) , & ScriptEditorDebugger : : _tab_changed ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _paused " ) , & ScriptEditorDebugger : : _paused ) ;
ClassDB : : bind_method ( D_METHOD ( " _scene_tree_selected " ) , & ScriptEditorDebugger : : _scene_tree_selected ) ;
ClassDB : : bind_method ( D_METHOD ( " _scene_tree_folded " ) , & ScriptEditorDebugger : : _scene_tree_folded ) ;
2018-02-21 15:07:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " _scene_tree_rmb_selected " ) , & ScriptEditorDebugger : : _scene_tree_rmb_selected ) ;
ClassDB : : bind_method ( D_METHOD ( " _file_selected " ) , & ScriptEditorDebugger : : _file_selected ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " live_debug_create_node " ) , & ScriptEditorDebugger : : live_debug_create_node ) ;
ClassDB : : bind_method ( D_METHOD ( " live_debug_instance_node " ) , & ScriptEditorDebugger : : live_debug_instance_node ) ;
ClassDB : : bind_method ( D_METHOD ( " live_debug_remove_node " ) , & ScriptEditorDebugger : : live_debug_remove_node ) ;
ClassDB : : bind_method ( D_METHOD ( " live_debug_remove_and_keep_node " ) , & ScriptEditorDebugger : : live_debug_remove_and_keep_node ) ;
ClassDB : : bind_method ( D_METHOD ( " live_debug_restore_node " ) , & ScriptEditorDebugger : : live_debug_restore_node ) ;
ClassDB : : bind_method ( D_METHOD ( " live_debug_duplicate_node " ) , & ScriptEditorDebugger : : live_debug_duplicate_node ) ;
ClassDB : : bind_method ( D_METHOD ( " live_debug_reparent_node " ) , & ScriptEditorDebugger : : live_debug_reparent_node ) ;
ClassDB : : bind_method ( D_METHOD ( " _scene_tree_property_select_object " ) , & ScriptEditorDebugger : : _scene_tree_property_select_object ) ;
ClassDB : : bind_method ( D_METHOD ( " _scene_tree_property_value_edited " ) , & ScriptEditorDebugger : : _scene_tree_property_value_edited ) ;
2014-02-13 21:03:28 +00:00
ADD_SIGNAL ( MethodInfo ( " goto_script_line " ) ) ;
2019-04-22 16:20:27 +00:00
ADD_SIGNAL ( MethodInfo ( " set_execution " , PropertyInfo ( " script " ) , PropertyInfo ( Variant : : INT , " line " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " clear_execution " , PropertyInfo ( " script " ) ) ) ;
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " breaked " , PropertyInfo ( Variant : : BOOL , " reallydid " ) , PropertyInfo ( Variant : : BOOL , " can_debug " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " show_debugger " , PropertyInfo ( Variant : : BOOL , " reallydid " ) ) ) ;
2014-02-13 21:03:28 +00:00
}
2017-03-05 15:44:50 +00:00
ScriptEditorDebugger : : ScriptEditorDebugger ( EditorNode * p_editor ) {
2019-11-18 08:42:28 +00:00
add_constant_override ( " margin_left " , - EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_stylebox ( " BottomPanelDebuggerOverride " , " EditorStyles " ) - > get_margin ( MARGIN_LEFT ) ) ;
add_constant_override ( " margin_right " , - EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_stylebox ( " BottomPanelDebuggerOverride " , " EditorStyles " ) - > get_margin ( MARGIN_RIGHT ) ) ;
2017-03-05 15:44:50 +00:00
ppeer = Ref < PacketPeerStream > ( memnew ( PacketPeerStream ) ) ;
2019-12-21 15:45:55 +00:00
ppeer - > set_input_buffer_max_size ( ( 1024 * 1024 * 8 ) - 4 ) ; // 8 MiB should be enough, minus 4 bytes for separator.
2017-03-05 15:44:50 +00:00
editor = p_editor ;
2018-05-15 20:12:35 +00:00
editor - > get_inspector ( ) - > connect ( " object_id_selected " , this , " _scene_tree_property_select_object " ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
tabs = memnew ( TabContainer ) ;
2017-05-02 20:13:12 +00:00
tabs - > set_tab_align ( TabContainer : : ALIGN_LEFT ) ;
tabs - > add_style_override ( " panel " , editor - > get_gui_base ( ) - > get_stylebox ( " DebuggerPanel " , " EditorStyles " ) ) ;
tabs - > add_style_override ( " tab_fg " , editor - > get_gui_base ( ) - > get_stylebox ( " DebuggerTabFG " , " EditorStyles " ) ) ;
tabs - > add_style_override ( " tab_bg " , editor - > get_gui_base ( ) - > get_stylebox ( " DebuggerTabBG " , " EditorStyles " ) ) ;
2019-11-28 15:37:15 +00:00
tabs - > connect ( " tab_changed " , this , " _tab_changed " ) ;
2017-09-18 19:06:55 +00:00
2014-02-13 21:03:28 +00:00
add_child ( tabs ) ;
2016-05-22 22:28:37 +00:00
{ //debugger
2017-03-05 15:44:50 +00:00
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
2016-05-22 22:28:37 +00:00
vbc - > set_name ( TTR ( " Debugger " ) ) ;
2017-03-05 15:44:50 +00:00
Control * dbg = vbc ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
HBoxContainer * hbc = memnew ( HBoxContainer ) ;
2016-05-22 22:28:37 +00:00
vbc - > add_child ( hbc ) ;
2014-02-13 21:03:28 +00:00
2017-08-08 02:55:24 +00:00
reason = memnew ( Label ) ;
2016-05-22 22:28:37 +00:00
reason - > set_text ( " " ) ;
hbc - > add_child ( reason ) ;
reason - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2018-05-26 11:50:46 +00:00
reason - > set_autowrap ( true ) ;
reason - > set_max_lines_visible ( 3 ) ;
reason - > set_mouse_filter ( Control : : MOUSE_FILTER_PASS ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
hbc - > add_child ( memnew ( VSeparator ) ) ;
2019-07-29 18:09:22 +00:00
skip_breakpoints = memnew ( ToolButton ) ;
hbc - > add_child ( skip_breakpoints ) ;
skip_breakpoints - > set_tooltip ( TTR ( " Skip Breakpoints " ) ) ;
skip_breakpoints - > connect ( " pressed " , this , " debug_skip_breakpoints " ) ;
hbc - > add_child ( memnew ( VSeparator ) ) ;
2014-02-13 21:03:28 +00:00
2018-02-13 16:46:45 +00:00
copy = memnew ( ToolButton ) ;
hbc - > add_child ( copy ) ;
copy - > set_tooltip ( TTR ( " Copy Error " ) ) ;
copy - > connect ( " pressed " , this , " debug_copy " ) ;
hbc - > add_child ( memnew ( VSeparator ) ) ;
2017-07-18 16:03:06 +00:00
step = memnew ( ToolButton ) ;
2016-05-22 22:28:37 +00:00
hbc - > add_child ( step ) ;
step - > set_tooltip ( TTR ( " Step Into " ) ) ;
2019-09-22 17:19:53 +00:00
step - > set_shortcut ( ED_GET_SHORTCUT ( " debugger/step_into " ) ) ;
2017-03-05 15:44:50 +00:00
step - > connect ( " pressed " , this , " debug_step " ) ;
2014-02-13 21:03:28 +00:00
2017-07-18 16:03:06 +00:00
next = memnew ( ToolButton ) ;
2016-05-22 22:28:37 +00:00
hbc - > add_child ( next ) ;
next - > set_tooltip ( TTR ( " Step Over " ) ) ;
2019-09-22 17:19:53 +00:00
next - > set_shortcut ( ED_GET_SHORTCUT ( " debugger/step_over " ) ) ;
2017-03-05 15:44:50 +00:00
next - > connect ( " pressed " , this , " debug_next " ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
hbc - > add_child ( memnew ( VSeparator ) ) ;
2014-02-13 21:03:28 +00:00
2017-07-18 16:03:06 +00:00
dobreak = memnew ( ToolButton ) ;
2016-05-22 22:28:37 +00:00
hbc - > add_child ( dobreak ) ;
dobreak - > set_tooltip ( TTR ( " Break " ) ) ;
2019-09-22 17:19:53 +00:00
dobreak - > set_shortcut ( ED_GET_SHORTCUT ( " debugger/break " ) ) ;
2017-03-05 15:44:50 +00:00
dobreak - > connect ( " pressed " , this , " debug_break " ) ;
2014-02-13 21:03:28 +00:00
2017-07-18 16:03:06 +00:00
docontinue = memnew ( ToolButton ) ;
2016-05-22 22:28:37 +00:00
hbc - > add_child ( docontinue ) ;
docontinue - > set_tooltip ( TTR ( " Continue " ) ) ;
2019-09-22 17:19:53 +00:00
docontinue - > set_shortcut ( ED_GET_SHORTCUT ( " debugger/continue " ) ) ;
2017-03-05 15:44:50 +00:00
docontinue - > connect ( " pressed " , this , " debug_continue " ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
back = memnew ( Button ) ;
2016-05-22 22:28:37 +00:00
hbc - > add_child ( back ) ;
back - > set_tooltip ( TTR ( " Inspect Previous Instance " ) ) ;
2016-06-12 00:40:51 +00:00
back - > hide ( ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
forward = memnew ( Button ) ;
2016-05-22 22:28:37 +00:00
hbc - > add_child ( forward ) ;
forward - > set_tooltip ( TTR ( " Inspect Next Instance " ) ) ;
2016-06-12 00:40:51 +00:00
forward - > hide ( ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
HSplitContainer * sc = memnew ( HSplitContainer ) ;
2016-05-22 22:28:37 +00:00
vbc - > add_child ( sc ) ;
sc - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
stack_dump = memnew ( Tree ) ;
2018-02-20 02:35:52 +00:00
stack_dump - > set_allow_reselect ( true ) ;
2016-05-22 22:28:37 +00:00
stack_dump - > set_columns ( 1 ) ;
stack_dump - > set_column_titles_visible ( true ) ;
2017-03-05 15:44:50 +00:00
stack_dump - > set_column_title ( 0 , TTR ( " Stack Frames " ) ) ;
2016-05-22 22:28:37 +00:00
stack_dump - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
stack_dump - > set_hide_root ( true ) ;
2017-03-05 15:44:50 +00:00
stack_dump - > connect ( " cell_selected " , this , " _stack_dump_frame_selected " ) ;
2016-05-22 22:28:37 +00:00
sc - > add_child ( stack_dump ) ;
2014-02-13 21:03:28 +00:00
2022-03-07 10:57:30 +00:00
VBoxContainer * inspector_vbox = memnew ( VBoxContainer ) ;
sc - > add_child ( inspector_vbox ) ;
HBoxContainer * tools_hb = memnew ( HBoxContainer ) ;
inspector_vbox - > add_child ( tools_hb ) ;
search = memnew ( LineEdit ) ;
search - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
search - > set_placeholder ( TTR ( " Filter stack variables " ) ) ;
search - > set_clear_button_enabled ( true ) ;
tools_hb - > add_child ( search ) ;
2018-09-11 13:53:50 +00:00
inspector = memnew ( EditorInspector ) ;
2016-05-22 22:28:37 +00:00
inspector - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2022-03-07 10:57:30 +00:00
inspector - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2022-03-19 11:04:49 +00:00
inspector - > set_property_name_style ( EditorPropertyNameProcessor : : STYLE_RAW ) ;
2016-05-22 22:28:37 +00:00
inspector - > set_read_only ( true ) ;
2017-05-01 17:27:01 +00:00
inspector - > connect ( " object_id_selected " , this , " _scene_tree_property_select_object " ) ;
2022-03-07 10:57:30 +00:00
inspector - > register_text_enter ( search ) ;
inspector - > set_use_filter ( true ) ;
inspector_vbox - > add_child ( inspector ) ;
2014-02-13 21:03:28 +00:00
2018-09-02 04:36:45 +00:00
server . instance ( ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
pending_in_queue = 0 ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
variables = memnew ( ScriptEditorDebuggerVariables ) ;
2014-02-13 21:03:28 +00:00
2017-03-05 15:44:50 +00:00
breaked = false ;
2016-05-22 22:28:37 +00:00
tabs - > add_child ( dbg ) ;
}
2017-03-05 15:44:50 +00:00
{ //errors
2019-02-28 21:12:14 +00:00
errors_tab = memnew ( VBoxContainer ) ;
errors_tab - > set_name ( TTR ( " Errors " ) ) ;
2018-09-13 02:53:10 +00:00
2017-12-17 22:16:11 +00:00
HBoxContainer * errhb = memnew ( HBoxContainer ) ;
2019-02-28 21:12:14 +00:00
errors_tab - > add_child ( errhb ) ;
2018-09-13 02:53:10 +00:00
Button * expand_all = memnew ( Button ) ;
expand_all - > set_text ( TTR ( " Expand All " ) ) ;
expand_all - > connect ( " pressed " , this , " _expand_errors_list " ) ;
errhb - > add_child ( expand_all ) ;
Button * collapse_all = memnew ( Button ) ;
collapse_all - > set_text ( TTR ( " Collapse All " ) ) ;
collapse_all - > connect ( " pressed " , this , " _collapse_errors_list " ) ;
errhb - > add_child ( collapse_all ) ;
Control * space = memnew ( Control ) ;
space - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
errhb - > add_child ( space ) ;
clearbutton = memnew ( Button ) ;
clearbutton - > set_text ( TTR ( " Clear " ) ) ;
clearbutton - > set_h_size_flags ( 0 ) ;
clearbutton - > connect ( " pressed " , this , " _clear_errors_list " ) ;
errhb - > add_child ( clearbutton ) ;
2017-12-17 22:16:11 +00:00
2018-09-08 23:31:49 +00:00
error_tree = memnew ( Tree ) ;
error_tree - > set_columns ( 2 ) ;
2017-12-17 22:16:11 +00:00
2018-09-08 23:31:49 +00:00
error_tree - > set_column_expand ( 0 , false ) ;
error_tree - > set_column_min_width ( 0 , 140 ) ;
2017-12-17 22:16:11 +00:00
2018-09-08 23:31:49 +00:00
error_tree - > set_column_expand ( 1 , true ) ;
2017-12-17 22:16:11 +00:00
2018-09-08 23:31:49 +00:00
error_tree - > set_select_mode ( Tree : : SELECT_ROW ) ;
error_tree - > set_hide_root ( true ) ;
2018-09-13 02:53:10 +00:00
error_tree - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2018-09-08 23:31:49 +00:00
error_tree - > set_allow_rmb_select ( true ) ;
error_tree - > connect ( " item_rmb_selected " , this , " _error_tree_item_rmb_selected " ) ;
2019-02-28 21:12:14 +00:00
errors_tab - > add_child ( error_tree ) ;
2017-12-17 22:16:11 +00:00
2018-09-08 23:31:49 +00:00
item_menu = memnew ( PopupMenu ) ;
item_menu - > connect ( " id_pressed " , this , " _item_menu_id_pressed " ) ;
error_tree - > add_child ( item_menu ) ;
2016-05-22 22:28:37 +00:00
2019-02-28 21:12:14 +00:00
tabs - > add_child ( errors_tab ) ;
2016-05-22 22:28:37 +00:00
}
2017-11-16 09:18:36 +00:00
{ // remote scene tree
2016-05-22 22:28:37 +00:00
2017-03-05 15:44:50 +00:00
inspect_scene_tree = memnew ( Tree ) ;
2017-11-16 09:18:36 +00:00
EditorNode : : get_singleton ( ) - > get_scene_tree_dock ( ) - > add_remote_tree_editor ( inspect_scene_tree ) ;
2017-11-23 07:23:24 +00:00
EditorNode : : get_singleton ( ) - > get_scene_tree_dock ( ) - > connect ( " remote_tree_selected " , this , " _scene_tree_selected " ) ;
2017-11-16 09:18:36 +00:00
inspect_scene_tree - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2017-03-05 15:44:50 +00:00
inspect_scene_tree - > connect ( " cell_selected " , this , " _scene_tree_selected " ) ;
inspect_scene_tree - > connect ( " item_collapsed " , this , " _scene_tree_folded " ) ;
2018-02-21 15:07:49 +00:00
inspect_scene_tree - > set_allow_rmb_select ( true ) ;
inspect_scene_tree - > connect ( " item_rmb_selected " , this , " _scene_tree_rmb_selected " ) ;
2017-12-04 09:25:31 +00:00
auto_switch_remote_scene_tree = EDITOR_DEF ( " debugger/auto_switch_to_remote_scene_tree " , false ) ;
2017-11-22 13:50:54 +00:00
inspect_scene_tree_timeout = EDITOR_DEF ( " debugger/remote_scene_tree_refresh_interval " , 1.0 ) ;
2017-03-05 15:44:50 +00:00
inspect_edited_object_timeout = EDITOR_DEF ( " debugger/remote_inspect_refresh_interval " , 0.2 ) ;
inspected_object_id = 0 ;
updating_scene_tree = false ;
2014-02-13 21:03:28 +00:00
}
2018-02-21 15:07:49 +00:00
{ // File dialog
file_dialog = memnew ( EditorFileDialog ) ;
file_dialog - > connect ( " file_selected " , this , " _file_selected " ) ;
add_child ( file_dialog ) ;
}
2016-05-22 22:28:37 +00:00
{ //profiler
2017-03-05 15:44:50 +00:00
profiler = memnew ( EditorProfiler ) ;
2016-05-30 18:47:53 +00:00
profiler - > set_name ( TTR ( " Profiler " ) ) ;
2016-05-22 22:28:37 +00:00
tabs - > add_child ( profiler ) ;
2017-03-05 15:44:50 +00:00
profiler - > connect ( " enable_profiling " , this , " _profiler_activate " ) ;
profiler - > connect ( " break_request " , this , " _profiler_seeked " ) ;
2016-05-22 22:28:37 +00:00
}
2019-09-01 16:38:58 +00:00
{ //network profiler
network_profiler = memnew ( EditorNetworkProfiler ) ;
network_profiler - > set_name ( TTR ( " Network Profiler " ) ) ;
tabs - > add_child ( network_profiler ) ;
network_profiler - > connect ( " enable_profiling " , this , " _network_profiler_activate " ) ;
}
2016-05-22 22:28:37 +00:00
{ //monitors
2017-03-05 15:44:50 +00:00
HSplitContainer * hsp = memnew ( HSplitContainer ) ;
2016-05-22 22:28:37 +00:00
perf_monitors = memnew ( Tree ) ;
perf_monitors - > set_columns ( 2 ) ;
2017-03-05 15:44:50 +00:00
perf_monitors - > set_column_title ( 0 , TTR ( " Monitor " ) ) ;
perf_monitors - > set_column_title ( 1 , TTR ( " Value " ) ) ;
2016-05-22 22:28:37 +00:00
perf_monitors - > set_column_titles_visible ( true ) ;
2017-10-23 08:11:46 +00:00
perf_monitors - > connect ( " item_edited " , this , " _performance_select " ) ;
2019-09-04 05:20:57 +00:00
hsp - > add_child ( perf_monitors ) ;
2017-03-05 15:44:50 +00:00
perf_draw = memnew ( Control ) ;
2019-09-04 05:20:57 +00:00
perf_draw - > set_clip_contents ( true ) ;
2017-03-05 15:44:50 +00:00
perf_draw - > connect ( " draw " , this , " _performance_draw " ) ;
2016-05-22 22:28:37 +00:00
hsp - > add_child ( perf_draw ) ;
2019-09-04 05:20:57 +00:00
2016-05-30 18:47:53 +00:00
hsp - > set_name ( TTR ( " Monitors " ) ) ;
2017-10-23 08:11:46 +00:00
hsp - > set_split_offset ( 340 * EDSCALE ) ;
2016-05-22 22:28:37 +00:00
tabs - > add_child ( hsp ) ;
perf_max . resize ( Performance : : MONITOR_MAX ) ;
2017-03-05 15:44:50 +00:00
Map < String , TreeItem * > bases ;
TreeItem * root = perf_monitors - > create_item ( ) ;
2016-05-22 22:28:37 +00:00
perf_monitors - > set_hide_root ( true ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < Performance : : MONITOR_MAX ; i + + ) {
2016-05-22 22:28:37 +00:00
String n = Performance : : get_singleton ( ) - > get_monitor_name ( Performance : : Monitor ( i ) ) ;
2017-10-23 06:59:04 +00:00
Performance : : MonitorType mtype = Performance : : get_singleton ( ) - > get_monitor_type ( Performance : : Monitor ( i ) ) ;
2022-03-29 03:29:15 +00:00
String base = EditorPropertyNameProcessor : : get_singleton ( ) - > process_name ( n . get_slice ( " / " , 0 ) , EditorPropertyNameProcessor : : STYLE_CAPITALIZED ) ;
String name = EditorPropertyNameProcessor : : get_singleton ( ) - > process_name ( n . get_slice ( " / " , 1 ) , EditorPropertyNameProcessor : : STYLE_CAPITALIZED ) ;
2016-05-22 22:28:37 +00:00
if ( ! bases . has ( base ) ) {
TreeItem * b = perf_monitors - > create_item ( root ) ;
2017-03-05 15:44:50 +00:00
b - > set_text ( 0 , base . capitalize ( ) ) ;
b - > set_editable ( 0 , false ) ;
b - > set_selectable ( 0 , false ) ;
2017-10-23 08:11:46 +00:00
b - > set_expand_right ( 0 , true ) ;
2017-03-05 15:44:50 +00:00
bases [ base ] = b ;
2016-05-22 22:28:37 +00:00
}
TreeItem * it = perf_monitors - > create_item ( bases [ base ] ) ;
2017-10-23 06:59:04 +00:00
it - > set_metadata ( 1 , mtype ) ;
2017-10-23 08:11:46 +00:00
it - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
it - > set_editable ( 0 , true ) ;
it - > set_selectable ( 0 , false ) ;
it - > set_selectable ( 1 , false ) ;
2017-03-05 15:44:50 +00:00
it - > set_text ( 0 , name . capitalize ( ) ) ;
2016-05-22 22:28:37 +00:00
perf_items . push_back ( it ) ;
2018-07-25 01:11:03 +00:00
perf_max . write [ i ] = 0 ;
2016-05-22 22:28:37 +00:00
}
2019-09-04 05:20:57 +00:00
info_message = memnew ( Label ) ;
info_message - > set_text ( TTR ( " Pick one or more items from the list to display the graph. " ) ) ;
info_message - > set_valign ( Label : : VALIGN_CENTER ) ;
info_message - > set_align ( Label : : ALIGN_CENTER ) ;
info_message - > set_autowrap ( true ) ;
2019-11-04 09:12:15 +00:00
info_message - > set_custom_minimum_size ( Size2 ( 100 * EDSCALE , 0 ) ) ;
2019-09-04 05:20:57 +00:00
info_message - > set_anchors_and_margins_preset ( PRESET_WIDE , PRESET_MODE_KEEP_SIZE , 8 * EDSCALE ) ;
perf_draw - > add_child ( info_message ) ;
2016-05-22 22:28:37 +00:00
}
{ //vmem inspect
2017-03-05 15:44:50 +00:00
VBoxContainer * vmem_vb = memnew ( VBoxContainer ) ;
HBoxContainer * vmem_hb = memnew ( HBoxContainer ) ;
Label * vmlb = memnew ( Label ( TTR ( " List of Video Memory Usage by Resource: " ) + " " ) ) ;
2016-05-22 22:28:37 +00:00
vmlb - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2017-03-05 15:44:50 +00:00
vmem_hb - > add_child ( vmlb ) ;
vmem_hb - > add_child ( memnew ( Label ( TTR ( " Total: " ) + " " ) ) ) ;
vmem_total = memnew ( LineEdit ) ;
2016-05-22 22:28:37 +00:00
vmem_total - > set_editable ( false ) ;
2019-09-04 05:20:57 +00:00
vmem_total - > set_custom_minimum_size ( Size2 ( 100 , 0 ) * EDSCALE ) ;
2016-05-22 22:28:37 +00:00
vmem_hb - > add_child ( vmem_total ) ;
2017-07-18 16:03:06 +00:00
vmem_refresh = memnew ( ToolButton ) ;
2019-11-28 15:37:15 +00:00
vmem_refresh - > set_disabled ( true ) ;
2016-05-22 22:28:37 +00:00
vmem_hb - > add_child ( vmem_refresh ) ;
2020-03-17 11:49:31 +00:00
vmem_export = memnew ( ToolButton ) ;
vmem_export - > set_tooltip ( TTR ( " Export list to a CSV file " ) ) ;
vmem_hb - > add_child ( vmem_export ) ;
2016-05-22 22:28:37 +00:00
vmem_vb - > add_child ( vmem_hb ) ;
2017-03-05 15:44:50 +00:00
vmem_refresh - > connect ( " pressed " , this , " _video_mem_request " ) ;
2020-03-17 11:49:31 +00:00
vmem_export - > connect ( " pressed " , this , " _video_mem_export " ) ;
2016-05-22 22:28:37 +00:00
2017-08-08 02:55:24 +00:00
VBoxContainer * vmmc = memnew ( VBoxContainer ) ;
2017-03-05 15:44:50 +00:00
vmem_tree = memnew ( Tree ) ;
2016-05-22 22:28:37 +00:00
vmem_tree - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
vmem_tree - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
vmmc - > add_child ( vmem_tree ) ;
vmmc - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
vmem_vb - > add_child ( vmmc ) ;
2019-11-28 15:37:15 +00:00
vmem_vb - > set_name ( TTR ( " Video RAM " ) ) ;
2016-05-22 22:28:37 +00:00
vmem_tree - > set_columns ( 4 ) ;
vmem_tree - > set_column_titles_visible ( true ) ;
2017-03-05 15:44:50 +00:00
vmem_tree - > set_column_title ( 0 , TTR ( " Resource Path " ) ) ;
vmem_tree - > set_column_expand ( 0 , true ) ;
vmem_tree - > set_column_expand ( 1 , false ) ;
vmem_tree - > set_column_title ( 1 , TTR ( " Type " ) ) ;
2019-11-28 15:37:15 +00:00
vmem_tree - > set_column_min_width ( 1 , 100 * EDSCALE ) ;
2017-03-05 15:44:50 +00:00
vmem_tree - > set_column_expand ( 2 , false ) ;
vmem_tree - > set_column_title ( 2 , TTR ( " Format " ) ) ;
2019-11-28 15:37:15 +00:00
vmem_tree - > set_column_min_width ( 2 , 150 * EDSCALE ) ;
2017-03-05 15:44:50 +00:00
vmem_tree - > set_column_expand ( 3 , false ) ;
vmem_tree - > set_column_title ( 3 , TTR ( " Usage " ) ) ;
2019-11-28 15:37:15 +00:00
vmem_tree - > set_column_min_width ( 3 , 80 * EDSCALE ) ;
2016-05-22 22:28:37 +00:00
vmem_tree - > set_hide_root ( true ) ;
tabs - > add_child ( vmem_vb ) ;
}
{ // misc
2019-02-18 00:25:26 +00:00
VBoxContainer * misc = memnew ( VBoxContainer ) ;
misc - > set_name ( TTR ( " Misc " ) ) ;
tabs - > add_child ( misc ) ;
2017-07-18 06:09:19 +00:00
GridContainer * info_left = memnew ( GridContainer ) ;
info_left - > set_columns ( 2 ) ;
2019-02-18 00:25:26 +00:00
misc - > add_child ( info_left ) ;
2017-03-05 15:44:50 +00:00
clicked_ctrl = memnew ( LineEdit ) ;
2017-07-18 06:09:19 +00:00
clicked_ctrl - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
info_left - > add_child ( memnew ( Label ( TTR ( " Clicked Control: " ) ) ) ) ;
info_left - > add_child ( clicked_ctrl ) ;
2017-03-05 15:44:50 +00:00
clicked_ctrl_type = memnew ( LineEdit ) ;
2017-07-18 06:09:19 +00:00
info_left - > add_child ( memnew ( Label ( TTR ( " Clicked Control Type: " ) ) ) ) ;
info_left - > add_child ( clicked_ctrl_type ) ;
2016-05-22 22:28:37 +00:00
2017-03-05 15:44:50 +00:00
live_edit_root = memnew ( LineEdit ) ;
2017-07-18 06:09:19 +00:00
live_edit_root - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2016-05-22 22:28:37 +00:00
{
2017-03-05 15:44:50 +00:00
HBoxContainer * lehb = memnew ( HBoxContainer ) ;
2017-05-02 21:02:06 +00:00
Label * l = memnew ( Label ( TTR ( " Live Edit Root: " ) ) ) ;
2017-07-18 06:09:19 +00:00
info_left - > add_child ( l ) ;
lehb - > add_child ( live_edit_root ) ;
2017-03-05 15:44:50 +00:00
le_set = memnew ( Button ( TTR ( " Set From Tree " ) ) ) ;
2016-05-22 22:28:37 +00:00
lehb - > add_child ( le_set ) ;
2017-03-05 15:44:50 +00:00
le_clear = memnew ( Button ( TTR ( " Clear " ) ) ) ;
2016-05-22 22:28:37 +00:00
lehb - > add_child ( le_clear ) ;
2017-05-02 21:02:06 +00:00
info_left - > add_child ( lehb ) ;
2016-05-22 22:28:37 +00:00
le_set - > set_disabled ( true ) ;
le_clear - > set_disabled ( true ) ;
}
2019-02-18 00:25:26 +00:00
misc - > add_child ( memnew ( VSeparator ) ) ;
HBoxContainer * buttons = memnew ( HBoxContainer ) ;
export_csv = memnew ( Button ( TTR ( " Export measures as CSV " ) ) ) ;
export_csv - > connect ( " pressed " , this , " _export_csv " ) ;
buttons - > add_child ( export_csv ) ;
misc - > add_child ( buttons ) ;
2015-08-02 15:29:37 +00:00
}
2017-03-05 15:44:50 +00:00
msgdialog = memnew ( AcceptDialog ) ;
2014-02-13 21:03:28 +00:00
add_child ( msgdialog ) ;
2017-03-05 15:44:50 +00:00
p_editor - > get_undo_redo ( ) - > set_method_notify_callback ( _method_changeds , this ) ;
p_editor - > get_undo_redo ( ) - > set_property_notify_callback ( _property_changeds , this ) ;
2018-11-11 12:14:06 +00:00
live_debug = true ;
2019-11-20 15:22:16 +00:00
camera_override = OVERRIDE_NONE ;
2017-03-05 15:44:50 +00:00
last_path_id = false ;
error_count = 0 ;
2018-08-16 05:41:03 +00:00
warning_count = 0 ;
2017-03-05 15:44:50 +00:00
hide_on_stop = true ;
2017-06-25 09:20:01 +00:00
enable_external_editor = false ;
2017-03-05 15:44:50 +00:00
last_error_count = 0 ;
2018-08-16 05:41:03 +00:00
last_warning_count = 0 ;
2020-03-15 10:45:39 +00:00
remote_port = 0 ;
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
EditorNode : : get_singleton ( ) - > get_pause_button ( ) - > connect ( " pressed " , this , " _paused " ) ;
2014-02-13 21:03:28 +00:00
}
ScriptEditorDebugger : : ~ ScriptEditorDebugger ( ) {
memdelete ( variables ) ;
ppeer - > set_stream_peer ( Ref < StreamPeer > ( ) ) ;
server - > stop ( ) ;
2017-10-17 14:37:25 +00:00
_clear_remote_objects ( ) ;
2014-02-13 21:03:28 +00:00
}