Merge pull request #11940 from GodotExplorer/debugger
Enhanced debugger for godot 3.0
This commit is contained in:
commit
6065b2d177
|
@ -35,6 +35,8 @@
|
|||
#include "os/input.h"
|
||||
#include "os/os.h"
|
||||
#include "project_settings.h"
|
||||
#include "scene/main/node.h"
|
||||
|
||||
void ScriptDebuggerRemote::_send_video_memory() {
|
||||
|
||||
List<ResourceUsage> usage;
|
||||
|
@ -201,20 +203,39 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue)
|
|||
|
||||
List<String> members;
|
||||
List<Variant> member_vals;
|
||||
|
||||
if (ScriptInstance *inst = p_script->debug_get_stack_level_instance(lv)) {
|
||||
members.push_back("self");
|
||||
member_vals.push_back(inst->get_owner());
|
||||
}
|
||||
p_script->debug_get_stack_level_members(lv, &members, &member_vals);
|
||||
|
||||
ERR_CONTINUE(members.size() != member_vals.size());
|
||||
|
||||
List<String> locals;
|
||||
List<Variant> local_vals;
|
||||
|
||||
p_script->debug_get_stack_level_locals(lv, &locals, &local_vals);
|
||||
|
||||
ERR_CONTINUE(locals.size() != local_vals.size());
|
||||
|
||||
List<String> globals;
|
||||
List<Variant> globals_vals;
|
||||
p_script->debug_get_globals(&globals, &globals_vals);
|
||||
ERR_CONTINUE(globals.size() != globals_vals.size());
|
||||
|
||||
packet_peer_stream->put_var("stack_frame_vars");
|
||||
packet_peer_stream->put_var(2 + locals.size() * 2 + members.size() * 2);
|
||||
packet_peer_stream->put_var(3 + (locals.size() + members.size() + globals.size()) * 2);
|
||||
|
||||
{ //locals
|
||||
packet_peer_stream->put_var(locals.size());
|
||||
|
||||
List<String>::Element *E = locals.front();
|
||||
List<Variant>::Element *F = local_vals.front();
|
||||
|
||||
while (E) {
|
||||
_put_variable(E->get(), F->get());
|
||||
|
||||
E = E->next();
|
||||
F = F->next();
|
||||
}
|
||||
}
|
||||
|
||||
{ //members
|
||||
packet_peer_stream->put_var(members.size());
|
||||
|
@ -231,11 +252,11 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue)
|
|||
}
|
||||
}
|
||||
|
||||
{ //locals
|
||||
packet_peer_stream->put_var(locals.size());
|
||||
{ //globals
|
||||
packet_peer_stream->put_var(globals.size());
|
||||
|
||||
List<String>::Element *E = locals.front();
|
||||
List<Variant>::Element *F = local_vals.front();
|
||||
List<String>::Element *E = globals.front();
|
||||
List<Variant>::Element *F = globals_vals.front();
|
||||
|
||||
while (E) {
|
||||
_put_variable(E->get(), F->get());
|
||||
|
@ -532,56 +553,88 @@ void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) {
|
|||
if (!obj)
|
||||
return;
|
||||
|
||||
typedef Pair<PropertyInfo, Variant> PropertyDesc;
|
||||
List<PropertyDesc> properties;
|
||||
|
||||
if (ScriptInstance *si = obj->get_script_instance()) {
|
||||
if (!si->get_script().is_null()) {
|
||||
|
||||
Set<StringName> members;
|
||||
si->get_script()->get_members(&members);
|
||||
for (Set<StringName>::Element *E = members.front(); E; E = E->next()) {
|
||||
|
||||
Variant m;
|
||||
if (si->get(E->get(), m)) {
|
||||
PropertyInfo pi(m.get_type(), String("Members/") + E->get());
|
||||
properties.push_back(PropertyDesc(pi, m));
|
||||
}
|
||||
}
|
||||
|
||||
Map<StringName, Variant> constants;
|
||||
si->get_script()->get_constants(&constants);
|
||||
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
|
||||
PropertyInfo pi(E->value().get_type(), (String("Constants/") + E->key()));
|
||||
properties.push_back(PropertyDesc(pi, E->value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Node *node = Object::cast_to<Node>(obj)) {
|
||||
PropertyInfo pi(Variant::NODE_PATH, String("Node/path"));
|
||||
properties.push_front(PropertyDesc(pi, node->get_path()));
|
||||
} else if (Resource *res = Object::cast_to<Resource>(obj)) {
|
||||
if (Script *s = Object::cast_to<Script>(res)) {
|
||||
Map<StringName, Variant> constants;
|
||||
s->get_constants(&constants);
|
||||
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
|
||||
PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key());
|
||||
properties.push_front(PropertyDesc(pi, E->value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<PropertyInfo> pinfo;
|
||||
obj->get_property_list(&pinfo, true);
|
||||
|
||||
int props_to_send = 0;
|
||||
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
|
||||
|
||||
if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) {
|
||||
props_to_send++;
|
||||
properties.push_back(PropertyDesc(E->get(), obj->get(E->get().name)));
|
||||
}
|
||||
}
|
||||
|
||||
Array send_props;
|
||||
for (int i = 0; i < properties.size(); i++) {
|
||||
const PropertyInfo &pi = properties[i].first;
|
||||
const Variant &var = properties[i].second;
|
||||
RES res = var;
|
||||
|
||||
Array prop;
|
||||
prop.push_back(pi.name);
|
||||
prop.push_back(pi.type);
|
||||
|
||||
//only send information that can be sent..
|
||||
int len = 0; //test how big is this to encode
|
||||
encode_variant(var, NULL, len);
|
||||
if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size
|
||||
prop.push_back(PROPERTY_HINT_OBJECT_TOO_BIG);
|
||||
prop.push_back("");
|
||||
prop.push_back(pi.usage);
|
||||
prop.push_back(Variant());
|
||||
} else {
|
||||
prop.push_back(pi.hint);
|
||||
if (res.is_null())
|
||||
prop.push_back(pi.hint_string);
|
||||
else
|
||||
prop.push_back(String("RES:") + res->get_path());
|
||||
prop.push_back(pi.usage);
|
||||
prop.push_back(var);
|
||||
}
|
||||
send_props.push_back(prop);
|
||||
}
|
||||
|
||||
packet_peer_stream->put_var("message:inspect_object");
|
||||
packet_peer_stream->put_var(props_to_send * 5 + 4);
|
||||
packet_peer_stream->put_var(3);
|
||||
packet_peer_stream->put_var(p_id);
|
||||
packet_peer_stream->put_var(obj->get_class());
|
||||
if (obj->is_class("Resource") || obj->is_class("Node"))
|
||||
packet_peer_stream->put_var(obj->call("get_path"));
|
||||
else
|
||||
packet_peer_stream->put_var("");
|
||||
|
||||
packet_peer_stream->put_var(props_to_send);
|
||||
|
||||
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
|
||||
|
||||
if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) {
|
||||
|
||||
if (E->get().usage & PROPERTY_USAGE_CATEGORY) {
|
||||
packet_peer_stream->put_var("*" + E->get().name);
|
||||
} else {
|
||||
packet_peer_stream->put_var(E->get().name);
|
||||
}
|
||||
|
||||
Variant var = obj->get(E->get().name);
|
||||
packet_peer_stream->put_var(E->get().type);
|
||||
//only send information that can be sent..
|
||||
|
||||
int len = 0; //test how big is this to encode
|
||||
encode_variant(var, NULL, len);
|
||||
|
||||
if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size
|
||||
packet_peer_stream->put_var(PROPERTY_HINT_OBJECT_TOO_BIG);
|
||||
packet_peer_stream->put_var("");
|
||||
packet_peer_stream->put_var(Variant());
|
||||
} else {
|
||||
packet_peer_stream->put_var(E->get().hint);
|
||||
packet_peer_stream->put_var(E->get().hint_string);
|
||||
packet_peer_stream->put_var(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
packet_peer_stream->put_var(send_props);
|
||||
}
|
||||
|
||||
void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value) {
|
||||
|
@ -590,7 +643,11 @@ void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String &p_p
|
|||
if (!obj)
|
||||
return;
|
||||
|
||||
obj->set(p_property, p_value);
|
||||
String prop_name = p_property;
|
||||
if (p_property.begins_with("Members/"))
|
||||
prop_name = p_property.substr(8, p_property.length());
|
||||
|
||||
obj->set(prop_name, p_value);
|
||||
}
|
||||
|
||||
void ScriptDebuggerRemote::_poll_events() {
|
||||
|
|
|
@ -120,6 +120,9 @@ public:
|
|||
|
||||
virtual int get_member_line(const StringName &p_member) const { return -1; }
|
||||
|
||||
virtual void get_constants(Map<StringName, Variant> *p_constants) {}
|
||||
virtual void get_members(Set<StringName> *p_constants) {}
|
||||
|
||||
Script() {}
|
||||
};
|
||||
|
||||
|
@ -130,6 +133,7 @@ public:
|
|||
virtual void get_property_list(List<PropertyInfo> *p_properties) const = 0;
|
||||
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const = 0;
|
||||
|
||||
virtual Object *get_owner() { return NULL; }
|
||||
virtual void get_property_state(List<Pair<StringName, Variant> > &state);
|
||||
|
||||
virtual void get_method_list(List<MethodInfo> *p_list) const = 0;
|
||||
|
@ -244,7 +248,8 @@ public:
|
|||
virtual String debug_get_stack_level_source(int p_level) const = 0;
|
||||
virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0;
|
||||
virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0;
|
||||
virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0;
|
||||
virtual ScriptInstance *debug_get_stack_level_instance(int p_level) { return NULL; }
|
||||
virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0;
|
||||
virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) = 0;
|
||||
|
||||
struct StackInfo {
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
/*************************************************************************/
|
||||
/* dictionary_property_edit.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "dictionary_property_edit.h"
|
||||
#include "editor_node.h"
|
||||
|
||||
void DictionaryPropertyEdit::_notif_change() {
|
||||
_change_notify();
|
||||
}
|
||||
|
||||
void DictionaryPropertyEdit::_notif_changev(const String &p_v) {
|
||||
_change_notify(p_v.utf8().get_data());
|
||||
}
|
||||
|
||||
void DictionaryPropertyEdit::_set_key(const Variant &p_old_key, const Variant &p_new_key) {
|
||||
|
||||
// TODO: Set key of a dictionary is not allowd yet
|
||||
return;
|
||||
}
|
||||
|
||||
void DictionaryPropertyEdit::_set_value(const Variant &p_key, const Variant &p_value) {
|
||||
|
||||
Dictionary dict = get_dictionary();
|
||||
dict[p_key] = p_value;
|
||||
Object *o = ObjectDB::get_instance(obj);
|
||||
if (!o)
|
||||
return;
|
||||
|
||||
o->set(property, dict);
|
||||
}
|
||||
|
||||
Variant DictionaryPropertyEdit::get_dictionary() const {
|
||||
|
||||
Object *o = ObjectDB::get_instance(obj);
|
||||
if (!o)
|
||||
return Dictionary();
|
||||
Variant dict = o->get(property);
|
||||
if (dict.get_type() != Variant::DICTIONARY)
|
||||
return Dictionary();
|
||||
return dict;
|
||||
}
|
||||
|
||||
void DictionaryPropertyEdit::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
|
||||
Dictionary dict = get_dictionary();
|
||||
|
||||
Array keys = dict.keys();
|
||||
keys.sort();
|
||||
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
String index = itos(i);
|
||||
|
||||
const Variant &key = keys[i];
|
||||
PropertyInfo pi(key.get_type(), index + ": key");
|
||||
p_list->push_back(pi);
|
||||
|
||||
const Variant &value = dict[key];
|
||||
pi = PropertyInfo(value.get_type(), index + ": value");
|
||||
p_list->push_back(pi);
|
||||
}
|
||||
}
|
||||
|
||||
void DictionaryPropertyEdit::edit(Object *p_obj, const StringName &p_prop) {
|
||||
|
||||
property = p_prop;
|
||||
obj = p_obj->get_instance_id();
|
||||
}
|
||||
|
||||
Node *DictionaryPropertyEdit::get_node() {
|
||||
|
||||
Object *o = ObjectDB::get_instance(obj);
|
||||
if (!o)
|
||||
return NULL;
|
||||
|
||||
return cast_to<Node>(o);
|
||||
}
|
||||
|
||||
void DictionaryPropertyEdit::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_set_key"), &DictionaryPropertyEdit::_set_key);
|
||||
ClassDB::bind_method(D_METHOD("_set_value"), &DictionaryPropertyEdit::_set_value);
|
||||
ClassDB::bind_method(D_METHOD("_notif_change"), &DictionaryPropertyEdit::_notif_change);
|
||||
ClassDB::bind_method(D_METHOD("_notif_changev"), &DictionaryPropertyEdit::_notif_changev);
|
||||
}
|
||||
|
||||
bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
|
||||
|
||||
Dictionary dict = get_dictionary();
|
||||
Array keys = dict.keys();
|
||||
keys.sort();
|
||||
|
||||
String pn = p_name;
|
||||
int slash = pn.find(": ");
|
||||
if (slash != -1 && pn.length() > slash) {
|
||||
String type = pn.substr(slash + 2, pn.length());
|
||||
int index = pn.substr(0, slash).to_int();
|
||||
if (type == "key" && index < keys.size()) {
|
||||
|
||||
const Variant &key = keys[index];
|
||||
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
|
||||
|
||||
ur->create_action(TTR("Change Dictionary Key"));
|
||||
ur->add_do_method(this, "_set_key", key, p_value);
|
||||
ur->add_undo_method(this, "_set_key", p_value, key);
|
||||
ur->add_do_method(this, "_notif_changev", p_name);
|
||||
ur->add_undo_method(this, "_notif_changev", p_name);
|
||||
ur->commit_action();
|
||||
|
||||
return true;
|
||||
} else if (type == "value" && index < keys.size()) {
|
||||
const Variant &key = keys[index];
|
||||
if (dict.has(key)) {
|
||||
|
||||
Variant value = dict[key];
|
||||
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
|
||||
|
||||
ur->create_action(TTR("Change Dictionary Value"));
|
||||
ur->add_do_method(this, "_set_value", key, p_value);
|
||||
ur->add_undo_method(this, "_set_value", key, value);
|
||||
ur->add_do_method(this, "_notif_changev", p_name);
|
||||
ur->add_undo_method(this, "_notif_changev", p_name);
|
||||
ur->commit_action();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DictionaryPropertyEdit::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
|
||||
Dictionary dict = get_dictionary();
|
||||
Array keys = dict.keys();
|
||||
keys.sort();
|
||||
|
||||
String pn = p_name;
|
||||
int slash = pn.find(": ");
|
||||
|
||||
if (slash != -1 && pn.length() > slash) {
|
||||
|
||||
String type = pn.substr(slash + 2, pn.length());
|
||||
int index = pn.substr(0, slash).to_int();
|
||||
|
||||
if (type == "key" && index < keys.size()) {
|
||||
r_ret = keys[index];
|
||||
return true;
|
||||
} else if (type == "value" && index < keys.size()) {
|
||||
const Variant &key = keys[index];
|
||||
if (dict.has(key)) {
|
||||
r_ret = dict[key];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DictionaryPropertyEdit::DictionaryPropertyEdit() {
|
||||
obj = 0;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*************************************************************************/
|
||||
/* dictionary_property_edit.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef DICTIONARY_PROPERTY_EDIT_H
|
||||
#define DICTIONARY_PROPERTY_EDIT_H
|
||||
|
||||
#include "scene/main/node.h"
|
||||
|
||||
class DictionaryPropertyEdit : public Reference {
|
||||
GDCLASS(DictionaryPropertyEdit, Reference);
|
||||
|
||||
ObjectID obj;
|
||||
StringName property;
|
||||
|
||||
void _notif_change();
|
||||
void _notif_changev(const String &p_v);
|
||||
void _set_key(const Variant &p_old_key, const Variant &p_new_key);
|
||||
void _set_value(const Variant &p_key, const Variant &p_value);
|
||||
|
||||
Variant get_dictionary() const;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
public:
|
||||
void edit(Object *p_obj, const StringName &p_prop);
|
||||
|
||||
Node *get_node();
|
||||
|
||||
DictionaryPropertyEdit();
|
||||
};
|
||||
|
||||
#endif // DICTIONARY_PROPERTY_EDIT_H
|
|
@ -303,8 +303,7 @@ void EditorNode::_notification(int p_what) {
|
|||
|
||||
if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
|
||||
scene_tabs->set_tab_close_display_policy((bool(EDITOR_DEF("interface/editor/always_show_close_button_in_scene_tabs", false)) ? Tabs::CLOSE_BUTTON_SHOW_ALWAYS : Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY));
|
||||
property_editor->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true)));
|
||||
Ref<Theme> theme = create_custom_theme(theme_base->get_theme());
|
||||
Ref<Theme> theme = create_editor_theme(theme_base->get_theme());
|
||||
|
||||
theme_base->set_theme(theme);
|
||||
gui_base->set_theme(theme);
|
||||
|
@ -1368,6 +1367,8 @@ void EditorNode::_prepare_history() {
|
|||
}
|
||||
} else if (Object::cast_to<Node>(obj)) {
|
||||
text = Object::cast_to<Node>(obj)->get_name();
|
||||
} else if (obj->is_class("ScriptEditorDebuggerInspectedObject")) {
|
||||
text = obj->call("get_title");
|
||||
} else {
|
||||
text = obj->get_class();
|
||||
}
|
||||
|
@ -1463,6 +1464,7 @@ void EditorNode::_edit_current() {
|
|||
|
||||
object_menu->set_disabled(true);
|
||||
|
||||
bool capitalize = bool(EDITOR_DEF("interface/editor/capitalize_properties", true));
|
||||
bool is_resource = current_obj->is_class("Resource");
|
||||
bool is_node = current_obj->is_class("Node");
|
||||
resource_save_button->set_disabled(!is_resource);
|
||||
|
@ -1516,6 +1518,11 @@ void EditorNode::_edit_current() {
|
|||
|
||||
} else {
|
||||
|
||||
if (current_obj->is_class("ScriptEditorDebuggerInspectedObject")) {
|
||||
editable_warning = TTR("This is a remote object so changes to it will not be kept.\nPlease read the documentation relevant to debugging to better understand this workflow.");
|
||||
capitalize = false;
|
||||
}
|
||||
|
||||
property_editor->edit(current_obj);
|
||||
node_dock->set_node(NULL);
|
||||
}
|
||||
|
@ -1525,6 +1532,10 @@ void EditorNode::_edit_current() {
|
|||
property_editable_warning_dialog->set_text(editable_warning);
|
||||
}
|
||||
|
||||
if (property_editor->is_capitalize_paths_enabled() != capitalize) {
|
||||
property_editor->set_enable_capitalize_paths(capitalize);
|
||||
}
|
||||
|
||||
/* Take care of PLUGIN EDITOR */
|
||||
|
||||
EditorPlugin *main_plugin = editor_data.get_editor(current_obj);
|
||||
|
|
|
@ -149,14 +149,14 @@ void EditorPath::_notification(int p_what) {
|
|||
|
||||
if (name == "")
|
||||
name = r->get_class();
|
||||
} else if (Object::cast_to<Node>(obj)) {
|
||||
|
||||
} else if (obj->is_class("ScriptEditorDebuggerInspectedObject"))
|
||||
name = obj->call("get_title");
|
||||
else if (Object::cast_to<Node>(obj))
|
||||
name = Object::cast_to<Node>(obj)->get_name();
|
||||
} else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "") {
|
||||
else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "")
|
||||
name = Object::cast_to<Resource>(obj)->get_name();
|
||||
} else {
|
||||
else
|
||||
name = obj->get_class();
|
||||
}
|
||||
|
||||
set_tooltip(obj->get_class());
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "core/project_settings.h"
|
||||
#include "editor/array_property_edit.h"
|
||||
#include "editor/create_dialog.h"
|
||||
#include "editor/dictionary_property_edit.h"
|
||||
#include "editor/editor_export.h"
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_help.h"
|
||||
|
@ -1157,7 +1158,8 @@ void CustomPropertyEditor::_node_path_selected(NodePath p_path) {
|
|||
node = Object::cast_to<Node>(owner);
|
||||
else if (owner->is_class("ArrayPropertyEdit"))
|
||||
node = Object::cast_to<ArrayPropertyEdit>(owner)->get_node();
|
||||
|
||||
else if (owner->is_class("DictionaryPropertyEdit"))
|
||||
node = Object::cast_to<DictionaryPropertyEdit>(owner)->get_node();
|
||||
if (!node) {
|
||||
v = p_path;
|
||||
emit_signal("variant_changed");
|
||||
|
@ -3215,9 +3217,14 @@ void PropertyEditor::update_tree() {
|
|||
} break;
|
||||
case Variant::DICTIONARY: {
|
||||
|
||||
Variant v = obj->get(p.name);
|
||||
|
||||
item->set_cell_mode(1, TreeItem::CELL_MODE_STRING);
|
||||
item->set_editable(1, false);
|
||||
item->set_text(1, obj->get(p.name).operator String());
|
||||
item->set_text(1, String("Dictionary{") + itos(v.call("size")) + "}");
|
||||
item->add_button(1, get_icon("EditResource", "EditorIcons"));
|
||||
|
||||
if (show_type_icons)
|
||||
item->set_icon(0, get_icon("DictionaryData", "EditorIcons"));
|
||||
|
||||
} break;
|
||||
|
||||
|
@ -3416,7 +3423,9 @@ void PropertyEditor::update_tree() {
|
|||
type = p.hint_string;
|
||||
|
||||
RES res = obj->get(p.name).operator RefPtr();
|
||||
|
||||
if (type.begins_with("RES:") && type != "RES:") { // Remote resources
|
||||
res = ResourceLoader::load(type.substr(4, type.length()));
|
||||
}
|
||||
Ref<EncodedObjectAsID> encoded = obj->get(p.name); //for debugger and remote tools
|
||||
|
||||
if (encoded.is_valid()) {
|
||||
|
@ -3427,6 +3436,7 @@ void PropertyEditor::update_tree() {
|
|||
item->set_editable(1, true);
|
||||
|
||||
} else if (obj->get(p.name).get_type() == Variant::NIL || res.is_null()) {
|
||||
|
||||
item->set_text(1, "<null>");
|
||||
item->set_icon(1, Ref<Texture>());
|
||||
item->set_custom_as_button(1, false);
|
||||
|
@ -3585,7 +3595,7 @@ void PropertyEditor::_edit_set(const String &p_name, const Variant &p_value, boo
|
|||
}
|
||||
}
|
||||
|
||||
if (!undo_redo || Object::cast_to<ArrayPropertyEdit>(obj)) { //kind of hacky
|
||||
if (!undo_redo || Object::cast_to<ArrayPropertyEdit>(obj) || Object::cast_to<DictionaryPropertyEdit>(obj)) { //kind of hacky
|
||||
|
||||
obj->set(p_name, p_value);
|
||||
if (p_refresh_all)
|
||||
|
@ -3983,8 +3993,20 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
|
|||
|
||||
Ref<ArrayPropertyEdit> ape = memnew(ArrayPropertyEdit);
|
||||
ape->edit(obj, n, ht, Variant::Type(t));
|
||||
|
||||
EditorNode::get_singleton()->push_item(ape.ptr());
|
||||
|
||||
} else if (t == Variant::DICTIONARY) {
|
||||
|
||||
Variant v = obj->get(n);
|
||||
|
||||
if (v.get_type() != t) {
|
||||
Variant::CallError ce;
|
||||
v = Variant::construct(Variant::Type(t), NULL, 0, ce);
|
||||
}
|
||||
|
||||
Ref<DictionaryPropertyEdit> dpe = memnew(DictionaryPropertyEdit);
|
||||
dpe->edit(obj, n);
|
||||
EditorNode::get_singleton()->push_item(dpe.ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1853,6 +1853,8 @@ void SceneTreeDock::_local_tree_selected() {
|
|||
remote_tree->hide();
|
||||
edit_remote->set_pressed(false);
|
||||
edit_local->set_pressed(true);
|
||||
|
||||
_node_selected();
|
||||
}
|
||||
|
||||
void SceneTreeDock::_bind_methods() {
|
||||
|
|
|
@ -116,7 +116,7 @@ class ScriptEditorDebuggerInspectedObject : public Object {
|
|||
protected:
|
||||
bool _set(const StringName &p_name, const Variant &p_value) {
|
||||
|
||||
if (!prop_values.has(p_name))
|
||||
if (!prop_values.has(p_name) || String(p_name).begins_with("Constants/"))
|
||||
return false;
|
||||
|
||||
emit_signal("value_edited", p_name, p_value);
|
||||
|
@ -132,6 +132,7 @@ protected:
|
|||
r_ret = prop_values[p_name];
|
||||
return true;
|
||||
}
|
||||
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const {
|
||||
|
||||
p_list->clear(); //sorry, no want category
|
||||
|
@ -142,23 +143,52 @@ protected:
|
|||
|
||||
static void _bind_methods() {
|
||||
|
||||
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);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("value_edited"));
|
||||
}
|
||||
|
||||
public:
|
||||
ObjectID last_edited_id;
|
||||
String type_name;
|
||||
ObjectID remote_object_id;
|
||||
List<PropertyInfo> prop_list;
|
||||
Map<StringName, Variant> prop_values;
|
||||
|
||||
ObjectID get_remote_object_id() {
|
||||
return remote_object_id;
|
||||
}
|
||||
|
||||
String get_title() {
|
||||
if (remote_object_id)
|
||||
return TTR("Remote ") + String(type_name) + ": " + itos(remote_object_id);
|
||||
else
|
||||
return "<null>";
|
||||
}
|
||||
Variant get_variant(const StringName &p_name) {
|
||||
|
||||
Variant var;
|
||||
_get(p_name, var);
|
||||
return var;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
|
||||
prop_list.clear();
|
||||
prop_values.clear();
|
||||
}
|
||||
void update() {
|
||||
_change_notify();
|
||||
}
|
||||
|
||||
void update_single(const char *p_prop) {
|
||||
_change_notify(p_prop);
|
||||
}
|
||||
|
||||
ScriptEditorDebuggerInspectedObject() { last_edited_id = 0; }
|
||||
ScriptEditorDebuggerInspectedObject() {
|
||||
remote_object_id = 0;
|
||||
}
|
||||
};
|
||||
|
||||
void ScriptEditorDebugger::debug_next() {
|
||||
|
@ -297,7 +327,6 @@ Size2 ScriptEditorDebugger::get_minimum_size() const {
|
|||
void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) {
|
||||
|
||||
if (p_msg == "debug_enter") {
|
||||
|
||||
Array msg;
|
||||
msg.push_back("get_stack_dump");
|
||||
ppeer->put_var(msg);
|
||||
|
@ -315,12 +344,10 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
if (error != "") {
|
||||
tabs->set_current_tab(0);
|
||||
}
|
||||
|
||||
profiler->set_enabled(false);
|
||||
|
||||
EditorNode::get_singleton()->get_pause_button()->set_pressed(true);
|
||||
|
||||
EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
|
||||
_clear_remote_objects();
|
||||
|
||||
} else if (p_msg == "debug_exit") {
|
||||
|
||||
|
@ -337,9 +364,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
//tabs->set_current_tab(0);
|
||||
profiler->set_enabled(true);
|
||||
profiler->disable_seeking();
|
||||
|
||||
inspector->edit(NULL);
|
||||
EditorNode::get_singleton()->get_pause_button()->set_pressed(false);
|
||||
|
||||
} else if (p_msg == "message:click_ctrl") {
|
||||
|
||||
clicked_ctrl->set_text(p_data[0]);
|
||||
|
@ -399,55 +425,57 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
le_set->set_disabled(false);
|
||||
} else if (p_msg == "message:inspect_object") {
|
||||
|
||||
ScriptEditorDebuggerInspectedObject *debugObj = NULL;
|
||||
|
||||
ObjectID id = p_data[0];
|
||||
String type = p_data[1];
|
||||
Variant path = p_data[2]; //what to do yet, i don't know
|
||||
int prop_count = p_data[3];
|
||||
Array properties = p_data[2];
|
||||
|
||||
int idx = 4;
|
||||
|
||||
if (inspected_object->last_edited_id != id) {
|
||||
inspected_object->prop_list.clear();
|
||||
inspected_object->prop_values.clear();
|
||||
bool is_new_object = false;
|
||||
if (remote_objects.has(id)) {
|
||||
debugObj = remote_objects[id];
|
||||
} else {
|
||||
debugObj = memnew(ScriptEditorDebuggerInspectedObject);
|
||||
debugObj->remote_object_id = id;
|
||||
debugObj->type_name = type;
|
||||
remote_objects[id] = debugObj;
|
||||
is_new_object = true;
|
||||
debugObj->connect("value_edited", this, "_scene_tree_property_value_edited");
|
||||
}
|
||||
|
||||
for (int i = 0; i < prop_count; i++) {
|
||||
for (int i = 0; i < properties.size(); i++) {
|
||||
|
||||
Array prop = properties[i];
|
||||
if (prop.size() != 6)
|
||||
continue;
|
||||
|
||||
PropertyInfo pinfo;
|
||||
pinfo.name = p_data[idx++];
|
||||
pinfo.type = Variant::Type(int(p_data[idx++]));
|
||||
pinfo.hint = PropertyHint(int(p_data[idx++]));
|
||||
pinfo.hint_string = p_data[idx++];
|
||||
if (pinfo.name.begins_with("*")) {
|
||||
pinfo.name = pinfo.name.substr(1, pinfo.name.length());
|
||||
pinfo.usage = PROPERTY_USAGE_CATEGORY;
|
||||
} else {
|
||||
pinfo.usage = PROPERTY_USAGE_EDITOR;
|
||||
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];
|
||||
|
||||
String hint_string = pinfo.hint_string;
|
||||
if (hint_string.begins_with("RES:") && hint_string != "RES:") {
|
||||
String path = hint_string.substr(4, hint_string.length());
|
||||
var = ResourceLoader::load(path);
|
||||
}
|
||||
|
||||
if (inspected_object->last_edited_id != id) {
|
||||
if (is_new_object) {
|
||||
//don't update.. it's the same, instead refresh
|
||||
inspected_object->prop_list.push_back(pinfo);
|
||||
debugObj->prop_list.push_back(pinfo);
|
||||
}
|
||||
|
||||
inspected_object->prop_values[pinfo.name] = p_data[idx++];
|
||||
|
||||
if (inspected_object->last_edited_id == id) {
|
||||
//same, just update value, don't rebuild
|
||||
inspected_object->update_single(pinfo.name.ascii().get_data());
|
||||
}
|
||||
debugObj->prop_values[pinfo.name] = var;
|
||||
}
|
||||
|
||||
if (inspected_object->last_edited_id != id) {
|
||||
//only if different
|
||||
inspected_object->update();
|
||||
if (editor->get_editor_history()->get_current() != debugObj->get_instance_id()) {
|
||||
editor->push_item(debugObj, "");
|
||||
} else {
|
||||
debugObj->update();
|
||||
}
|
||||
|
||||
inspected_object->last_edited_id = id;
|
||||
|
||||
tabs->set_current_tab(inspect_info->get_index());
|
||||
inspect_properties->edit(inspected_object);
|
||||
|
||||
} else if (p_msg == "message:video_mem") {
|
||||
|
||||
vmem_tree->clear();
|
||||
|
@ -502,7 +530,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
|
||||
int ofs = 0;
|
||||
int mcount = p_data[ofs];
|
||||
|
||||
ofs++;
|
||||
for (int i = 0; i < mcount; i++) {
|
||||
|
||||
|
@ -521,12 +548,11 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
v = s.get_slice(":", 1).to_int();
|
||||
}
|
||||
|
||||
variables->add_property("members/" + n, v, h, hs);
|
||||
variables->add_property("Locals/" + n, v, h, hs);
|
||||
}
|
||||
|
||||
ofs += mcount * 2;
|
||||
|
||||
mcount = p_data[ofs];
|
||||
|
||||
ofs++;
|
||||
for (int i = 0; i < mcount; i++) {
|
||||
|
||||
|
@ -545,7 +571,30 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
v = s.get_slice(":", 1).to_int();
|
||||
}
|
||||
|
||||
variables->add_property("locals/" + n, v, h, hs);
|
||||
variables->add_property("Members/" + n, v, h, hs);
|
||||
}
|
||||
|
||||
ofs += mcount * 2;
|
||||
mcount = p_data[ofs];
|
||||
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();
|
||||
|
||||
if (n.begins_with("*")) {
|
||||
|
||||
n = n.substr(1, n.length());
|
||||
h = PROPERTY_HINT_OBJECT_ID;
|
||||
String s = v;
|
||||
s = s.replace("[", "");
|
||||
hs = s.get_slice(":", 0);
|
||||
v = s.get_slice(":", 1).to_int();
|
||||
}
|
||||
|
||||
variables->add_property("Globals/" + n, v, h, hs);
|
||||
}
|
||||
|
||||
variables->update();
|
||||
|
@ -1101,6 +1150,8 @@ void ScriptEditorDebugger::start() {
|
|||
EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), true);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorNode::get_singleton()->get_scene_tree_dock()->show_remote_tree();
|
||||
set_process(true);
|
||||
}
|
||||
|
||||
|
@ -1133,11 +1184,11 @@ void ScriptEditorDebugger::stop() {
|
|||
le_set->set_disabled(true);
|
||||
profiler->set_enabled(true);
|
||||
|
||||
inspect_properties->edit(NULL);
|
||||
inspect_scene_tree->clear();
|
||||
|
||||
EditorNode::get_singleton()->get_pause_button()->set_pressed(false);
|
||||
EditorNode::get_singleton()->get_pause_button()->set_disabled(true);
|
||||
EditorNode::get_singleton()->get_scene_tree_dock()->hide_remote_tree();
|
||||
|
||||
if (hide_on_stop) {
|
||||
if (is_visible_in_tree())
|
||||
|
@ -1604,6 +1655,24 @@ void ScriptEditorDebugger::_paused() {
|
|||
}
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj) {
|
||||
|
||||
if (remote_objects.has(p_id))
|
||||
memdelete(remote_objects[p_id]);
|
||||
remote_objects[p_id] = p_obj;
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_clear_remote_objects() {
|
||||
|
||||
for (Map<ObjectID, ScriptEditorDebuggerInspectedObject *>::Element *E = remote_objects.front(); E; E = E->next()) {
|
||||
if (editor->get_editor_history()->get_current() == E->value()->get_instance_id()) {
|
||||
editor->push_item(NULL);
|
||||
}
|
||||
memdelete(E->value());
|
||||
}
|
||||
remote_objects.clear();
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_stack_dump_frame_selected"), &ScriptEditorDebugger::_stack_dump_frame_selected);
|
||||
|
@ -1649,6 +1718,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
|
|||
ppeer = Ref<PacketPeerStream>(memnew(PacketPeerStream));
|
||||
ppeer->set_input_buffer_max_size(1024 * 1024 * 8); //8mb should be enough
|
||||
editor = p_editor;
|
||||
editor->get_property_editor()->connect("object_id_selected", this, "_scene_tree_property_select_object");
|
||||
|
||||
tabs = memnew(TabContainer);
|
||||
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
|
||||
|
@ -1761,41 +1831,18 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
|
|||
tabs->add_child(error_split);
|
||||
}
|
||||
|
||||
{ // inquire
|
||||
|
||||
inspect_info = memnew(HSplitContainer);
|
||||
inspect_info->set_name(TTR("Remote Inspector"));
|
||||
tabs->add_child(inspect_info);
|
||||
|
||||
VBoxContainer *info_left = memnew(VBoxContainer);
|
||||
info_left->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
inspect_info->add_child(info_left);
|
||||
{ // remote scene tree
|
||||
|
||||
inspect_scene_tree = memnew(Tree);
|
||||
info_left->add_margin_child(TTR("Live Scene Tree:"), inspect_scene_tree, true);
|
||||
EditorNode::get_singleton()->get_scene_tree_dock()->add_remote_tree_editor(inspect_scene_tree);
|
||||
inspect_scene_tree->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
inspect_scene_tree->connect("cell_selected", this, "_scene_tree_selected");
|
||||
inspect_scene_tree->connect("item_collapsed", this, "_scene_tree_folded");
|
||||
|
||||
//
|
||||
|
||||
VBoxContainer *info_right = memnew(VBoxContainer);
|
||||
info_right->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
inspect_info->add_child(info_right);
|
||||
|
||||
inspect_properties = memnew(PropertyEditor);
|
||||
inspect_properties->hide_top_label();
|
||||
inspect_properties->set_show_categories(true);
|
||||
inspect_properties->connect("object_id_selected", this, "_scene_tree_property_select_object");
|
||||
|
||||
info_right->add_margin_child(TTR("Remote Object Properties: "), inspect_properties, true);
|
||||
|
||||
inspect_scene_tree_timeout = EDITOR_DEF("debugger/scene_tree_refresh_interval", 1.0);
|
||||
inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2);
|
||||
inspected_object_id = 0;
|
||||
updating_scene_tree = false;
|
||||
|
||||
inspected_object = memnew(ScriptEditorDebuggerInspectedObject);
|
||||
inspected_object->connect("value_edited", this, "_scene_tree_property_value_edited");
|
||||
}
|
||||
|
||||
{ //profiler
|
||||
|
@ -1952,5 +1999,5 @@ ScriptEditorDebugger::~ScriptEditorDebugger() {
|
|||
ppeer->set_stream_peer(Ref<StreamPeer>());
|
||||
|
||||
server->stop();
|
||||
memdelete(inspected_object);
|
||||
_clear_remote_objects();
|
||||
}
|
||||
|
|
|
@ -72,19 +72,18 @@ class ScriptEditorDebugger : public Control {
|
|||
Button *le_set;
|
||||
Button *le_clear;
|
||||
|
||||
Tree *inspect_scene_tree;
|
||||
HSplitContainer *inspect_info;
|
||||
PropertyEditor *inspect_properties;
|
||||
bool updating_scene_tree;
|
||||
float inspect_scene_tree_timeout;
|
||||
float inspect_edited_object_timeout;
|
||||
ObjectID inspected_object_id;
|
||||
ScriptEditorDebuggerInspectedObject *inspected_object;
|
||||
bool updating_scene_tree;
|
||||
ScriptEditorDebuggerVariables *variables;
|
||||
Map<ObjectID, ScriptEditorDebuggerInspectedObject *> remote_objects;
|
||||
Set<ObjectID> unfold_cache;
|
||||
|
||||
HSplitContainer *error_split;
|
||||
ItemList *error_list;
|
||||
ItemList *error_stack;
|
||||
Tree *inspect_scene_tree;
|
||||
|
||||
int error_count;
|
||||
int last_error_count;
|
||||
|
@ -96,7 +95,6 @@ class ScriptEditorDebugger : public Control {
|
|||
TabContainer *tabs;
|
||||
|
||||
Label *reason;
|
||||
ScriptEditorDebuggerVariables *variables;
|
||||
|
||||
Button *step;
|
||||
Button *next;
|
||||
|
@ -174,6 +172,9 @@ class ScriptEditorDebugger : public Control {
|
|||
|
||||
void _paused();
|
||||
|
||||
void _set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj);
|
||||
void _clear_remote_objects();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
|
|
@ -100,7 +100,7 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
|
|||
#endif
|
||||
instance->owner->set_script_instance(instance);
|
||||
|
||||
/* STEP 2, INITIALIZE AND CONSRTUCT */
|
||||
/* STEP 2, INITIALIZE AND CONSRTUCT */
|
||||
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->lock();
|
||||
|
@ -615,6 +615,23 @@ ScriptLanguage *GDScript::get_language() const {
|
|||
return GDScriptLanguage::get_singleton();
|
||||
}
|
||||
|
||||
void GDScript::get_constants(Map<StringName, Variant> *p_constants) {
|
||||
|
||||
if (p_constants) {
|
||||
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
|
||||
(*p_constants)[E->key()] = E->value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GDScript::get_members(Set<StringName> *p_members) {
|
||||
if (p_members) {
|
||||
for (Set<StringName>::Element *E = members.front(); E; E = E->next()) {
|
||||
p_members->insert(E->get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
|
||||
|
||||
GDScript *top = this;
|
||||
|
|
|
@ -198,6 +198,9 @@ public:
|
|||
return -1;
|
||||
}
|
||||
|
||||
virtual void get_constants(Map<StringName, Variant> *p_constants);
|
||||
virtual void get_members(Set<StringName> *p_members);
|
||||
|
||||
GDScript();
|
||||
~GDScript();
|
||||
};
|
||||
|
@ -219,7 +222,7 @@ class GDScriptInstance : public ScriptInstance {
|
|||
void _ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ Object *get_owner() { return owner; }
|
||||
virtual Object *get_owner() { return owner; }
|
||||
|
||||
virtual bool set(const StringName &p_name, const Variant &p_value);
|
||||
virtual bool get(const StringName &p_name, Variant &r_ret) const;
|
||||
|
@ -407,7 +410,8 @@ public:
|
|||
virtual String debug_get_stack_level_source(int p_level) const;
|
||||
virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
|
||||
virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
|
||||
virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
|
||||
virtual ScriptInstance *debug_get_stack_level_instance(int p_level);
|
||||
virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
|
||||
virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1);
|
||||
|
||||
virtual void reload_all_scripts();
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "gdscript_compiler.h"
|
||||
#include "global_constants.h"
|
||||
#include "os/file_access.h"
|
||||
#include "project_settings.h"
|
||||
#include "core/engine.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/editor_file_system.h"
|
||||
|
@ -280,10 +280,62 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *
|
|||
p_values->push_back(instance->debug_get_member_by_index(E->get().index));
|
||||
}
|
||||
}
|
||||
void GDScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
|
||||
|
||||
//no globals are really reachable in gdscript
|
||||
ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) {
|
||||
|
||||
ERR_FAIL_COND_V(_debug_parse_err_line >= 0, NULL);
|
||||
ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, NULL);
|
||||
|
||||
int l = _debug_call_stack_pos - p_level - 1;
|
||||
ScriptInstance *instance = _call_stack[l].instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
|
||||
|
||||
const Map<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map();
|
||||
const Variant *globals = GDScriptLanguage::get_singleton()->get_global_array();
|
||||
|
||||
List<Pair<String, Variant> > cinfo;
|
||||
get_public_constants(&cinfo);
|
||||
|
||||
for (const Map<StringName, int>::Element *E = name_idx.front(); E; E = E->next()) {
|
||||
|
||||
if (ClassDB::class_exists(E->key()) || Engine::get_singleton()->has_singleton(E->key()))
|
||||
continue;
|
||||
|
||||
bool is_script_constant = false;
|
||||
for (List<Pair<String, Variant> >::Element *CE = cinfo.front(); CE; CE = CE->next()) {
|
||||
if (CE->get().first == E->key()) {
|
||||
is_script_constant = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_script_constant)
|
||||
continue;
|
||||
|
||||
const Variant &var = globals[E->value()];
|
||||
if (Object *obj = var) {
|
||||
if (Object::cast_to<GDScriptNativeClass>(obj))
|
||||
continue;
|
||||
}
|
||||
|
||||
bool skip = false;
|
||||
for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
|
||||
if (E->key() == GlobalConstants::get_global_constant_name(i)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip)
|
||||
continue;
|
||||
|
||||
p_globals->push_back(E->key());
|
||||
p_values->push_back(var);
|
||||
}
|
||||
}
|
||||
|
||||
String GDScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
|
||||
|
||||
if (_debug_parse_err_line >= 0)
|
||||
|
@ -1743,7 +1795,7 @@ static void _find_type_arguments(GDScriptCompletionContext &context, const GDScr
|
|||
}
|
||||
|
||||
} else {
|
||||
//regular method
|
||||
//regular method
|
||||
|
||||
#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
|
||||
if (p_argidx < m->get_argument_count()) {
|
||||
|
|
Loading…
Reference in New Issue