Browse Source

-Properly check limits to objects sent (regarding to size), fixes #9034
-Changed the way objects are marshalled and sent to the debugger
-Editing debugged objects happens in the remote inspector now

Juan Linietsky 8 years ago
parent
commit
dc62389739

+ 133 - 73
core/io/marshalls.cpp

@@ -33,8 +33,28 @@
 #include "reference.h"
 #include "reference.h"
 #include <stdio.h>
 #include <stdio.h>
 
 
+void EncodedObjectAsID::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_object_id", "id"), &EncodedObjectAsID::set_object_id);
+	ClassDB::bind_method(D_METHOD("get_object_id"), &EncodedObjectAsID::get_object_id);
+}
+
+void EncodedObjectAsID::set_object_id(ObjectID p_id) {
+	id = p_id;
+}
+
+ObjectID EncodedObjectAsID::get_object_id() const {
+
+	return id;
+}
+
+EncodedObjectAsID::EncodedObjectAsID() {
+
+	id = 0;
+}
+
 #define ENCODE_MASK 0xFF
 #define ENCODE_MASK 0xFF
 #define ENCODE_FLAG_64 1 << 16
 #define ENCODE_FLAG_64 1 << 16
+#define ENCODE_FLAG_OBJECT_AS_ID 1 << 16
 
 
 static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r_string) {
 static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r_string) {
 	ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
 	ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
@@ -381,56 +401,74 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
 		} break;
 		} break;
 		case Variant::OBJECT: {
 		case Variant::OBJECT: {
 
 
-			ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED);
-
-			String str;
-			Error err = _decode_string(buf, len, r_len, str);
-			if (err)
-				return err;
+			if (type & ENCODE_FLAG_OBJECT_AS_ID) {
+				//this _is_ allowed
+				ObjectID val = decode_uint64(buf);
+				if (r_len)
+					(*r_len) += 8;
 
 
-			if (str == String()) {
-				r_variant = (Object *)NULL;
-			} else {
+				if (val == 0) {
+					r_variant = (Object *)NULL;
+				} else {
+					Ref<EncodedObjectAsID> obj_as_id;
+					obj_as_id.instance();
+					obj_as_id->set_object_id(val);
 
 
-				Object *obj = ClassDB::instance(str);
+					r_variant = obj_as_id;
+				}
 
 
-				ERR_FAIL_COND_V(!obj, ERR_UNAVAILABLE);
-				ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
+			} else {
+				ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED);
 
 
-				int32_t count = decode_uint32(buf);
-				buf += 4;
-				len -= 4;
-				if (r_len) {
-					(*r_len) += 4;
-				}
+				String str;
+				Error err = _decode_string(buf, len, r_len, str);
+				if (err)
+					return err;
 
 
-				for (int i = 0; i < count; i++) {
+				if (str == String()) {
+					r_variant = (Object *)NULL;
+				} else {
 
 
-					str = String();
-					err = _decode_string(buf, len, r_len, str);
-					if (err)
-						return err;
+					Object *obj = ClassDB::instance(str);
 
 
-					Variant value;
-					int used;
-					err = decode_variant(value, buf, len, &used, p_allow_objects);
-					if (err)
-						return err;
+					ERR_FAIL_COND_V(!obj, ERR_UNAVAILABLE);
+					ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
 
 
-					buf += used;
-					len -= used;
+					int32_t count = decode_uint32(buf);
+					buf += 4;
+					len -= 4;
 					if (r_len) {
 					if (r_len) {
-						(*r_len) += used;
+						(*r_len) += 4;
 					}
 					}
 
 
-					obj->set(str, value);
-				}
+					for (int i = 0; i < count; i++) {
 
 
-				if (obj->cast_to<Reference>()) {
-					REF ref = REF(obj->cast_to<Reference>());
-					r_variant = ref;
-				} else {
-					r_variant = obj;
+						str = String();
+						err = _decode_string(buf, len, r_len, str);
+						if (err)
+							return err;
+
+						Variant value;
+						int used;
+						err = decode_variant(value, buf, len, &used, p_allow_objects);
+						if (err)
+							return err;
+
+						buf += used;
+						len -= used;
+						if (r_len) {
+							(*r_len) += used;
+						}
+
+						obj->set(str, value);
+					}
+
+					if (obj->cast_to<Reference>()) {
+						REF ref = REF(obj->cast_to<Reference>());
+						r_variant = ref;
+					} else {
+						r_variant = obj;
+					}
 				}
 				}
 			}
 			}
 
 
@@ -776,7 +814,7 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) {
 		r_len++; //pad
 		r_len++; //pad
 }
 }
 
 
-Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
+Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_object_as_id) {
 
 
 	uint8_t *buf = r_buffer;
 	uint8_t *buf = r_buffer;
 
 
@@ -800,6 +838,11 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
 				flags |= ENCODE_FLAG_64; //always encode real as double
 				flags |= ENCODE_FLAG_64; //always encode real as double
 			}
 			}
 		} break;
 		} break;
+		case Variant::OBJECT: {
+			if (p_object_as_id) {
+				flags |= ENCODE_FLAG_OBJECT_AS_ID;
+			}
+		} break;
 	}
 	}
 
 
 	if (buf) {
 	if (buf) {
@@ -1071,49 +1114,66 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
 		} break;
 		} break;
 		case Variant::OBJECT: {
 		case Variant::OBJECT: {
 
 
-			Object *obj = p_variant;
-			if (!obj) {
+			if (p_object_as_id) {
+
 				if (buf) {
 				if (buf) {
-					encode_uint32(0, buf);
-					buf += 4;
-					r_len += 4;
+
+					Object *obj = p_variant;
+					ObjectID id = 0;
+					if (obj && ObjectDB::instance_validate(obj)) {
+						id = obj->get_instance_id();
+					}
+
+					encode_uint64(id, buf);
 				}
 				}
+
+				r_len += 8;
+
 			} else {
 			} else {
-				_encode_string(obj->get_class(), buf, r_len);
+				Object *obj = p_variant;
+				if (!obj) {
+					if (buf) {
+						encode_uint32(0, buf);
+						buf += 4;
+						r_len += 4;
+					}
+				} else {
+					_encode_string(obj->get_class(), buf, r_len);
 
 
-				List<PropertyInfo> props;
-				obj->get_property_list(&props);
+					List<PropertyInfo> props;
+					obj->get_property_list(&props);
 
 
-				int pc = 0;
-				for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+					int pc = 0;
+					for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
 
 
-					if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
-						continue;
-					pc++;
-				}
+						if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
+							continue;
+						pc++;
+					}
 
 
-				if (buf) {
-					encode_uint32(pc, buf);
-					buf += 4;
-				}
+					if (buf) {
+						encode_uint32(pc, buf);
+						buf += 4;
+					}
 
 
-				r_len += 4;
+					r_len += 4;
 
 
-				for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+					for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
 
 
-					if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
-						continue;
+						if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
+							continue;
 
 
-					_encode_string(E->get().name, buf, r_len);
+						_encode_string(E->get().name, buf, r_len);
 
 
-					int len;
-					Error err = encode_variant(obj->get(E->get().name), buf, len);
-					if (err)
-						return err;
-					ERR_FAIL_COND_V(len % 4, ERR_BUG);
-					r_len += len;
-					if (buf)
-						buf += len;
+						int len;
+						Error err = encode_variant(obj->get(E->get().name), buf, len, p_object_as_id);
+						if (err)
+							return err;
+						ERR_FAIL_COND_V(len % 4, ERR_BUG);
+						r_len += len;
+						if (buf)
+							buf += len;
+					}
 				}
 				}
 			}
 			}
 
 
@@ -1147,12 +1207,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
 					r_len++; //pad
 					r_len++; //pad
 				*/
 				*/
 				int len;
 				int len;
-				encode_variant(E->get(), buf, len);
+				encode_variant(E->get(), buf, len, p_object_as_id);
 				ERR_FAIL_COND_V(len % 4, ERR_BUG);
 				ERR_FAIL_COND_V(len % 4, ERR_BUG);
 				r_len += len;
 				r_len += len;
 				if (buf)
 				if (buf)
 					buf += len;
 					buf += len;
-				encode_variant(d[E->get()], buf, len);
+				encode_variant(d[E->get()], buf, len, p_object_as_id);
 				ERR_FAIL_COND_V(len % 4, ERR_BUG);
 				ERR_FAIL_COND_V(len % 4, ERR_BUG);
 				r_len += len;
 				r_len += len;
 				if (buf)
 				if (buf)
@@ -1174,7 +1234,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
 			for (int i = 0; i < v.size(); i++) {
 			for (int i = 0; i < v.size(); i++) {
 
 
 				int len;
 				int len;
-				encode_variant(v.get(i), buf, len);
+				encode_variant(v.get(i), buf, len, p_object_as_id);
 				ERR_FAIL_COND_V(len % 4, ERR_BUG);
 				ERR_FAIL_COND_V(len % 4, ERR_BUG);
 				r_len += len;
 				r_len += len;
 				if (buf)
 				if (buf)

+ 18 - 3
core/io/marshalls.h

@@ -32,8 +32,8 @@
 
 
 #include "typedefs.h"
 #include "typedefs.h"
 
 
+#include "reference.h"
 #include "variant.h"
 #include "variant.h"
-
 /**
 /**
   * Miscellaneous helpers for marshalling data types, and encoding
   * Miscellaneous helpers for marshalling data types, and encoding
   * in an endian independent way
   * in an endian independent way
@@ -183,7 +183,22 @@ static inline double decode_double(const uint8_t *p_arr) {
 	return md.d;
 	return md.d;
 }
 }
 
 
-Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects=true);
-Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len);
+class EncodedObjectAsID : public Reference {
+	GDCLASS(EncodedObjectAsID, Reference);
+
+	ObjectID id;
+
+protected:
+	static void _bind_methods();
+
+public:
+	void set_object_id(ObjectID p_id);
+	ObjectID get_object_id() const;
+
+	EncodedObjectAsID();
+};
+
+Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects = true);
+Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_object_as_id = false);
 
 
 #endif
 #endif

+ 14 - 2
core/io/packet_peer.cpp

@@ -92,7 +92,7 @@ Error PacketPeer::get_var(Variant &r_variant) const {
 Error PacketPeer::put_var(const Variant &p_packet) {
 Error PacketPeer::put_var(const Variant &p_packet) {
 
 
 	int len;
 	int len;
-	Error err = encode_variant(p_packet, NULL, len); // compute len first
+	Error err = encode_variant(p_packet, NULL, len, !allow_object_decoding); // compute len first
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
@@ -101,7 +101,7 @@ Error PacketPeer::put_var(const Variant &p_packet) {
 
 
 	uint8_t *buf = (uint8_t *)alloca(len);
 	uint8_t *buf = (uint8_t *)alloca(len);
 	ERR_FAIL_COND_V(!buf, ERR_OUT_OF_MEMORY);
 	ERR_FAIL_COND_V(!buf, ERR_OUT_OF_MEMORY);
-	err = encode_variant(p_packet, buf, len);
+	err = encode_variant(p_packet, buf, len, !allow_object_decoding);
 	ERR_FAIL_COND_V(err, err);
 	ERR_FAIL_COND_V(err, err);
 
 
 	return put_packet(buf, len);
 	return put_packet(buf, len);
@@ -155,6 +155,8 @@ void PacketPeerStream::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_stream_peer", "peer"), &PacketPeerStream::_set_stream_peer);
 	ClassDB::bind_method(D_METHOD("set_stream_peer", "peer"), &PacketPeerStream::_set_stream_peer);
 	ClassDB::bind_method(D_METHOD("set_input_buffer_max_size", "max_size_bytes"), &PacketPeerStream::set_input_buffer_max_size);
 	ClassDB::bind_method(D_METHOD("set_input_buffer_max_size", "max_size_bytes"), &PacketPeerStream::set_input_buffer_max_size);
 	ClassDB::bind_method(D_METHOD("set_output_buffer_max_size", "max_size_bytes"), &PacketPeerStream::set_output_buffer_max_size);
 	ClassDB::bind_method(D_METHOD("set_output_buffer_max_size", "max_size_bytes"), &PacketPeerStream::set_output_buffer_max_size);
+	ClassDB::bind_method(D_METHOD("get_input_buffer_max_size"), &PacketPeerStream::get_input_buffer_max_size);
+	ClassDB::bind_method(D_METHOD("get_output_buffer_max_size"), &PacketPeerStream::get_output_buffer_max_size);
 }
 }
 
 
 Error PacketPeerStream::_poll_buffer() const {
 Error PacketPeerStream::_poll_buffer() const {
@@ -268,11 +270,21 @@ void PacketPeerStream::set_input_buffer_max_size(int p_max_size) {
 	input_buffer.resize(next_power_of_2(p_max_size + 4));
 	input_buffer.resize(next_power_of_2(p_max_size + 4));
 }
 }
 
 
+int PacketPeerStream::get_input_buffer_max_size() const {
+
+	return input_buffer.size() - 4;
+}
+
 void PacketPeerStream::set_output_buffer_max_size(int p_max_size) {
 void PacketPeerStream::set_output_buffer_max_size(int p_max_size) {
 
 
 	output_buffer.resize(next_power_of_2(p_max_size + 4));
 	output_buffer.resize(next_power_of_2(p_max_size + 4));
 }
 }
 
 
+int PacketPeerStream::get_output_buffer_max_size() const {
+
+	return output_buffer.size() - 4;
+}
+
 PacketPeerStream::PacketPeerStream() {
 PacketPeerStream::PacketPeerStream() {
 
 
 	int rbsize = GLOBAL_GET("network/limits/packet_peer_stream/max_buffer_po2");
 	int rbsize = GLOBAL_GET("network/limits/packet_peer_stream/max_buffer_po2");

+ 2 - 0
core/io/packet_peer.h

@@ -98,7 +98,9 @@ public:
 
 
 	void set_stream_peer(const Ref<StreamPeer> &p_peer);
 	void set_stream_peer(const Ref<StreamPeer> &p_peer);
 	void set_input_buffer_max_size(int p_max_size);
 	void set_input_buffer_max_size(int p_max_size);
+	int get_input_buffer_max_size() const;
 	void set_output_buffer_max_size(int p_max_size);
 	void set_output_buffer_max_size(int p_max_size);
+	int get_output_buffer_max_size() const;
 	PacketPeerStream();
 	PacketPeerStream();
 };
 };
 
 

+ 1 - 0
core/object.h

@@ -83,6 +83,7 @@ enum PropertyHint {
 	PROPERTY_HINT_PROPERTY_OF_BASE_TYPE, ///< a property of a base type
 	PROPERTY_HINT_PROPERTY_OF_BASE_TYPE, ///< a property of a base type
 	PROPERTY_HINT_PROPERTY_OF_INSTANCE, ///< a property of an instance
 	PROPERTY_HINT_PROPERTY_OF_INSTANCE, ///< a property of an instance
 	PROPERTY_HINT_PROPERTY_OF_SCRIPT, ///< a property of a script & base
 	PROPERTY_HINT_PROPERTY_OF_SCRIPT, ///< a property of a script & base
+	PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send
 	PROPERTY_HINT_MAX,
 	PROPERTY_HINT_MAX,
 };
 };
 
 

+ 2 - 1
core/register_core_types.cpp

@@ -39,6 +39,7 @@
 #include "input_map.h"
 #include "input_map.h"
 #include "io/config_file.h"
 #include "io/config_file.h"
 #include "io/http_client.h"
 #include "io/http_client.h"
+#include "io/marshalls.h"
 #include "io/packet_peer.h"
 #include "io/packet_peer.h"
 #include "io/packet_peer_udp.h"
 #include "io/packet_peer_udp.h"
 #include "io/pck_packer.h"
 #include "io/pck_packer.h"
@@ -56,7 +57,6 @@
 #include "project_settings.h"
 #include "project_settings.h"
 #include "translation.h"
 #include "translation.h"
 #include "undo_redo.h"
 #include "undo_redo.h"
-
 static ResourceFormatSaverBinary *resource_saver_binary = NULL;
 static ResourceFormatSaverBinary *resource_saver_binary = NULL;
 static ResourceFormatLoaderBinary *resource_loader_binary = NULL;
 static ResourceFormatLoaderBinary *resource_loader_binary = NULL;
 static ResourceFormatImporter *resource_format_importer = NULL;
 static ResourceFormatImporter *resource_format_importer = NULL;
@@ -157,6 +157,7 @@ void register_core_types() {
 	ClassDB::register_class<PackedDataContainer>();
 	ClassDB::register_class<PackedDataContainer>();
 	ClassDB::register_virtual_class<PackedDataContainerRef>();
 	ClassDB::register_virtual_class<PackedDataContainerRef>();
 	ClassDB::register_class<AStar>();
 	ClassDB::register_class<AStar>();
+	ClassDB::register_class<EncodedObjectAsID>();
 
 
 	ip = IP::create();
 	ip = IP::create();
 
 

+ 23 - 37
core/script_debugger_remote.cpp

@@ -30,10 +30,10 @@
 #include "script_debugger_remote.h"
 #include "script_debugger_remote.h"
 
 
 #include "io/ip.h"
 #include "io/ip.h"
+#include "io/marshalls.h"
 #include "os/input.h"
 #include "os/input.h"
 #include "os/os.h"
 #include "os/os.h"
 #include "project_settings.h"
 #include "project_settings.h"
-
 void ScriptDebuggerRemote::_send_video_memory() {
 void ScriptDebuggerRemote::_send_video_memory() {
 
 
 	List<ResourceUsage> usage;
 	List<ResourceUsage> usage;
@@ -120,6 +120,18 @@ static ObjectID safe_get_instance_id(const Variant &p_v) {
 	}
 	}
 }
 }
 
 
+void ScriptDebuggerRemote::_put_variable(const String &p_name, const Variant &p_variable) {
+
+	packet_peer_stream->put_var(p_name);
+	int len = 0;
+	Error err = encode_variant(p_variable, NULL, len);
+	if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size
+		packet_peer_stream->put_var(Variant());
+	} else {
+		packet_peer_stream->put_var(p_variable);
+	}
+}
+
 void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) {
 void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) {
 
 
 	//this function is called when there is a debugger break (bug on script)
 	//this function is called when there is a debugger break (bug on script)
@@ -210,14 +222,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue)
 
 
 					while (E) {
 					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());
-						}
+						_put_variable(E->get(), F->get());
 
 
 						E = E->next();
 						E = E->next();
 						F = F->next();
 						F = F->next();
@@ -231,15 +236,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue)
 					List<Variant>::Element *F = local_vals.front();
 					List<Variant>::Element *F = local_vals.front();
 
 
 					while (E) {
 					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());
-						}
+						_put_variable(E->get(), F->get());
 
 
 						E = E->next();
 						E = E->next();
 						F = F->next();
 						F = F->next();
@@ -566,30 +563,19 @@ void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) {
 			}
 			}
 
 
 			Variant var = obj->get(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..
 
 
-			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;
-				}
+			int len = 0; //test how big is this to encode
+			encode_variant(var, NULL, len);
 
 
-				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
+			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 {
 			} 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);
 				packet_peer_stream->put_var(E->get().hint_string);
 				packet_peer_stream->put_var(E->get().hint_string);
-				//only send information that can be sent..
-
-				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(var);
 			}
 			}
 		}
 		}

+ 2 - 0
core/script_debugger_remote.h

@@ -126,6 +126,8 @@ class ScriptDebuggerRemote : public ScriptDebugger {
 
 
 	Vector<FrameData> profile_frame_data;
 	Vector<FrameData> profile_frame_data;
 
 
+	void _put_variable(const String &p_name, const Variant &p_variable);
+
 public:
 public:
 	struct ResourceUsage {
 	struct ResourceUsage {
 
 

+ 27 - 2
editor/property_editor.cpp

@@ -38,6 +38,7 @@
 #include "editor_node.h"
 #include "editor_node.h"
 #include "editor_settings.h"
 #include "editor_settings.h"
 #include "io/image_loader.h"
 #include "io/image_loader.h"
+#include "io/marshalls.h"
 #include "io/resource_loader.h"
 #include "io/resource_loader.h"
 #include "multi_node_edit.h"
 #include "multi_node_edit.h"
 #include "os/input.h"
 #include "os/input.h"
@@ -2320,7 +2321,15 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String &p
 		} break;
 		} break;
 		case Variant::OBJECT: {
 		case Variant::OBJECT: {
 
 
-			if (obj->get(p_name).get_type() == Variant::NIL || obj->get(p_name).operator RefPtr().is_null()) {
+			Ref<EncodedObjectAsID> encoded = obj->get(p_name); //for debugger and remote tools
+
+			if (encoded.is_valid()) {
+
+				p_item->set_text(1, "Object: " + itos(encoded->get_object_id()));
+				p_item->set_icon(1, Ref<Texture>());
+				p_item->set_custom_as_button(1, true);
+
+			} else if (obj->get(p_name).get_type() == Variant::NIL || obj->get(p_name).operator RefPtr().is_null()) {
 				p_item->set_text(1, "<null>");
 				p_item->set_text(1, "<null>");
 				p_item->set_icon(1, Ref<Texture>());
 				p_item->set_icon(1, Ref<Texture>());
 				p_item->set_custom_as_button(1, false);
 				p_item->set_custom_as_button(1, false);
@@ -3610,7 +3619,16 @@ void PropertyEditor::update_tree() {
 
 
 				RES res = obj->get(p.name).operator RefPtr();
 				RES res = obj->get(p.name).operator RefPtr();
 
 
-				if (obj->get(p.name).get_type() == Variant::NIL || res.is_null()) {
+				Ref<EncodedObjectAsID> encoded = obj->get(p.name); //for debugger and remote tools
+
+				if (encoded.is_valid()) {
+
+					item->set_text(1, "Object: " + itos(encoded->get_object_id()));
+					item->set_icon(1, Ref<Texture>());
+					item->set_custom_as_button(1, true);
+					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_text(1, "<null>");
 					item->set_icon(1, Ref<Texture>());
 					item->set_icon(1, Ref<Texture>());
 					item->set_custom_as_button(1, false);
 					item->set_custom_as_button(1, false);
@@ -3939,6 +3957,13 @@ void PropertyEditor::_item_edited() {
 			if (!item->is_custom_set_as_button(1))
 			if (!item->is_custom_set_as_button(1))
 				break;
 				break;
 
 
+			Ref<EncodedObjectAsID> encoded = obj->get(name); //for debugger and remote tools
+
+			if (encoded.is_valid()) {
+
+				emit_signal("object_id_selected", encoded->get_object_id());
+			}
+
 			RES res = obj->get(name);
 			RES res = obj->get(name);
 			if (res.is_valid()) {
 			if (res.is_valid()) {
 				emit_signal("resource_selected", res.get_ref_ptr(), name);
 				emit_signal("resource_selected", res.get_ref_ptr(), name);

+ 9 - 5
editor/script_editor_debugger.cpp

@@ -372,7 +372,13 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
 			if (has_icon(p_data[i + 2], "EditorIcons"))
 			if (has_icon(p_data[i + 2], "EditorIcons"))
 				it->set_icon(0, get_icon(p_data[i + 2], "EditorIcons"));
 				it->set_icon(0, get_icon(p_data[i + 2], "EditorIcons"));
 			it->set_metadata(0, id);
 			it->set_metadata(0, id);
+
 			if (id == inspected_object_id) {
 			if (id == inspected_object_id) {
+				TreeItem *cti = it->get_parent(); //ensure selected is always uncollapsed
+				while (cti) {
+					cti->set_collapsed(false);
+					cti = cti->get_parent();
+				}
 				it->select(0);
 				it->select(0);
 			}
 			}
 
 
@@ -385,6 +391,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
 					it->set_collapsed(true);
 					it->set_collapsed(true);
 				}
 				}
 			}
 			}
+
 			lv[level] = it;
 			lv[level] = it;
 		}
 		}
 		updating_scene_tree = false;
 		updating_scene_tree = false;
@@ -439,11 +446,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
 
 
 		inspected_object->last_edited_id = id;
 		inspected_object->last_edited_id = id;
 
 
-		if (tabs->get_current_tab() == 2) {
-			inspect_properties->edit(inspected_object);
-		} else {
-			editor->push_item(inspected_object);
-		}
+		tabs->set_current_tab(inspect_info->get_index());
+		inspect_properties->edit(inspected_object);
 
 
 	} else if (p_msg == "message:video_mem") {
 	} else if (p_msg == "message:video_mem") {