Enhanced debugger. ake 2.1 more productive!
Allow access more informations from remote debugger. Refector more debugger related code to allow full access to variables. Array Property Editor now can edit with more objects including remote objects. Implements `GDInstance::debug_get_globals` to query all gloabl constants avaliable in GDScriptLanguage. Show globals in debug stack variable panel. Disabe capitalize property name for remote object. Add DictionaryPropertyEdit to edit with Dictionaries. The serialization/unserialization workflow use binary data instead of dictionary to avoid send too large data. Do not stop debugger if curent break point stack has error fix #9034. Don't send all content of strings but first 80 characters from remote debugger. Add constants into the break point stack tree and remote object instance edit inspector. Remote GDScript resource object instance list constants in the property inspector. Add `self` to the local in the break point stack as a remote object. Move some functions for GDScript related to thier base classes so debugger don't rely on the gdscript module any more. The slef in the debugger tree now expanded as the instance of script instead of the script resource.
This commit is contained in:
parent
171d8a501f
commit
da2bcda7be
|
@ -28,10 +28,12 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "script_debugger_remote.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "globals.h"
|
||||
#include "io/ip.h"
|
||||
#include "os/input.h"
|
||||
#include "os/os.h"
|
||||
|
||||
void ScriptDebuggerRemote::_send_video_memory() {
|
||||
|
||||
List<ResourceUsage> usage;
|
||||
|
@ -183,6 +185,8 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue)
|
|||
ERR_CONTINUE(cmd.size() != 1);
|
||||
int lv = cmd[0];
|
||||
|
||||
ScriptInstance *self_instance = p_script->debug_get_stack_level_instance(lv);
|
||||
|
||||
List<String> members;
|
||||
List<Variant> member_vals;
|
||||
|
||||
|
@ -197,47 +201,74 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue)
|
|||
|
||||
ERR_CONTINUE(locals.size() != local_vals.size());
|
||||
|
||||
List<String> globals;
|
||||
List<Variant> global_vals;
|
||||
|
||||
p_script->debug_get_globals(&globals, &global_vals);
|
||||
|
||||
ERR_CONTINUE(globals.size() != global_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(locals.size() + members.size() + globals.size());
|
||||
|
||||
{ //members
|
||||
packet_peer_stream->put_var(members.size());
|
||||
|
||||
List<String>::Element *E = members.front();
|
||||
List<Variant>::Element *F = member_vals.front();
|
||||
{ //locals
|
||||
List<String>::Element *E = locals.front();
|
||||
List<Variant>::Element *F = local_vals.front();
|
||||
|
||||
while (E) {
|
||||
|
||||
if (F->get().get_type() == Variant::OBJECT) {
|
||||
packet_peer_stream->put_var("*" + E->get());
|
||||
String pretty_print = F->get().operator String();
|
||||
packet_peer_stream->put_var(pretty_print.ascii().get_data());
|
||||
} else {
|
||||
packet_peer_stream->put_var(E->get());
|
||||
packet_peer_stream->put_var(F->get());
|
||||
}
|
||||
PropertyInfo pi(var.get_type(), String("locals/") + E->get());
|
||||
packet_peer_stream->put_var(_serialize(F->get(), pi));
|
||||
|
||||
E = E->next();
|
||||
F = F->next();
|
||||
}
|
||||
}
|
||||
|
||||
{ //locals
|
||||
packet_peer_stream->put_var(locals.size());
|
||||
{ //members
|
||||
|
||||
List<String>::Element *E = locals.front();
|
||||
List<Variant>::Element *F = local_vals.front();
|
||||
if (self_instance) { // self
|
||||
|
||||
members.push_front("self");
|
||||
member_vals.push_front(self_instance->get_owner());
|
||||
}
|
||||
|
||||
List<String>::Element *E = members.front();
|
||||
List<Variant>::Element *F = member_vals.front();
|
||||
|
||||
while (E) {
|
||||
|
||||
if (F->get().get_type() == Variant::OBJECT) {
|
||||
packet_peer_stream->put_var("*" + E->get());
|
||||
String pretty_print = F->get().operator String();
|
||||
packet_peer_stream->put_var(pretty_print.ascii().get_data());
|
||||
} else {
|
||||
packet_peer_stream->put_var(E->get());
|
||||
packet_peer_stream->put_var(F->get());
|
||||
PropertyInfo pi(var.get_type(), String("members/") + E->get());
|
||||
packet_peer_stream->put_var(_serialize(F->get(), pi));
|
||||
|
||||
E = E->next();
|
||||
F = F->next();
|
||||
}
|
||||
}
|
||||
|
||||
if (self_instance) { // constants
|
||||
|
||||
Ref<Script> script = self_instance->get_script();
|
||||
if (!script.is_null()) {
|
||||
|
||||
const Map<StringName, Variant> &constants = script->get_constants();
|
||||
|
||||
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
|
||||
|
||||
PropertyInfo pi(var.get_type(), String("constants/") + E->key());
|
||||
packet_peer_stream->put_var(_serialize(E->value(), pi));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ //globals
|
||||
List<String>::Element *E = globals.front();
|
||||
List<Variant>::Element *F = global_vals.front();
|
||||
|
||||
while (E) {
|
||||
|
||||
PropertyInfo pi(var.get_type(), String("globals/") + E->get());
|
||||
packet_peer_stream->put_var(_serialize(F->get(), pi));
|
||||
|
||||
E = E->next();
|
||||
F = F->next();
|
||||
|
@ -531,69 +562,81 @@ void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) {
|
|||
if (!obj)
|
||||
return;
|
||||
|
||||
Array props;
|
||||
const uint32_t SEND_PROPERTIES = 0xFFFFFFFF; // All kind of properties are allowed
|
||||
List<PropertyInfo> pinfo;
|
||||
Set<StringName> ignored_properties;
|
||||
obj->get_property_list(&pinfo, true);
|
||||
bool query_props = true;
|
||||
|
||||
int props_to_send = 0;
|
||||
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
|
||||
if (ScriptInstance *si = obj->get_script_instance()) {
|
||||
if (!si->get_script().is_null()) {
|
||||
|
||||
if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) {
|
||||
props_to_send++;
|
||||
const Map<StringName, Variant> &constants = si->get_script()->get_constants();
|
||||
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
|
||||
|
||||
PropertyInfo pi(E->value().get_type(), String("constants/") + E->key());
|
||||
props.push_back(_serialize(E->value(), pi));
|
||||
}
|
||||
|
||||
const Set<StringName> &members = si->get_script()->get_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());
|
||||
props.push_back(_serialize(m, pi));
|
||||
|
||||
ignored_properties.insert(E->get());
|
||||
}
|
||||
}
|
||||
|
||||
PropertyInfo pi(Variant::OBJECT, String("Resource/script"));
|
||||
props.push_back(_serialize(si->get_script(), pi));
|
||||
}
|
||||
} else if (Resource *res = obj->cast_to<Resource>()) {
|
||||
|
||||
if (res->cast_to<Script>()) {
|
||||
|
||||
const Map<StringName, Variant> &constants = res->cast_to<Script>()->get_constants();
|
||||
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
|
||||
|
||||
PropertyInfo pi(E->value().get_type(), String("constants/") + E->key());
|
||||
props.push_back(_serialize(E->value(), pi));
|
||||
}
|
||||
}
|
||||
|
||||
PropertyInfo pi(Variant::OBJECT, res->get_type_name(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CATEGORY);
|
||||
props.push_front(_serialize(res, pi));
|
||||
|
||||
PropertyInfo pathpi(Variant::STRING, "Resource/Resource");
|
||||
pathpi.hint_string = "REMOTE:RES";
|
||||
props.push_back(_serialize(res->get_path(), pathpi));
|
||||
|
||||
query_props = false;
|
||||
} else if (obj->is_type("Node")) {
|
||||
|
||||
String path = obj->call("get_path");
|
||||
PropertyInfo pi(Variant::OBJECT, String("Node/path"));
|
||||
props.push_back(_serialize(path, pi));
|
||||
}
|
||||
|
||||
if (query_props) {
|
||||
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
|
||||
|
||||
if (E->get().usage & SEND_PROPERTIES && !ignored_properties.has(E->get().name)) {
|
||||
|
||||
Variant var = obj->get(E->get().name);
|
||||
props.push_back(_serialize(var, E->get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packet_peer_stream->put_var("message:inspect_object");
|
||||
packet_peer_stream->put_var(props_to_send * 5 + 4);
|
||||
packet_peer_stream->put_var(2);
|
||||
packet_peer_stream->put_var(p_id);
|
||||
packet_peer_stream->put_var(obj->get_type());
|
||||
if (obj->is_type("Resource") || obj->is_type("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);
|
||||
|
||||
if (E->get().type == Variant::OBJECT || var.get_type() == Variant::OBJECT) {
|
||||
|
||||
ObjectID id2;
|
||||
Object *obj = var;
|
||||
if (obj) {
|
||||
id2 = obj->get_instance_ID();
|
||||
} else {
|
||||
id2 = 0;
|
||||
}
|
||||
|
||||
packet_peer_stream->put_var(Variant::INT); //hint string
|
||||
packet_peer_stream->put_var(PROPERTY_HINT_OBJECT_ID); //hint
|
||||
packet_peer_stream->put_var(E->get().hint_string); //hint string
|
||||
packet_peer_stream->put_var(id2); //value
|
||||
} else {
|
||||
packet_peer_stream->put_var(E->get().type);
|
||||
packet_peer_stream->put_var(E->get().hint);
|
||||
packet_peer_stream->put_var(E->get().hint_string);
|
||||
//only send information that can be sent..
|
||||
if (var.get_type() == Variant::IMAGE) {
|
||||
var = Image();
|
||||
}
|
||||
if (var.get_type() >= Variant::DICTIONARY) {
|
||||
var = Array(); //send none for now, may be to big
|
||||
}
|
||||
packet_peer_stream->put_var(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
packet_peer_stream->put_var(props);
|
||||
}
|
||||
|
||||
void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value) {
|
||||
|
@ -602,7 +645,164 @@ void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String &p_p
|
|||
if (!obj)
|
||||
return;
|
||||
|
||||
obj->set(p_property, p_value);
|
||||
String name = p_property;
|
||||
const String member_prefix = String("members/");
|
||||
if (name.begins_with(member_prefix) && p_property.length() > member_prefix.length()) {
|
||||
name = p_property.substr(member_prefix.length(), p_property.length());
|
||||
}
|
||||
|
||||
obj->set(name, p_value);
|
||||
}
|
||||
|
||||
int __put_value_to_buff_at_pos(const Variant &value, DVector<uint8_t> &buff, int pos) {
|
||||
|
||||
int size_required = 0;
|
||||
|
||||
DVector<uint8_t> valuebuf;
|
||||
if (value.get_type() == Variant::RAW_ARRAY)
|
||||
valuebuf = value;
|
||||
|
||||
String sub_contetn;
|
||||
|
||||
switch (value.get_type()) {
|
||||
case Variant::NIL:
|
||||
case Variant::INT:
|
||||
case Variant::BOOL:
|
||||
size_required = sizeof(uint32_t);
|
||||
break;
|
||||
case Variant::REAL:
|
||||
size_required = sizeof(uint32_t);
|
||||
break;
|
||||
case Variant::STRING: {
|
||||
sub_contetn = value;
|
||||
const int MAX_STR_LEN = 80; // More than 80 will not be send to the debugger
|
||||
if (sub_contetn.length() > MAX_STR_LEN)
|
||||
sub_contetn = sub_contetn.substr(0, MAX_STR_LEN) + "...";
|
||||
encode_variant(sub_contetn, NULL, size_required);
|
||||
} break;
|
||||
default:
|
||||
encode_variant(value, NULL, size_required);
|
||||
break;
|
||||
}
|
||||
if (buff.size() < pos + size_required)
|
||||
buff.resize((pos + size_required) * 2);
|
||||
|
||||
switch (value.get_type()) {
|
||||
case Variant::INT:
|
||||
case Variant::BOOL:
|
||||
encode_uint32(value, &buff.write()[pos]);
|
||||
break;
|
||||
case Variant::REAL:
|
||||
encode_float(value, &buff.write()[pos]);
|
||||
break;
|
||||
case Variant::STRING:
|
||||
encode_variant(sub_contetn, &buff.write()[pos], size_required);
|
||||
break;
|
||||
default:
|
||||
encode_variant(value, &buff.write()[pos], size_required);
|
||||
break;
|
||||
}
|
||||
|
||||
return size_required;
|
||||
}
|
||||
|
||||
int ScriptDebuggerRemote::_serialize_variant(const Variant &var, const PropertyInfo &p_info, DVector<uint8_t> &buff) {
|
||||
|
||||
int used_size = 0;
|
||||
|
||||
used_size += __put_value_to_buff_at_pos(p_info.name, buff, used_size);
|
||||
const int type_index = used_size;
|
||||
used_size += __put_value_to_buff_at_pos(var.get_type(), buff, type_index);
|
||||
const int hint_index = used_size;
|
||||
used_size += __put_value_to_buff_at_pos(p_info.hint, buff, hint_index);
|
||||
used_size += __put_value_to_buff_at_pos(p_info.usage, buff, used_size);
|
||||
|
||||
StringName hint_string = p_info.hint_string;
|
||||
|
||||
int value_len = 0;
|
||||
switch (var.get_type()) {
|
||||
case Variant::OBJECT: {
|
||||
__put_value_to_buff_at_pos(Variant::INT, buff, type_index);
|
||||
__put_value_to_buff_at_pos(PROPERTY_HINT_OBJECT_ID, buff, hint_index);
|
||||
Object *obj = var;
|
||||
uint32_t id = obj ? obj->get_instance_ID() : 0;
|
||||
hint_string = obj ? obj->get_type_name() : hint_string;
|
||||
value_len += __put_value_to_buff_at_pos(id, buff, used_size + value_len);
|
||||
} break;
|
||||
case Variant::IMAGE:
|
||||
value_len += __put_value_to_buff_at_pos(Image(), buff, used_size + value_len);
|
||||
break;
|
||||
case Variant::ARRAY: {
|
||||
Array arr = var;
|
||||
value_len += __put_value_to_buff_at_pos(arr.size(), buff, used_size + value_len);
|
||||
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
|
||||
const Variant &e = arr[i];
|
||||
PropertyInfo pi(e.get_type(), "");
|
||||
DVector<uint8_t> ebuff;
|
||||
ebuff.resize(256);
|
||||
ebuff.resize(_serialize_variant(e, pi, ebuff));
|
||||
|
||||
value_len += __put_value_to_buff_at_pos(ebuff, buff, used_size + value_len);
|
||||
}
|
||||
} break;
|
||||
case Variant::STRING_ARRAY: {
|
||||
|
||||
DVector<String> strarr = var;
|
||||
Array arr;
|
||||
arr.resize(strarr.size());
|
||||
|
||||
for (int i = 0; i < strarr.size(); i++)
|
||||
arr[i] = strarr[i];
|
||||
|
||||
PropertyInfo pi(Variant::ARRAY, "");
|
||||
DVector<uint8_t> ebuff;
|
||||
ebuff.resize(256);
|
||||
ebuff.resize(_serialize_variant(arr, pi, ebuff));
|
||||
|
||||
value_len += __put_value_to_buff_at_pos(ebuff, buff, used_size + value_len);
|
||||
} break;
|
||||
case Variant::DICTIONARY: {
|
||||
Dictionary dict = var;
|
||||
value_len += __put_value_to_buff_at_pos(dict.size(), buff, used_size + value_len);
|
||||
|
||||
const Array &keys = dict.keys();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
|
||||
PropertyInfo pi;
|
||||
const Variant &key = keys[i];
|
||||
|
||||
DVector<uint8_t> tmpbuff;
|
||||
tmpbuff.resize(256);
|
||||
pi.type = key.get_type();
|
||||
tmpbuff.resize(_serialize_variant(key, pi, tmpbuff));
|
||||
value_len += __put_value_to_buff_at_pos(tmpbuff, buff, used_size + value_len);
|
||||
|
||||
const Variant &value = dict[key];
|
||||
pi.type = value.get_type();
|
||||
tmpbuff.resize(_serialize_variant(value, pi, tmpbuff));
|
||||
value_len += __put_value_to_buff_at_pos(tmpbuff, buff, used_size + value_len);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
value_len += __put_value_to_buff_at_pos(var, buff, used_size + value_len);
|
||||
break;
|
||||
}
|
||||
used_size += value_len;
|
||||
|
||||
used_size += __put_value_to_buff_at_pos(hint_string, buff, used_size);
|
||||
|
||||
return used_size;
|
||||
}
|
||||
|
||||
DVector<uint8_t> ScriptDebuggerRemote::_serialize(const Variant &var, const PropertyInfo &p_info) {
|
||||
|
||||
DVector<uint8_t> buff;
|
||||
buff.resize(256);
|
||||
buff.resize(_serialize_variant(var, p_info, buff));
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
void ScriptDebuggerRemote::_poll_events() {
|
||||
|
@ -648,6 +848,9 @@ void ScriptDebuggerRemote::_poll_events() {
|
|||
} else if (command == "set_object_property") {
|
||||
|
||||
_set_object_property(cmd[1], cmd[2], cmd[3]);
|
||||
} else if (command == "set_variable_value") {
|
||||
|
||||
// TODO: Implement set the value stack variale
|
||||
|
||||
} else if (command == "start_profiling") {
|
||||
|
||||
|
@ -945,6 +1148,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() {
|
|||
tcp_client = StreamPeerTCP::create_ref();
|
||||
packet_peer_stream = Ref<PacketPeerStream>(memnew(PacketPeerStream));
|
||||
packet_peer_stream->set_stream_peer(tcp_client);
|
||||
packet_peer_stream->set_input_buffer_max_size(pow(2, 20));
|
||||
mutex = Mutex::create();
|
||||
locking = false;
|
||||
|
||||
|
|
|
@ -108,7 +108,6 @@ class ScriptDebuggerRemote : public ScriptDebugger {
|
|||
void *request_scene_tree_ud;
|
||||
|
||||
void _set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value);
|
||||
|
||||
void _send_object_id(ObjectID p_id);
|
||||
void _send_video_memory();
|
||||
LiveEditFuncs *live_edit_funcs;
|
||||
|
@ -118,6 +117,9 @@ class ScriptDebuggerRemote : public ScriptDebugger {
|
|||
|
||||
void _send_profiling_data(bool p_for_frame);
|
||||
|
||||
int _serialize_variant(const Variant &var, const PropertyInfo &p_info, DVector<uint8_t> &buff);
|
||||
DVector<uint8_t> _serialize(const Variant &var, const PropertyInfo &p_info);
|
||||
|
||||
struct FrameData {
|
||||
|
||||
StringName name;
|
||||
|
|
|
@ -90,6 +90,9 @@ public:
|
|||
virtual ScriptInstance *instance_create(Object *p_this) = 0;
|
||||
virtual bool instance_has(const Object *p_this) const = 0;
|
||||
|
||||
virtual const Map<StringName, Variant> &get_constants() const = 0;
|
||||
virtual const Set<StringName> &get_members() const = 0;
|
||||
|
||||
virtual bool has_source_code() const = 0;
|
||||
virtual String get_source_code() const = 0;
|
||||
virtual void set_source_code(const String &p_code) = 0;
|
||||
|
@ -128,6 +131,7 @@ public:
|
|||
virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||
virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||
virtual void notification(int p_notification) = 0;
|
||||
virtual Object *get_owner() { return NULL; }
|
||||
|
||||
//this is used by script languages that keep a reference counter of their own
|
||||
//you can make make Ref<> not die when it reaches zero, so deleting the reference
|
||||
|
@ -196,6 +200,7 @@ 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 ScriptInstance *debug_get_stack_level_instance(int p_level) = 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 String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) = 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
/*************************************************************************/
|
||||
/* 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(int p_idx, const Variant &p_new_key) {
|
||||
|
||||
// Set key of a dictionary is not allowd
|
||||
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();
|
||||
|
||||
const Array &keys = dict.keys();
|
||||
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 o->cast_to<Node>();
|
||||
}
|
||||
|
||||
void DictionaryPropertyEdit::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_set_key"), &DictionaryPropertyEdit::_set_key);
|
||||
ObjectTypeDB::bind_method(_MD("_set_value"), &DictionaryPropertyEdit::_set_value);
|
||||
ObjectTypeDB::bind_method(_MD("_notif_change"), &DictionaryPropertyEdit::_notif_change);
|
||||
ObjectTypeDB::bind_method(_MD("_notif_changev"), &DictionaryPropertyEdit::_notif_changev);
|
||||
}
|
||||
|
||||
bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
|
||||
|
||||
Dictionary dict = get_dictionary();
|
||||
const Array &keys = dict.keys();
|
||||
|
||||
String pn = p_name;
|
||||
int slash = pn.find("/");
|
||||
if (slash != -1 && pn.length() > slash) {
|
||||
String type = pn.substr(slash + 1, 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", index, p_value);
|
||||
ur->add_undo_method(this, "_set_key", index, 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();
|
||||
const Array &keys = dict.keys();
|
||||
|
||||
String pn = p_name;
|
||||
int slash = pn.find("/");
|
||||
|
||||
if (slash != -1 && pn.length() > slash) {
|
||||
|
||||
String type = pn.substr(slash + 1, 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 {
|
||||
OBJ_TYPE(DictionaryPropertyEdit, Reference);
|
||||
|
||||
ObjectID obj;
|
||||
StringName property;
|
||||
|
||||
void _notif_change();
|
||||
void _notif_changev(const String &p_v);
|
||||
void _set_key(const int p_idx, 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
|
|
@ -29,6 +29,7 @@
|
|||
/*************************************************************************/
|
||||
#include "property_editor.h"
|
||||
#include "array_property_edit.h"
|
||||
#include "dictionary_property_edit.h"
|
||||
#include "editor_file_system.h"
|
||||
#include "editor_help.h"
|
||||
#include "editor_import_export.h"
|
||||
|
@ -2885,7 +2886,7 @@ void PropertyEditor::update_tree() {
|
|||
if (type == "")
|
||||
type = "Object";
|
||||
|
||||
ObjectID id = obj->get(p.name);
|
||||
ObjectID id = _get_curent_remote_object_id(p.name);
|
||||
if (id != 0) {
|
||||
item->set_text(1, type + " ID: " + itos(id));
|
||||
item->add_button(1, get_icon("EditResource", "EditorIcons"));
|
||||
|
@ -2993,10 +2994,10 @@ void PropertyEditor::update_tree() {
|
|||
} break;
|
||||
case Variant::DICTIONARY: {
|
||||
|
||||
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_cell_mode(1, TreeItem::CELL_MODE_CUSTOM);
|
||||
item->add_button(1, get_icon("EditResource", "EditorIcons"));
|
||||
Dictionary d = obj->get(p.name);
|
||||
item->set_text(1, "Dictionary{" + itos(d.size()) + "}");
|
||||
} break;
|
||||
|
||||
case Variant::INT_ARRAY: {
|
||||
|
@ -3208,8 +3209,16 @@ void PropertyEditor::update_tree() {
|
|||
type = p.hint_string;
|
||||
|
||||
if (obj->get(p.name).get_type() == Variant::NIL || obj->get(p.name).operator RefPtr().is_null()) {
|
||||
item->set_text(1, "<null>");
|
||||
item->set_icon(1, Ref<Texture>());
|
||||
|
||||
if (Object *_o = obj->get(p.name)) {
|
||||
if (_o->is_type("ScriptEditorDebuggerInspectedObject"))
|
||||
item->set_text(1, _o->call("get_title"));
|
||||
else
|
||||
item->set_text(1, String(_o->get_type_name()) + " ID: " + itos(obj->get_instance_ID()));
|
||||
} else {
|
||||
item->set_text(1, "<null>");
|
||||
item->set_icon(1, Ref<Texture>());
|
||||
}
|
||||
|
||||
} else {
|
||||
RES res = obj->get(p.name).operator RefPtr();
|
||||
|
@ -3331,6 +3340,35 @@ void PropertyEditor::_draw_transparency(Object *t, const Rect2 &p_rect) {
|
|||
tree->draw_rect(area, color);
|
||||
}
|
||||
|
||||
ObjectID PropertyEditor::_get_curent_remote_object_id(const StringName &p_name) {
|
||||
|
||||
ObjectID id = 0;
|
||||
if (obj) {
|
||||
id = obj->get(p_name);
|
||||
if (id == 0) {
|
||||
|
||||
Object *debugObj = NULL;
|
||||
|
||||
if (obj->is_type("ScriptEditorDebuggerVariables")) {
|
||||
if (Object *oo = obj->call("get_var_value", p_name)) {
|
||||
if (oo->is_type("ScriptEditorDebuggerInspectedObject"))
|
||||
debugObj = oo;
|
||||
}
|
||||
} else if (obj->is_type("ScriptEditorDebuggerInspectedObject")) {
|
||||
if (Object *oo = obj->call("get_variant", p_name)) {
|
||||
if (oo->is_type("ScriptEditorDebuggerInspectedObject"))
|
||||
debugObj = oo;
|
||||
}
|
||||
}
|
||||
if (debugObj) {
|
||||
id = debugObj->call("get_remote_object_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void PropertyEditor::_item_selected() {
|
||||
|
||||
TreeItem *item = tree->get_selected();
|
||||
|
@ -3573,12 +3611,16 @@ void PropertyEditor::edit(Object *p_object) {
|
|||
|
||||
if (obj == p_object)
|
||||
return;
|
||||
|
||||
obj = p_object;
|
||||
|
||||
if (obj) {
|
||||
|
||||
obj->remove_change_receptor(this);
|
||||
}
|
||||
|
||||
obj = p_object;
|
||||
if (obj->is_type("ScriptEditorDebuggerInspectedObject"))
|
||||
set_enable_capitalize_paths(false);
|
||||
}
|
||||
|
||||
evaluator->edit(p_object);
|
||||
|
||||
|
@ -3687,15 +3729,24 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
|
|||
|
||||
} else if (t == Variant::OBJECT) {
|
||||
|
||||
RES r = obj->get(n);
|
||||
if (r.is_valid()) {
|
||||
Variant var = obj->get(n);
|
||||
|
||||
RES r = var;
|
||||
if (r.is_valid()) {
|
||||
emit_signal("resource_selected", r, n);
|
||||
} else if (Object *o = var) {
|
||||
// Remote object clicked form property editor cell
|
||||
if (o->is_type("ScriptEditorDebuggerInspectedObject")) {
|
||||
ObjectID id = o->call("get_remote_object_id");
|
||||
emit_signal("object_id_selected", id);
|
||||
print_line(String("OBJ ID SELECTED: ") + itos(id));
|
||||
}
|
||||
}
|
||||
} else if (t == Variant::INT && h == PROPERTY_HINT_OBJECT_ID) {
|
||||
|
||||
emit_signal("object_id_selected", obj->get(n));
|
||||
print_line("OBJ ID SELECTED");
|
||||
ObjectID id = _get_curent_remote_object_id(n);
|
||||
emit_signal("object_id_selected", id);
|
||||
print_line(String("OBJ ID SELECTED: ") + itos(id));
|
||||
|
||||
} else if (t == Variant::ARRAY || t == Variant::INT_ARRAY || t == Variant::REAL_ARRAY || t == Variant::STRING_ARRAY || t == Variant::VECTOR2_ARRAY || t == Variant::VECTOR3_ARRAY || t == Variant::COLOR_ARRAY || t == Variant::RAW_ARRAY) {
|
||||
|
||||
|
@ -3710,6 +3761,11 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
|
|||
ape->edit(obj, n, Variant::Type(t));
|
||||
|
||||
EditorNode::get_singleton()->push_item(ape.ptr());
|
||||
} else if (t == Variant::DICTIONARY) {
|
||||
|
||||
Ref<DictionaryPropertyEdit> dpe = memnew(DictionaryPropertyEdit);
|
||||
dpe->edit(obj, n);
|
||||
EditorNode::get_singleton()->push_item(dpe.ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,6 +236,8 @@ class PropertyEditor : public Control {
|
|||
void _resource_preview_done(const String &p_path, const Ref<Texture> &p_preview, Variant p_ud);
|
||||
void _draw_transparency(Object *t, const Rect2 &p_rect);
|
||||
|
||||
ObjectID _get_curent_remote_object_id(const StringName &p_name);
|
||||
|
||||
UndoRedo *undo_redo;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "script_editor_debugger.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "editor_node.h"
|
||||
#include "editor_profiler.h"
|
||||
#include "editor_settings.h"
|
||||
|
@ -55,9 +56,17 @@ class ScriptEditorDebuggerVariables : public Object {
|
|||
protected:
|
||||
bool _set(const StringName &p_name, const Variant &p_value) {
|
||||
|
||||
#if 0 // Modify stack atomic variables is not supported yet
|
||||
if(values.has(p_name)) {
|
||||
|
||||
emit_signal("value_edited", p_name, p_value);
|
||||
values[p_name] = p_value;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const {
|
||||
|
||||
if (!values.has(p_name))
|
||||
|
@ -67,10 +76,19 @@ protected:
|
|||
}
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const {
|
||||
|
||||
p_list->clear();
|
||||
for (const List<PropertyInfo>::Element *E = props.front(); E; E = E->next())
|
||||
p_list->push_back(E->get());
|
||||
}
|
||||
|
||||
static void _bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("clear"), &ScriptEditorDebuggerVariables::clear);
|
||||
ObjectTypeDB::bind_method(_MD("get_var_value"), &ScriptEditorDebuggerVariables::get_var_value);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("value_edited"));
|
||||
}
|
||||
|
||||
public:
|
||||
void clear() {
|
||||
|
||||
|
@ -78,34 +96,30 @@ public:
|
|||
values.clear();
|
||||
}
|
||||
|
||||
String get_var_value(const String &p_var) const {
|
||||
Variant 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);
|
||||
if (v == p_var)
|
||||
return E->get();
|
||||
}
|
||||
Variant var;
|
||||
if (values.has(p_var))
|
||||
var = values[p_var];
|
||||
|
||||
return "";
|
||||
return var;
|
||||
}
|
||||
|
||||
void add_property(const String &p_name, const Variant &p_value, const PropertyHint &p_hint, const String p_hint_string) {
|
||||
void add_property(const PropertyInfo &p_info, const Variant &p_value) {
|
||||
|
||||
PropertyInfo pinfo;
|
||||
pinfo.name = p_name;
|
||||
pinfo.type = p_value.get_type();
|
||||
pinfo.hint = p_hint;
|
||||
pinfo.hint_string = p_hint_string;
|
||||
props.push_back(pinfo);
|
||||
values[p_name] = p_value;
|
||||
props.push_back(p_info);
|
||||
values[p_info.name] = p_value;
|
||||
}
|
||||
|
||||
void update() {
|
||||
_change_notify();
|
||||
}
|
||||
|
||||
ScriptEditorDebuggerVariables() {
|
||||
void update_single(const char *p_prop) {
|
||||
_change_notify(p_prop);
|
||||
}
|
||||
|
||||
ScriptEditorDebuggerVariables() {}
|
||||
};
|
||||
|
||||
class ScriptEditorDebuggerInspectedObject : public Object {
|
||||
|
@ -115,14 +129,13 @@ 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);
|
||||
prop_values[p_name] = p_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const {
|
||||
|
||||
if (!prop_values.has(p_name))
|
||||
|
@ -141,23 +154,52 @@ protected:
|
|||
|
||||
static void _bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("get_title"), &ScriptEditorDebuggerInspectedObject::get_title);
|
||||
ObjectTypeDB::bind_method(_MD("get_variant"), &ScriptEditorDebuggerInspectedObject::get_variant);
|
||||
ObjectTypeDB::bind_method(_MD("clear"), &ScriptEditorDebuggerInspectedObject::clear);
|
||||
ObjectTypeDB::bind_method(_MD("get_remote_object_id"), &ScriptEditorDebuggerInspectedObject::get_remote_object_id);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("value_edited"));
|
||||
}
|
||||
|
||||
public:
|
||||
ObjectID last_edited_id;
|
||||
ObjectID remote_object_id;
|
||||
List<PropertyInfo> prop_list;
|
||||
Map<StringName, Variant> prop_values;
|
||||
StringName type_name;
|
||||
|
||||
ObjectID get_remote_object_id() {
|
||||
return remote_object_id;
|
||||
}
|
||||
|
||||
String get_title() {
|
||||
if (remote_object_id)
|
||||
return String(type_name) + " ID: " + 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() {
|
||||
|
@ -258,6 +300,16 @@ void ScriptEditorDebugger::_scene_tree_property_value_edited(const String &p_pro
|
|||
inspect_edited_object_timeout = 0.7; //avoid annoyance, don't request soon after editing
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_scene_tree_variable_value_edited(const String &p_prop, const Variant &p_value) {
|
||||
|
||||
Array msg;
|
||||
msg.push_back("set_variable_value");
|
||||
msg.push_back(p_prop);
|
||||
msg.push_back(p_value);
|
||||
ppeer->put_var(msg);
|
||||
inspect_edited_object_timeout = 0.7; //avoid annoyance, don't request soon after editing
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_scene_tree_property_select_object(ObjectID p_object) {
|
||||
|
||||
inspected_object_id = p_object;
|
||||
|
@ -293,10 +345,15 @@ Size2 ScriptEditorDebugger::get_minimum_size() const {
|
|||
ms.y = MAX(ms.y, 250);
|
||||
return ms;
|
||||
}
|
||||
|
||||
Variant _unserial_variant(const DVector<uint8_t> &data, PropertyInfo &r_info);
|
||||
|
||||
void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) {
|
||||
|
||||
if (p_msg == "debug_enter") {
|
||||
|
||||
_clear_remote_objects();
|
||||
|
||||
Array msg;
|
||||
msg.push_back("get_stack_dump");
|
||||
ppeer->put_var(msg);
|
||||
|
@ -324,6 +381,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
|
||||
} else if (p_msg == "debug_exit") {
|
||||
|
||||
_clear_remote_objects();
|
||||
|
||||
breaked = false;
|
||||
step->set_disabled(true);
|
||||
next->set_disabled(true);
|
||||
|
@ -392,57 +451,46 @@ 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];
|
||||
|
||||
int idx = 4;
|
||||
|
||||
if (inspected_object->last_edited_id != id) {
|
||||
inspected_object->prop_list.clear();
|
||||
inspected_object->prop_values.clear();
|
||||
if (remote_objects.has(id)) {
|
||||
debugObj = remote_objects[id];
|
||||
} else {
|
||||
debugObj = memnew(ScriptEditorDebuggerInspectedObject);
|
||||
debugObj->remote_object_id = id;
|
||||
debugObj->connect("value_edited", this, "_scene_tree_property_value_edited");
|
||||
}
|
||||
debugObj->clear();
|
||||
|
||||
for (int i = 0; i < prop_count; i++) {
|
||||
String title = String("Object ID: ") + itos(id);
|
||||
debugObj->prop_list.push_back(PropertyInfo(Variant::STRING, title, PROPERTY_HINT_NONE, title, PROPERTY_USAGE_CATEGORY));
|
||||
|
||||
Array props = p_data[1];
|
||||
for (int i = 0; i < props.size(); i++) {
|
||||
|
||||
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;
|
||||
int len = 0;
|
||||
Variant value = _unserialize_variant(props[i], pinfo, len);
|
||||
|
||||
if (value.get_type() == Variant::STRING && pinfo.hint_string == "REMOTE:RES") {
|
||||
|
||||
pinfo.type = Variant::OBJECT;
|
||||
pinfo.hint_string = "";
|
||||
RES res = ResourceLoader::load(value);
|
||||
debugObj->prop_list.push_back(pinfo);
|
||||
debugObj->prop_values[pinfo.name] = ResourceLoader::load(value);
|
||||
} else {
|
||||
pinfo.usage = PROPERTY_USAGE_EDITOR;
|
||||
|
||||
debugObj->prop_list.push_back(pinfo);
|
||||
debugObj->prop_values[pinfo.name] = value;
|
||||
}
|
||||
|
||||
if (inspected_object->last_edited_id != id) {
|
||||
//don't update.. it's the same, instead refresh
|
||||
inspected_object->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->update_single(pinfo.name.ascii().get_data());
|
||||
}
|
||||
|
||||
if (inspected_object->last_edited_id != id) {
|
||||
//only if different
|
||||
inspected_object->update();
|
||||
}
|
||||
|
||||
inspected_object->last_edited_id = id;
|
||||
|
||||
if (tabs->get_current_tab() == 2) {
|
||||
inspect_properties->edit(inspected_object);
|
||||
} else {
|
||||
editor->push_item(inspected_object);
|
||||
}
|
||||
debugObj->update();
|
||||
editor->push_item(debugObj, "");
|
||||
|
||||
} else if (p_msg == "message:video_mem") {
|
||||
|
||||
|
@ -472,6 +520,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
} else if (p_msg == "stack_dump") {
|
||||
|
||||
stack_dump->clear();
|
||||
_clear_remote_objects();
|
||||
|
||||
TreeItem *r = stack_dump->create_item();
|
||||
|
||||
for (int i = 0; i < p_data.size(); i++) {
|
||||
|
@ -495,53 +545,14 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
} else if (p_msg == "stack_frame_vars") {
|
||||
|
||||
variables->clear();
|
||||
_clear_remote_objects();
|
||||
|
||||
int ofs = 0;
|
||||
int mcount = p_data[ofs];
|
||||
for (int i = 0; i < p_data.size(); i++) {
|
||||
|
||||
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("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("locals/" + n, v, h, hs);
|
||||
PropertyInfo pinfo;
|
||||
int len = 0;
|
||||
Variant value = _unserialize_variant(p_data[i], pinfo, len);
|
||||
variables->add_property(pinfo, value);
|
||||
}
|
||||
|
||||
variables->update();
|
||||
|
@ -757,6 +768,129 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
|||
}
|
||||
}
|
||||
|
||||
Variant __get_value_from_buff_at_pos(Variant::Type type, const DVector<uint8_t> &buff, int pos, int &r_len) {
|
||||
|
||||
Variant v;
|
||||
ERR_FAIL_COND_V(pos >= buff.size(), v);
|
||||
|
||||
int size = 0;
|
||||
switch (type) {
|
||||
case Variant::INT:
|
||||
v = decode_uint32(&buff.read()[pos]);
|
||||
size += sizeof(uint32_t);
|
||||
break;
|
||||
case Variant::BOOL:
|
||||
v = bool(decode_uint32(&buff.read()[pos]));
|
||||
size += sizeof(uint32_t);
|
||||
break;
|
||||
case Variant::REAL:
|
||||
v = decode_float(&buff.read()[pos]);
|
||||
size += sizeof(uint32_t);
|
||||
break;
|
||||
default:
|
||||
decode_variant(v, &buff.read()[pos], buff.size() - pos, &size);
|
||||
break;
|
||||
}
|
||||
|
||||
r_len += size;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
Variant ScriptEditorDebugger::_unserialize_variant(const DVector<uint8_t> &data, PropertyInfo &r_info, int &r_len) {
|
||||
|
||||
Variant v;
|
||||
int read_len = 0;
|
||||
|
||||
if (const int len_max = data.size()) {
|
||||
|
||||
r_info.name = __get_value_from_buff_at_pos(Variant::STRING, data, read_len, read_len);
|
||||
r_info.type = Variant::Type((int)__get_value_from_buff_at_pos(Variant::INT, data, read_len, read_len));
|
||||
r_info.hint = PropertyHint((int)__get_value_from_buff_at_pos(Variant::INT, data, read_len, read_len));
|
||||
r_info.usage = __get_value_from_buff_at_pos(Variant::INT, data, read_len, read_len);
|
||||
|
||||
ScriptEditorDebuggerInspectedObject *eobj = NULL;
|
||||
|
||||
switch (r_info.type) {
|
||||
case Variant::INT: {
|
||||
v = __get_value_from_buff_at_pos(Variant::INT, data, read_len, read_len);
|
||||
|
||||
if (r_info.hint == PROPERTY_HINT_OBJECT_ID) {
|
||||
|
||||
ObjectID eid = v;
|
||||
|
||||
if (remote_objects.has(eid))
|
||||
eobj = remote_objects[eid];
|
||||
else {
|
||||
eobj = memnew(ScriptEditorDebuggerInspectedObject);
|
||||
eobj->connect("value_edited", this, "_scene_tree_property_value_edited");
|
||||
eobj->remote_object_id = eid;
|
||||
remote_objects[eid] = eobj;
|
||||
}
|
||||
|
||||
v = eobj;
|
||||
}
|
||||
} break;
|
||||
case Variant::ARRAY: {
|
||||
int size = __get_value_from_buff_at_pos(Variant::INT, data, read_len, read_len);
|
||||
|
||||
ERR_BREAK(size < 0);
|
||||
|
||||
Array arr;
|
||||
arr.resize(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
int len = data.size() - read_len;
|
||||
ERR_BREAK(len < 0);
|
||||
DVector<uint8_t> ebuff = __get_value_from_buff_at_pos(Variant::RAW_ARRAY, data, read_len, read_len);
|
||||
PropertyInfo pi;
|
||||
arr[i] = _unserialize_variant(ebuff, pi, len);
|
||||
}
|
||||
|
||||
v = arr;
|
||||
} break;
|
||||
case Variant::DICTIONARY: {
|
||||
int size = __get_value_from_buff_at_pos(Variant::INT, data, read_len, read_len);
|
||||
|
||||
ERR_BREAK(size < 0);
|
||||
|
||||
Dictionary dict;
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
||||
int len = data.size() - read_len;
|
||||
ERR_BREAK(len < 0);
|
||||
|
||||
PropertyInfo pi;
|
||||
DVector<uint8_t> tmpbuff = __get_value_from_buff_at_pos(Variant::RAW_ARRAY, data, read_len, read_len);
|
||||
Variant key = _unserialize_variant(tmpbuff, pi, len);
|
||||
|
||||
len = data.size() - read_len;
|
||||
ERR_BREAK(len < 0);
|
||||
|
||||
tmpbuff = __get_value_from_buff_at_pos(Variant::RAW_ARRAY, data, read_len, read_len);
|
||||
Variant value = _unserialize_variant(tmpbuff, pi, len);
|
||||
|
||||
dict[key] = value;
|
||||
}
|
||||
v = dict;
|
||||
} break;
|
||||
default:
|
||||
v = __get_value_from_buff_at_pos(r_info.type, data, read_len, read_len);
|
||||
break;
|
||||
}
|
||||
|
||||
r_info.hint_string = __get_value_from_buff_at_pos(Variant::STRING, data, read_len, read_len);
|
||||
|
||||
if (eobj) {
|
||||
eobj->type_name = r_info.hint_string;
|
||||
}
|
||||
}
|
||||
|
||||
r_len = read_len;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_performance_select(Object *, int, bool) {
|
||||
|
||||
perf_draw->update();
|
||||
|
@ -986,7 +1120,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
|
|||
ERR_FAIL_COND(ret != OK);
|
||||
}
|
||||
if (cmd.get_type() != Variant::STRING) {
|
||||
stop();
|
||||
//stop();
|
||||
ERR_FAIL_COND(cmd.get_type() != Variant::STRING);
|
||||
}
|
||||
|
||||
|
@ -995,11 +1129,11 @@ void ScriptEditorDebugger::_notification(int p_what) {
|
|||
|
||||
ret = ppeer->get_var(cmd);
|
||||
if (ret != OK) {
|
||||
stop();
|
||||
//stop();
|
||||
ERR_FAIL_COND(ret != OK);
|
||||
}
|
||||
if (cmd.get_type() != Variant::INT) {
|
||||
stop();
|
||||
//stop();
|
||||
ERR_FAIL_COND(cmd.get_type() != Variant::INT);
|
||||
}
|
||||
|
||||
|
@ -1053,6 +1187,8 @@ void ScriptEditorDebugger::stop() {
|
|||
|
||||
set_process(false);
|
||||
|
||||
_clear_remote_objects();
|
||||
|
||||
server->stop();
|
||||
|
||||
ppeer->set_stream_peer(Ref<StreamPeer>());
|
||||
|
@ -1530,6 +1666,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() {
|
||||
|
||||
inspector->edit(NULL);
|
||||
inspect_properties->edit(NULL);
|
||||
|
||||
for (Map<ObjectID, ScriptEditorDebuggerInspectedObject *>::Element *E = remote_objects.front(); E; E = E->next()) {
|
||||
memdelete(E->value());
|
||||
}
|
||||
remote_objects.clear();
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_stack_dump_frame_selected"), &ScriptEditorDebugger::_stack_dump_frame_selected);
|
||||
|
@ -1564,6 +1718,7 @@ void ScriptEditorDebugger::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("live_debug_reparent_node"), &ScriptEditorDebugger::live_debug_reparent_node);
|
||||
ObjectTypeDB::bind_method(_MD("_scene_tree_property_select_object"), &ScriptEditorDebugger::_scene_tree_property_select_object);
|
||||
ObjectTypeDB::bind_method(_MD("_scene_tree_property_value_edited"), &ScriptEditorDebugger::_scene_tree_property_value_edited);
|
||||
ObjectTypeDB::bind_method(_MD("_scene_tree_variable_value_edited"), &ScriptEditorDebugger::_scene_tree_variable_value_edited);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("goto_script_line"));
|
||||
ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "reallydid"), PropertyInfo(Variant::BOOL, "can_debug")));
|
||||
|
@ -1573,7 +1728,10 @@ void ScriptEditorDebugger::_bind_methods() {
|
|||
ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
|
||||
|
||||
ppeer = Ref<PacketPeerStream>(memnew(PacketPeerStream));
|
||||
ppeer->set_input_buffer_max_size(pow(2, 20));
|
||||
|
||||
editor = p_editor;
|
||||
editor->get_property_editor()->connect("object_id_selected", this, "_scene_tree_property_select_object");
|
||||
|
||||
tabs = memnew(TabContainer);
|
||||
tabs->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
|
@ -1660,6 +1818,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
|
|||
pending_in_queue = 0;
|
||||
|
||||
variables = memnew(ScriptEditorDebuggerVariables);
|
||||
variables->connect("value_edited", this, "_scene_tree_variable_value_edited");
|
||||
|
||||
breaked = false;
|
||||
|
||||
|
@ -1704,14 +1863,12 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
|
|||
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->hide_top_label();
|
||||
inspect_properties->set_show_categories(true);
|
||||
inspect_properties->connect("object_id_selected", this, "_scene_tree_property_select_object");
|
||||
|
||||
|
@ -1721,9 +1878,6 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
|
|||
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
|
||||
|
@ -1874,5 +2028,5 @@ ScriptEditorDebugger::~ScriptEditorDebugger() {
|
|||
ppeer->set_stream_peer(Ref<StreamPeer>());
|
||||
|
||||
server->stop();
|
||||
memdelete(inspected_object);
|
||||
_clear_remote_objects();
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ class ScriptEditorDebugger : public Control {
|
|||
float inspect_scene_tree_timeout;
|
||||
float inspect_edited_object_timeout;
|
||||
ObjectID inspected_object_id;
|
||||
ScriptEditorDebuggerInspectedObject *inspected_object;
|
||||
Map<ObjectID, ScriptEditorDebuggerInspectedObject *> remote_objects;
|
||||
bool updating_scene_tree;
|
||||
Set<ObjectID> unfold_cache;
|
||||
|
||||
|
@ -142,9 +142,10 @@ class ScriptEditorDebugger : public Control {
|
|||
void _scene_tree_selected();
|
||||
void _scene_tree_request();
|
||||
void _parse_message(const String &p_msg, const Array &p_data);
|
||||
Variant _unserialize_variant(const DVector<uint8_t> &data, PropertyInfo &r_info, int &r_len);
|
||||
void _scene_tree_property_select_object(ObjectID p_object);
|
||||
void _scene_tree_property_value_edited(const String &p_prop, const Variant &p_value);
|
||||
|
||||
void _scene_tree_variable_value_edited(const String &p_prop, const Variant &p_value);
|
||||
void _video_mem_request();
|
||||
|
||||
int _get_node_path_cache(const NodePath &p_path);
|
||||
|
@ -168,6 +169,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();
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
/*************************************************************************/
|
||||
#include "gd_compiler.h"
|
||||
#include "gd_script.h"
|
||||
#include "global_constants.h"
|
||||
#include "globals.h"
|
||||
#include "os/file_access.h"
|
||||
|
||||
|
@ -242,9 +243,47 @@ 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;
|
||||
GDInstance *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();
|
||||
|
||||
for (const Map<StringName, int>::Element *E = name_idx.front(); E; E = E->next()) {
|
||||
|
||||
if (ObjectTypeDB::type_exists(E->key()) || Globals::get_singleton()->has_singleton(E->key()) || E->key() == "PI")
|
||||
continue;
|
||||
|
||||
const Variant &var = globals[E->value()];
|
||||
if (Object *obj = var) {
|
||||
if (obj->cast_to<GDNativeClass>())
|
||||
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) {
|
||||
|
||||
|
|
|
@ -138,8 +138,8 @@ public:
|
|||
bool is_valid() const { return valid; }
|
||||
|
||||
const Map<StringName, Ref<GDScript> > &get_subclasses() const { return subclasses; }
|
||||
const Map<StringName, Variant> &get_constants() const { return constants; }
|
||||
const Set<StringName> &get_members() const { return members; }
|
||||
virtual const Map<StringName, Variant> &get_constants() const { return constants; }
|
||||
virtual const Set<StringName> &get_members() const { return members; }
|
||||
const Map<StringName, GDFunction *> &get_member_functions() const { return member_functions; }
|
||||
const Ref<GDNativeClass> &get_native() const { return native; }
|
||||
|
||||
|
@ -199,7 +199,7 @@ class GDInstance : 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;
|
||||
|
@ -374,7 +374,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 void debug_get_globals(List<String> *p_globals, 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 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();
|
||||
|
|
Loading…
Reference in New Issue