summaryrefslogtreecommitdiffstats
path: root/core/object/object.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/object/object.cpp')
-rw-r--r--core/object/object.cpp128
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));