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.cpp174
1 files changed, 106 insertions, 68 deletions
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 096edd4e60..797eecd312 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -416,21 +416,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 +447,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 +506,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 +530,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;
@@ -648,13 +660,20 @@ 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 {
@@ -845,7 +864,9 @@ 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()) + "]";
}
@@ -915,20 +936,38 @@ 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 {
@@ -954,20 +993,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 +1027,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 +1049,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) {
@@ -1217,21 +1250,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 +1282,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) {
@@ -1442,7 +1471,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;
}
@@ -1529,7 +1558,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);
@@ -1814,6 +1843,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 +1862,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 +1880,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 +1889,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) {