summaryrefslogtreecommitdiff
path: root/core/object/object.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/object/object.cpp')
-rw-r--r--core/object/object.cpp554
1 files changed, 281 insertions, 273 deletions
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 096edd4e60..540b9a8f19 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -38,6 +38,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
+#include "core/variant/typed_array.h"
#ifdef DEBUG_ENABLED
@@ -102,8 +103,8 @@ PropertyInfo PropertyInfo::from_dict(const Dictionary &p_dict) {
return pi;
}
-Array convert_property_list(const List<PropertyInfo> *p_list) {
- Array va;
+TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list) {
+ TypedArray<Dictionary> va;
for (const List<PropertyInfo>::Element *E = p_list->front(); E; E = E->next()) {
va.push_back(Dictionary(E->get()));
}
@@ -161,167 +162,11 @@ MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) {
return mi;
}
-MethodInfo::MethodInfo() :
- flags(METHOD_FLAG_NORMAL) {}
-
-MethodInfo::MethodInfo(const String &p_name) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
-}
-
-MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
-}
-
-MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
-}
-
-MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
- arguments.push_back(p_param3);
-}
-
-MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
- arguments.push_back(p_param3);
- arguments.push_back(p_param4);
-}
-
-MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
- arguments.push_back(p_param3);
- arguments.push_back(p_param4);
- arguments.push_back(p_param5);
-}
-
-MethodInfo::MethodInfo(Variant::Type ret) :
- flags(METHOD_FLAG_NORMAL) {
- return_val.type = ret;
-}
-
-MethodInfo::MethodInfo(Variant::Type ret, const String &p_name) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- return_val.type = ret;
-}
-
-MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- return_val.type = ret;
- arguments.push_back(p_param1);
-}
-
-MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- return_val.type = ret;
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
-}
-
-MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- return_val.type = ret;
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
- arguments.push_back(p_param3);
-}
-
-MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- return_val.type = ret;
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
- arguments.push_back(p_param3);
- arguments.push_back(p_param4);
-}
-
-MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) :
- name(p_name),
- flags(METHOD_FLAG_NORMAL) {
- return_val.type = ret;
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
- arguments.push_back(p_param3);
- arguments.push_back(p_param4);
- arguments.push_back(p_param5);
-}
-
-MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name) :
- name(p_name),
- return_val(p_ret),
- flags(METHOD_FLAG_NORMAL) {
-}
-
-MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1) :
- name(p_name),
- return_val(p_ret),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
-}
-
-MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) :
- name(p_name),
- return_val(p_ret),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
-}
-
-MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) :
- name(p_name),
- return_val(p_ret),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
- arguments.push_back(p_param3);
-}
-
-MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) :
- name(p_name),
- return_val(p_ret),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
- arguments.push_back(p_param3);
- arguments.push_back(p_param4);
-}
-
-MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) :
- name(p_name),
- return_val(p_ret),
- flags(METHOD_FLAG_NORMAL) {
- arguments.push_back(p_param1);
- arguments.push_back(p_param2);
- arguments.push_back(p_param3);
- arguments.push_back(p_param4);
- arguments.push_back(p_param5);
-}
-
Object::Connection::operator Variant() const {
Dictionary d;
d["signal"] = signal;
d["callable"] = callable;
d["flags"] = flags;
- d["binds"] = binds;
return d;
}
@@ -344,9 +189,6 @@ Object::Connection::Connection(const Variant &p_variant) {
if (d.has("flags")) {
flags = d["flags"];
}
- if (d.has("binds")) {
- binds = d["binds"];
- }
}
bool Object::_predelete() {
@@ -416,21 +258,22 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
return;
- } else if (p_name == CoreStringNames::get_singleton()->_meta) {
- metadata = p_value.duplicate();
- if (r_valid) {
- *r_valid = true;
- }
- return;
- }
-
- // Something inside the object... :|
- bool success = _setv(p_name, p_value);
- if (success) {
- if (r_valid) {
- *r_valid = true;
+ } else {
+ Variant **V = metadata_properties.getptr(p_name);
+ if (V) {
+ **V = p_value;
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return;
+ } else if (p_name.operator String().begins_with("metadata/")) {
+ // Must exist, otherwise duplicate() will not work.
+ set_meta(p_name.operator String().replace_first("metadata/", ""), p_value);
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return;
}
- return;
}
#ifdef TOOLS_ENABLED
@@ -446,6 +289,15 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
#endif
+ // Something inside the object... :|
+ bool success = _setv(p_name, p_value);
+ if (success) {
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return;
+ }
+
if (r_valid) {
*r_valid = false;
}
@@ -496,24 +348,18 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
*r_valid = true;
}
return ret;
+ }
- } else if (p_name == CoreStringNames::get_singleton()->_meta) {
- ret = metadata;
+ const Variant *const *V = metadata_properties.getptr(p_name);
+
+ if (V) {
+ ret = **V;
if (r_valid) {
*r_valid = true;
}
return ret;
} else {
- // Something inside the object... :|
- bool success = _getv(p_name, ret);
- if (success) {
- if (r_valid) {
- *r_valid = true;
- }
- return ret;
- }
-
#ifdef TOOLS_ENABLED
if (script_instance) {
bool valid;
@@ -526,6 +372,14 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
}
}
#endif
+ // Something inside the object... :|
+ bool success = _getv(p_name, ret);
+ if (success) {
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return ret;
+ }
if (r_valid) {
*r_valid = false;
@@ -619,7 +473,6 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co
void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) const {
if (script_instance && p_reversed) {
- p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}
@@ -636,7 +489,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
uint32_t pcount;
const GDNativePropertyInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount);
for (uint32_t i = 0; i < pcount; i++) {
- p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name));
+ p_list->push_back(PropertyInfo(pinfo[i]));
}
if (_extension->free_property_list) {
_extension->free_property_list(_extension_instance, pinfo);
@@ -648,16 +501,76 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
if (!is_class("Script")) { // can still be set, but this is for user-friendliness
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
- if (!metadata.is_empty()) {
- p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
- }
+
if (script_instance && !p_reversed) {
- p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}
+
+ for (const KeyValue<StringName, Variant> &K : metadata) {
+ PropertyInfo pi = PropertyInfo(K.value.get_type(), "metadata/" + K.key.operator String());
+ if (K.value.get_type() == Variant::OBJECT) {
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "Resource";
+ }
+ p_list->push_back(pi);
+ }
}
-void Object::_validate_property(PropertyInfo &property) const {
+void Object::validate_property(PropertyInfo &p_property) const {
+ _validate_propertyv(p_property);
+}
+
+bool Object::property_can_revert(const StringName &p_name) const {
+ if (script_instance) {
+ if (script_instance->property_can_revert(p_name)) {
+ return true;
+ }
+ }
+
+// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+ if (_extension && _extension->property_can_revert) {
+ if (_extension->property_can_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name)) {
+ return true;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ return _property_can_revertv(p_name);
+}
+
+Variant Object::property_get_revert(const StringName &p_name) const {
+ Variant ret;
+
+ if (script_instance) {
+ if (script_instance->property_get_revert(p_name, ret)) {
+ return ret;
+ }
+ }
+
+// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+ if (_extension && _extension->property_get_revert) {
+ if (_extension->property_get_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) {
+ return ret;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ if (_property_get_revertv(p_name, ret)) {
+ return ret;
+ }
+ return Variant();
}
void Object::get_method_list(List<MethodInfo> *p_list) const {
@@ -805,6 +718,7 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
+ case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
return ret;
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
}
@@ -824,6 +738,54 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_
return ret;
}
+Variant Object::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+ if (p_method == CoreStringNames::get_singleton()->_free) {
+ // Free is not const, so fail.
+ r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
+ return Variant();
+ }
+
+ Variant ret;
+ OBJ_DEBUG_LOCK
+
+ if (script_instance) {
+ ret = script_instance->call_const(p_method, p_args, p_argcount, r_error);
+ //force jumptable
+ switch (r_error.error) {
+ case Callable::CallError::CALL_OK:
+ return ret;
+ case Callable::CallError::CALL_ERROR_INVALID_METHOD:
+ break;
+ case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
+ break;
+ case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
+ case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
+ case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
+ return ret;
+ case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
+ }
+ }
+ }
+
+ //extension does not need this, because all methods are registered in MethodBind
+
+ MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
+
+ if (method) {
+ if (!method->is_const()) {
+ r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
+ return ret;
+ }
+ ret = method->call(this, p_args, p_argcount, r_error);
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ }
+
+ return ret;
+}
+
void Object::notification(int p_notification, bool p_reversed) {
_notificationv(p_notification, p_reversed);
@@ -845,9 +807,11 @@ String Object::to_string() {
}
}
if (_extension && _extension->to_string) {
- return _extension->to_string(_extension_instance);
+ String ret;
+ _extension->to_string(_extension_instance, &ret);
+ return ret;
}
- return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
+ return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
}
void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
@@ -915,32 +879,50 @@ bool Object::has_meta(const StringName &p_name) const {
void Object::set_meta(const StringName &p_name, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
- metadata.erase(p_name);
+ if (metadata.has(p_name)) {
+ metadata.erase(p_name);
+ metadata_properties.erase("metadata/" + p_name.operator String());
+ notify_property_list_changed();
+ }
return;
}
- metadata[p_name] = p_value;
+ HashMap<StringName, Variant>::Iterator E = metadata.find(p_name);
+ if (E) {
+ E->value = p_value;
+ } else {
+ ERR_FAIL_COND(!p_name.operator String().is_valid_identifier());
+ Variant *V = &metadata.insert(p_name, p_value)->value;
+ metadata_properties["metadata/" + p_name.operator String()] = V;
+ notify_property_list_changed();
+ }
}
-Variant Object::get_meta(const StringName &p_name) const {
- ERR_FAIL_COND_V_MSG(!metadata.has(p_name), Variant(), "The object does not have any 'meta' values with the key '" + p_name + "'.");
+Variant Object::get_meta(const StringName &p_name, const Variant &p_default) const {
+ if (!metadata.has(p_name)) {
+ if (p_default != Variant()) {
+ return p_default;
+ } else {
+ ERR_FAIL_V_MSG(Variant(), "The object does not have any 'meta' values with the key '" + p_name + "'.");
+ }
+ }
return metadata[p_name];
}
void Object::remove_meta(const StringName &p_name) {
- metadata.erase(p_name);
+ set_meta(p_name, Variant());
}
-Array Object::_get_property_list_bind() const {
+TypedArray<Dictionary> Object::_get_property_list_bind() const {
List<PropertyInfo> lpi;
get_property_list(&lpi);
return convert_property_list(&lpi);
}
-Array Object::_get_method_list_bind() const {
+TypedArray<Dictionary> Object::_get_method_list_bind() const {
List<MethodInfo> ml;
get_method_list(&ml);
- Array ret;
+ TypedArray<Dictionary> ret;
for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) {
Dictionary d = E->get();
@@ -954,20 +936,16 @@ Array Object::_get_method_list_bind() const {
Vector<StringName> Object::_get_meta_list_bind() const {
Vector<StringName> _metaret;
- List<Variant> keys;
- metadata.get_key_list(&keys);
- for (const Variant &E : keys) {
- _metaret.push_back(E);
+ for (const KeyValue<StringName, Variant> &K : metadata) {
+ _metaret.push_back(K.key);
}
return _metaret;
}
void Object::get_meta_list(List<StringName> *p_list) const {
- List<Variant> keys;
- metadata.get_key_list(&keys);
- for (const Variant &E : keys) {
- p_list->push_back(E);
+ for (const KeyValue<StringName, Variant> &K : metadata) {
+ p_list->push_back(K.key);
}
}
@@ -992,15 +970,15 @@ struct _ObjectSignalDisconnectData {
Callable callable;
};
-Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Error Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- ERR_FAIL_COND_V(p_argcount < 1, Variant());
+ ERR_FAIL_COND_V(p_argcount < 1, Error::ERR_INVALID_PARAMETER);
if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::STRING_NAME;
- ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING, Variant());
+ ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING, Error::ERR_INVALID_PARAMETER);
}
r_error.error = Callable::CallError::CALL_OK;
@@ -1014,9 +992,7 @@ Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::C
args = &p_args[1];
}
- emit_signalp(signal, args, argc);
-
- return Variant();
+ return emit_signalp(signal, args, argc);
}
Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) {
@@ -1046,8 +1022,6 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
OBJ_DEBUG_LOCK
- Vector<const Variant *> bind_mem;
-
Error err = OK;
for (int i = 0; i < ssize; i++) {
@@ -1062,28 +1036,13 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
const Variant **args = p_args;
int argc = p_argcount;
- if (c.binds.size()) {
- //handle binds
- bind_mem.resize(p_argcount + c.binds.size());
-
- for (int j = 0; j < p_argcount; j++) {
- bind_mem.write[j] = p_args[j];
- }
- for (int j = 0; j < c.binds.size(); j++) {
- bind_mem.write[p_argcount + j] = &c.binds[j];
- }
-
- args = (const Variant **)bind_mem.ptr();
- argc = bind_mem.size();
- }
-
if (c.flags & CONNECT_DEFERRED) {
MessageQueue::get_singleton()->push_callablep(c.callable, args, argc, true);
} else {
Callable::CallError ce;
_emitting = true;
Variant ret;
- c.callable.call(args, argc, ret, ce);
+ c.callable.callp(args, argc, ret, ce);
_emitting = false;
if (ce.error != Callable::CallError::CALL_OK) {
@@ -1101,7 +1060,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
}
}
- bool disconnect = c.flags & CONNECT_ONESHOT;
+ bool disconnect = c.flags & CONNECT_ONE_SHOT;
#ifdef TOOLS_ENABLED
if (disconnect && (c.flags & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) {
//this signal was connected from the editor, and is being edited. just don't disconnect for now
@@ -1151,11 +1110,11 @@ void Object::_add_user_signal(const String &p_name, const Array &p_args) {
add_user_signal(mi);
}
-Array Object::_get_signal_list() const {
+TypedArray<Dictionary> Object::_get_signal_list() const {
List<MethodInfo> signal_list;
get_signal_list(&signal_list);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const MethodInfo &E : signal_list) {
ret.push_back(Dictionary(E));
}
@@ -1163,11 +1122,11 @@ Array Object::_get_signal_list() const {
return ret;
}
-Array Object::_get_signal_connection_list(const String &p_signal) const {
+TypedArray<Dictionary> Object::_get_signal_connection_list(const StringName &p_signal) const {
List<Connection> conns;
get_all_signal_connections(&conns);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const Connection &c : conns) {
if (c.signal.get_name() == p_signal) {
@@ -1178,8 +1137,8 @@ Array Object::_get_signal_connection_list(const String &p_signal) const {
return ret;
}
-Array Object::_get_incoming_connections() const {
- Array ret;
+TypedArray<Dictionary> Object::_get_incoming_connections() const {
+ TypedArray<Dictionary> ret;
int connections_amount = connections.size();
for (int idx_conn = 0; idx_conn < connections_amount; idx_conn++) {
ret.push_back(connections[idx_conn]);
@@ -1217,21 +1176,18 @@ void Object::get_signal_list(List<MethodInfo> *p_signals) const {
ClassDB::get_signal_list(get_class_name(), p_signals);
//find maybe usersignals?
- const StringName *S = nullptr;
- while ((S = signal_map.next(S))) {
- if (!signal_map[*S].user.name.is_empty()) {
+ for (const KeyValue<StringName, SignalData> &E : signal_map) {
+ if (!E.value.user.name.is_empty()) {
//user signal
- p_signals->push_back(signal_map[*S].user);
+ p_signals->push_back(E.value.user);
}
}
}
void Object::get_all_signal_connections(List<Connection> *p_connections) const {
- const StringName *S = nullptr;
-
- while ((S = signal_map.next(S))) {
- const SignalData *s = &signal_map[*S];
+ for (const KeyValue<StringName, SignalData> &E : signal_map) {
+ const SignalData *s = &E.value;
for (int i = 0; i < s->slot_map.size(); i++) {
p_connections->push_back(s->slot_map.getv(i).conn);
@@ -1252,10 +1208,9 @@ void Object::get_signal_connection_list(const StringName &p_signal, List<Connect
int Object::get_persistent_signal_connection_count() const {
int count = 0;
- const StringName *S = nullptr;
- while ((S = signal_map.next(S))) {
- const SignalData *s = &signal_map[*S];
+ for (const KeyValue<StringName, SignalData> &E : signal_map) {
+ const SignalData *s = &E.value;
for (int i = 0; i < s->slot_map.size(); i++) {
if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST) {
@@ -1273,7 +1228,7 @@ void Object::get_signals_connected_to_this(List<Connection> *p_connections) cons
}
}
-Error Object::connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) {
+Error Object::connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags) {
ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is null.");
Object *target_object = p_callable.get_object();
@@ -1321,7 +1276,6 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, co
conn.callable = target;
conn.signal = ::Signal(this, p_signal);
conn.flags = p_flags;
- conn.binds = p_binds;
slot.conn = conn;
slot.cE = target_object->connections.push_back(conn);
if (p_flags & CONNECT_REFERENCE_COUNTED) {
@@ -1353,8 +1307,6 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable
Callable target = p_callable;
return s->slot_map.has(*target.get_base_comparator());
- //const Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.find(target);
- //return (E!=nullptr );
}
void Object::disconnect(const StringName &p_signal, const Callable &p_callable) {
@@ -1395,11 +1347,11 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
}
}
-void Object::_set_bind(const String &p_set, const Variant &p_value) {
+void Object::_set_bind(const StringName &p_set, const Variant &p_value) {
set(p_set, p_value);
}
-Variant Object::_get_bind(const String &p_name) const {
+Variant Object::_get_bind(const StringName &p_name) const {
return get(p_name);
}
@@ -1442,7 +1394,7 @@ String Object::tr_n(const StringName &p_message, const StringName &p_message_plu
void Object::_clear_internal_resource_paths(const Variant &p_var) {
switch (p_var.get_type()) {
case Variant::OBJECT: {
- RES r = p_var;
+ Ref<Resource> r = p_var;
if (!r.is_valid()) {
return;
}
@@ -1516,8 +1468,8 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
ClassDB::bind_method(D_METHOD("set", "property", "value"), &Object::_set_bind);
ClassDB::bind_method(D_METHOD("get", "property"), &Object::_get_bind);
- ClassDB::bind_method(D_METHOD("set_indexed", "property", "value"), &Object::_set_indexed_bind);
- ClassDB::bind_method(D_METHOD("get_indexed", "property"), &Object::_get_indexed_bind);
+ ClassDB::bind_method(D_METHOD("set_indexed", "property_path", "value"), &Object::_set_indexed_bind);
+ ClassDB::bind_method(D_METHOD("get_indexed", "property_path"), &Object::_get_indexed_bind);
ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);
ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);
ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
@@ -1529,7 +1481,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta);
ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta);
- ClassDB::bind_method(D_METHOD("get_meta", "name"), &Object::get_meta);
+ ClassDB::bind_method(D_METHOD("get_meta", "name", "default"), &Object::get_meta, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta);
ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind);
@@ -1571,7 +1523,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list);
ClassDB::bind_method(D_METHOD("get_incoming_connections"), &Object::_get_incoming_connections);
- ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "binds", "flags"), &Object::connect, DEFVAL(Array()), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "flags"), &Object::connect, DEFVAL(0));
ClassDB::bind_method(D_METHOD("disconnect", "signal", "callable"), &Object::disconnect);
ClassDB::bind_method(D_METHOD("is_connected", "signal", "callable"), &Object::is_connected);
@@ -1603,10 +1555,17 @@ void Object::_bind_methods() {
BIND_OBJ_CORE_METHOD(miget);
MethodInfo plget("_get_property_list");
-
plget.return_val.type = Variant::ARRAY;
+ plget.return_val.hint = PROPERTY_HINT_ARRAY_TYPE;
+ plget.return_val.hint_string = "Dictionary";
BIND_OBJ_CORE_METHOD(plget);
+ BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_property_can_revert", PropertyInfo(Variant::STRING_NAME, "property")));
+ MethodInfo mipgr("_property_get_revert", PropertyInfo(Variant::STRING_NAME, "property"));
+ mipgr.return_val.name = "Variant";
+ mipgr.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ BIND_OBJ_CORE_METHOD(mipgr);
+
#endif
BIND_OBJ_CORE_METHOD(MethodInfo("_init"));
BIND_OBJ_CORE_METHOD(MethodInfo(Variant::STRING, "_to_string"));
@@ -1616,7 +1575,7 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_DEFERRED);
BIND_ENUM_CONSTANT(CONNECT_PERSIST);
- BIND_ENUM_CONSTANT(CONNECT_ONESHOT);
+ BIND_ENUM_CONSTANT(CONNECT_ONE_SHOT);
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
}
@@ -1814,6 +1773,13 @@ Object::Object() {
_construct_object(false);
}
+void Object::detach_from_objectdb() {
+ if (_instance_id != ObjectID()) {
+ ObjectDB::remove_instance(this);
+ _instance_id = ObjectID();
+ }
+}
+
Object::~Object() {
if (script_instance) {
memdelete(script_instance);
@@ -1826,15 +1792,15 @@ Object::~Object() {
_extension_instance = nullptr;
}
- const StringName *S = nullptr;
-
if (_emitting) {
//@todo this may need to actually reach the debugger prioritarily somehow because it may crash before
ERR_PRINT("Object " + to_string() + " was freed or unreferenced while a signal is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes.");
}
- while ((S = signal_map.next(nullptr))) {
- SignalData *s = &signal_map[*S];
+ while (signal_map.size()) {
+ // Avoid regular iteration so erasing is safe.
+ KeyValue<StringName, SignalData> &E = *signal_map.begin();
+ SignalData *s = &E.value;
//brute force disconnect for performance
int slot_count = s->slot_map.size();
@@ -1844,7 +1810,7 @@ Object::~Object() {
slot_list[i].value.conn.callable.get_object()->connections.erase(slot_list[i].value.cE);
}
- signal_map.erase(*S);
+ signal_map.erase(E.key);
}
//signals from nodes that connect to this node
@@ -1853,8 +1819,10 @@ Object::~Object() {
c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true);
}
- ObjectDB::remove_instance(this);
- _instance_id = ObjectID();
+ if (_instance_id != ObjectID()) {
+ ObjectDB::remove_instance(this);
+ _instance_id = ObjectID();
+ }
_predelete_ok = 2;
if (_instance_bindings != nullptr) {
@@ -1888,6 +1856,46 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
}
void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+ if (p_idx == 0) {
+ if (p_function == "connect" || p_function == "is_connected" || p_function == "disconnect" || p_function == "emit_signal" || p_function == "has_signal") {
+ List<MethodInfo> signals;
+ get_signal_list(&signals);
+ for (const MethodInfo &E : signals) {
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "call" || p_function == "call_deferred" || p_function == "callv" || p_function == "has_method") {
+ List<MethodInfo> methods;
+ get_method_list(&methods);
+ for (const MethodInfo &E : methods) {
+ if (E.name.begins_with("_") && !(E.flags & METHOD_FLAG_VIRTUAL)) {
+ continue;
+ }
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "set" || p_function == "set_deferred" || p_function == "get") {
+ List<PropertyInfo> properties;
+ get_property_list(&properties);
+ for (const PropertyInfo &E : properties) {
+ if (E.usage & PROPERTY_USAGE_DEFAULT && !(E.usage & PROPERTY_USAGE_INTERNAL)) {
+ r_options->push_back(E.name.quote());
+ }
+ }
+ } else if (p_function == "set_meta" || p_function == "get_meta" || p_function == "has_meta" || p_function == "remove_meta") {
+ for (const KeyValue<StringName, Variant> &K : metadata) {
+ r_options->push_back(String(K.key).quote());
+ }
+ }
+ } else if (p_idx == 2) {
+ if (p_function == "connect") {
+ // Ideally, the constants should be inferred by the parameter.
+ // But a parameter's PropertyInfo does not store the enum they come from, so this will do for now.
+ List<StringName> constants;
+ ClassDB::get_enum_constants("Object", "ConnectFlags", &constants);
+ for (const StringName &E : constants) {
+ r_options->push_back(String(E));
+ }
+ }
+ }
}
SpinLock ObjectDB::spin_lock;