diff options
Diffstat (limited to 'core/object/object.cpp')
-rw-r--r-- | core/object/object.cpp | 128 |
1 files changed, 85 insertions, 43 deletions
diff --git a/core/object/object.cpp b/core/object/object.cpp index 97a3a405b9..000d5328b4 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -29,7 +29,6 @@ /**************************************************************************/ #include "object.h" -#include "object.compat.inc" #include "core/extension/gdextension_manager.h" #include "core/io/resource.h" @@ -38,7 +37,7 @@ #include "core/object/script_language.h" #include "core/os/os.h" #include "core/string/print_string.h" -#include "core/string/translation.h" +#include "core/string/translation_server.h" #include "core/templates/local_vector.h" #include "core/variant/typed_array.h" @@ -207,10 +206,13 @@ void Object::cancel_free() { _predelete_ok = false; } -void Object::_postinitialize() { - _class_name_ptr = _get_class_namev(); // Set the direct pointer, which is much faster to obtain, but can only happen after postinitialize. +void Object::_initialize() { + _class_name_ptr = _get_class_namev(); // Set the direct pointer, which is much faster to obtain, but can only happen after _initialize. _initialize_classv(); _class_name_ptr = nullptr; // May have been called from a constructor. +} + +void Object::_postinitialize() { notification(NOTIFICATION_POSTINITIALIZE); } @@ -602,7 +604,7 @@ Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::Cal return Variant(); } - if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) { + if (!p_args[0]->is_string()) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING_NAME; @@ -621,7 +623,7 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call return Variant(); } - if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) { + if (!p_args[0]->is_string()) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING_NAME; @@ -717,7 +719,7 @@ Variant Object::getvar(const Variant &p_key, bool *r_valid) const { *r_valid = false; } - if (p_key.get_type() == Variant::STRING_NAME || p_key.get_type() == Variant::STRING) { + if (p_key.is_string()) { return get(p_key, r_valid); } return Variant(); @@ -727,7 +729,7 @@ void Object::setvar(const Variant &p_key, const Variant &p_value, bool *r_valid) if (r_valid) { *r_valid = false; } - if (p_key.get_type() == Variant::STRING_NAME || p_key.get_type() == Variant::STRING) { + if (p_key.is_string()) { return set(p_key, p_value, r_valid); } } @@ -743,7 +745,7 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) { } Callable::CallError ce; - Variant ret = callp(p_method, argptrs, p_args.size(), ce); + const Variant ret = callp(p_method, argptrs, p_args.size(), ce); if (ce.error != Callable::CallError::CALL_OK) { ERR_FAIL_V_MSG(Variant(), "Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce) + "."); } @@ -763,7 +765,7 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_ } if (is_ref_counted()) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference."); + ERR_FAIL_V_MSG(Variant(), "Can't free a RefCounted object."); } if (_lock_index.get() > 1) { @@ -784,7 +786,7 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_ if (script_instance) { ret = script_instance->callp(p_method, p_args, p_argcount, r_error); - //force jumptable + // Force jump table. switch (r_error.error) { case Callable::CallError::CALL_OK: return ret; @@ -994,7 +996,7 @@ void Object::set_meta(const StringName &p_name, const Variant &p_value) { if (E) { E->value = p_value; } else { - ERR_FAIL_COND_MSG(!p_name.operator String().is_valid_identifier(), "Invalid metadata identifier: '" + p_name + "'."); + ERR_FAIL_COND_MSG(!p_name.operator String().is_valid_ascii_identifier(), "Invalid metadata identifier: '" + p_name + "'."); Variant *V = &metadata.insert(p_name, p_value)->value; const String &sname = p_name; @@ -1020,6 +1022,14 @@ void Object::remove_meta(const StringName &p_name) { set_meta(p_name, Variant()); } +void Object::merge_meta_from(const Object *p_src) { + List<StringName> meta_keys; + p_src->get_meta_list(&meta_keys); + for (const StringName &key : meta_keys) { + set_meta(key, p_src->get_meta(key)); + } +} + TypedArray<Dictionary> Object::_get_property_list_bind() const { List<PropertyInfo> lpi; get_property_list(&lpi); @@ -1093,7 +1103,7 @@ Error Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::Cal ERR_FAIL_V(Error::ERR_INVALID_PARAMETER); } - if (unlikely(p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING)) { + if (unlikely(!p_args[0]->is_string())) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING_NAME; @@ -1713,33 +1723,65 @@ void Object::_bind_methods() { #define BIND_OBJ_CORE_METHOD(m_method) \ ::ClassDB::add_virtual_method(get_class_static(), m_method, true, Vector<String>(), true); - MethodInfo notification_mi("_notification", PropertyInfo(Variant::INT, "what")); - notification_mi.arguments_metadata.push_back(GodotTypeInfo::Metadata::METADATA_INT_IS_INT32); - BIND_OBJ_CORE_METHOD(notification_mi); - BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_set", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value"))); + BIND_OBJ_CORE_METHOD(MethodInfo("_init")); + + BIND_OBJ_CORE_METHOD(MethodInfo(Variant::STRING, "_to_string")); + + { + MethodInfo mi("_notification"); + mi.arguments.push_back(PropertyInfo(Variant::INT, "what")); + mi.arguments_metadata.push_back(GodotTypeInfo::Metadata::METADATA_INT_IS_INT32); + BIND_OBJ_CORE_METHOD(mi); + } + + { + MethodInfo mi("_set"); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "property")); + mi.arguments.push_back(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); + mi.return_val.type = Variant::BOOL; + BIND_OBJ_CORE_METHOD(mi); + } + #ifdef TOOLS_ENABLED - MethodInfo miget("_get", PropertyInfo(Variant::STRING_NAME, "property")); - miget.return_val.name = "Variant"; - miget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - BIND_OBJ_CORE_METHOD(miget); + { + MethodInfo mi("_get"); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "property")); + mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + BIND_OBJ_CORE_METHOD(mi); + } - 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); + { + MethodInfo mi("_get_property_list"); + mi.return_val.type = Variant::ARRAY; + mi.return_val.hint = PROPERTY_HINT_ARRAY_TYPE; + mi.return_val.hint_string = "Dictionary"; + BIND_OBJ_CORE_METHOD(mi); + } BIND_OBJ_CORE_METHOD(MethodInfo(Variant::NIL, "_validate_property", PropertyInfo(Variant::DICTIONARY, "property"))); 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); + { + MethodInfo mi("_property_get_revert"); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "property")); + mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + BIND_OBJ_CORE_METHOD(mi); + } + + // These are actually `Variant` methods, but that doesn't matter since scripts can't inherit built-in types. + + BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_iter_init", PropertyInfo(Variant::ARRAY, "iter"))); + + BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_iter_next", PropertyInfo(Variant::ARRAY, "iter"))); + + { + MethodInfo mi("_iter_get"); + mi.arguments.push_back(PropertyInfo(Variant::NIL, "iter", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); + mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + BIND_OBJ_CORE_METHOD(mi); + } #endif - BIND_OBJ_CORE_METHOD(MethodInfo("_init")); - BIND_OBJ_CORE_METHOD(MethodInfo(Variant::STRING, "_to_string")); BIND_CONSTANT(NOTIFICATION_POSTINITIALIZE); BIND_CONSTANT(NOTIFICATION_PREDELETE); @@ -1901,7 +1943,7 @@ void Object::set_instance_binding(void *p_token, void *p_binding, const GDExtens void *Object::get_instance_binding(void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks) { void *binding = nullptr; - _instance_binding_mutex.lock(); + MutexLock instance_binding_lock(_instance_binding_mutex); for (uint32_t i = 0; i < _instance_binding_count; i++) { if (_instance_bindings[i].token == p_token) { binding = _instance_bindings[i].binding; @@ -1932,14 +1974,12 @@ void *Object::get_instance_binding(void *p_token, const GDExtensionInstanceBindi _instance_binding_count++; } - _instance_binding_mutex.unlock(); - return binding; } bool Object::has_instance_binding(void *p_token) { bool found = false; - _instance_binding_mutex.lock(); + MutexLock instance_binding_lock(_instance_binding_mutex); for (uint32_t i = 0; i < _instance_binding_count; i++) { if (_instance_bindings[i].token == p_token) { found = true; @@ -1947,14 +1987,12 @@ bool Object::has_instance_binding(void *p_token) { } } - _instance_binding_mutex.unlock(); - return found; } void Object::free_instance_binding(void *p_token) { bool found = false; - _instance_binding_mutex.lock(); + MutexLock instance_binding_lock(_instance_binding_mutex); for (uint32_t i = 0; i < _instance_binding_count; i++) { if (!found && _instance_bindings[i].token == p_token) { if (_instance_bindings[i].free_callback) { @@ -1973,7 +2011,6 @@ void Object::free_instance_binding(void *p_token) { if (found) { _instance_binding_count--; } - _instance_binding_mutex.unlock(); } #ifdef TOOLS_ENABLED @@ -2097,7 +2134,11 @@ Object::~Object() { // Disconnect signals that connect to this object. while (connections.size()) { Connection c = connections.front()->get(); - bool disconnected = c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true); + Object *obj = c.callable.get_object(); + bool disconnected = false; + if (likely(obj)) { + disconnected = c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true); + } if (unlikely(!disconnected)) { // If the disconnect has failed, abandon the connection to avoid getting trapped in an infinite loop here. connections.pop_front(); @@ -2125,6 +2166,7 @@ bool predelete_handler(Object *p_object) { } void postinitialize_handler(Object *p_object) { + p_object->_initialize(); p_object->_postinitialize(); } @@ -2286,7 +2328,7 @@ void ObjectDB::cleanup() { // Ensure calling the native classes because if a leaked instance has a script // that overrides any of those methods, it'd not be OK to call them at this point, // now the scripting languages have already been terminated. - MethodBind *node_get_name = ClassDB::get_method("Node", "get_name"); + MethodBind *node_get_path = ClassDB::get_method("Node", "get_path"); MethodBind *resource_get_path = ClassDB::get_method("Resource", "get_path"); Callable::CallError call_error; @@ -2296,7 +2338,7 @@ void ObjectDB::cleanup() { String extra_info; if (obj->is_class("Node")) { - extra_info = " - Node name: " + String(node_get_name->call(obj, nullptr, 0, call_error)); + extra_info = " - Node path: " + String(node_get_path->call(obj, nullptr, 0, call_error)); } if (obj->is_class("Resource")) { extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error)); |