feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
|
|
@ -29,7 +29,6 @@
|
|||
/**************************************************************************/
|
||||
|
||||
#include "object.h"
|
||||
#include "object.compat.inc"
|
||||
|
||||
#include "core/extension/gdextension_manager.h"
|
||||
#include "core/io/resource.h"
|
||||
|
|
@ -38,21 +37,23 @@
|
|||
#include "core/object/script_language.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/string/print_string.h"
|
||||
#include "core/string/translation.h"
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "core/string/translation_server.h"
|
||||
#include "core/variant/typed_array.h"
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
struct _ObjectDebugLock {
|
||||
Object *obj;
|
||||
ObjectID obj_id;
|
||||
|
||||
_ObjectDebugLock(Object *p_obj) {
|
||||
obj = p_obj;
|
||||
obj->_lock_index.ref();
|
||||
obj_id = p_obj->get_instance_id();
|
||||
p_obj->_lock_index.ref();
|
||||
}
|
||||
~_ObjectDebugLock() {
|
||||
obj->_lock_index.unref();
|
||||
Object *obj_ptr = ObjectDB::get_instance(obj_id);
|
||||
if (likely(obj_ptr)) {
|
||||
obj_ptr->_lock_index.unref();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -164,6 +165,37 @@ MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) {
|
|||
return mi;
|
||||
}
|
||||
|
||||
uint32_t MethodInfo::get_compatibility_hash() const {
|
||||
bool has_return = (return_val.type != Variant::NIL) || (return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||
|
||||
uint32_t hash = hash_murmur3_one_32(has_return);
|
||||
hash = hash_murmur3_one_32(arguments.size(), hash);
|
||||
|
||||
if (has_return) {
|
||||
hash = hash_murmur3_one_32(return_val.type, hash);
|
||||
if (return_val.class_name != StringName()) {
|
||||
hash = hash_murmur3_one_32(return_val.class_name.hash(), hash);
|
||||
}
|
||||
}
|
||||
|
||||
for (const PropertyInfo &arg : arguments) {
|
||||
hash = hash_murmur3_one_32(arg.type, hash);
|
||||
if (arg.class_name != StringName()) {
|
||||
hash = hash_murmur3_one_32(arg.class_name.hash(), hash);
|
||||
}
|
||||
}
|
||||
|
||||
hash = hash_murmur3_one_32(default_arguments.size(), hash);
|
||||
for (const Variant &v : default_arguments) {
|
||||
hash = hash_murmur3_one_32(v.hash(), hash);
|
||||
}
|
||||
|
||||
hash = hash_murmur3_one_32(flags & METHOD_FLAG_CONST ? 1 : 0, hash);
|
||||
hash = hash_murmur3_one_32(flags & METHOD_FLAG_VARARG ? 1 : 0, hash);
|
||||
|
||||
return hash_fmix32(hash);
|
||||
}
|
||||
|
||||
Object::Connection::operator Variant() const {
|
||||
Dictionary d;
|
||||
d["signal"] = signal;
|
||||
|
|
@ -207,10 +239,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);
|
||||
}
|
||||
|
||||
|
|
@ -516,7 +551,13 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
|
|||
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";
|
||||
Object *obj = K.value;
|
||||
if (Object::cast_to<Script>(obj)) {
|
||||
pi.hint_string = "Script";
|
||||
pi.usage |= PROPERTY_USAGE_NEVER_DUPLICATE;
|
||||
} else {
|
||||
pi.hint_string = "Resource";
|
||||
}
|
||||
}
|
||||
p_list->push_back(pi);
|
||||
}
|
||||
|
|
@ -602,7 +643,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 +662,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 +758,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 +768,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,9 +784,9 @@ 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) + ".");
|
||||
ERR_FAIL_V_MSG(Variant(), vformat("Error calling method from 'callv': %s.", Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -784,7 +825,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;
|
||||
|
|
@ -935,7 +976,7 @@ void Object::set_script(const Variant &p_script) {
|
|||
script_instance = nullptr;
|
||||
}
|
||||
|
||||
if (!s.is_null()) {
|
||||
if (s.is_valid()) {
|
||||
if (s->can_instantiate()) {
|
||||
OBJ_DEBUG_LOCK
|
||||
script_instance = s->instance_create(this);
|
||||
|
|
@ -994,7 +1035,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(), vformat("Invalid metadata identifier: '%s'.", p_name));
|
||||
Variant *V = &metadata.insert(p_name, p_value)->value;
|
||||
|
||||
const String &sname = p_name;
|
||||
|
|
@ -1010,7 +1051,7 @@ Variant Object::get_meta(const StringName &p_name, const Variant &p_default) con
|
|||
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 + "'.");
|
||||
ERR_FAIL_V_MSG(Variant(), vformat("The object does not have any 'meta' values with the key '%s'.", p_name));
|
||||
}
|
||||
}
|
||||
return metadata[p_name];
|
||||
|
|
@ -1020,6 +1061,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);
|
||||
|
|
@ -1058,8 +1107,8 @@ void Object::get_meta_list(List<StringName> *p_list) const {
|
|||
|
||||
void Object::add_user_signal(const MethodInfo &p_signal) {
|
||||
ERR_FAIL_COND_MSG(p_signal.name.is_empty(), "Signal name cannot be empty.");
|
||||
ERR_FAIL_COND_MSG(ClassDB::has_signal(get_class_name(), p_signal.name), "User signal's name conflicts with a built-in signal of '" + get_class_name() + "'.");
|
||||
ERR_FAIL_COND_MSG(signal_map.has(p_signal.name), "Trying to add already existing signal '" + p_signal.name + "'.");
|
||||
ERR_FAIL_COND_MSG(ClassDB::has_signal(get_class_name(), p_signal.name), vformat("User signal's name conflicts with a built-in signal of '%s'.", get_class_name()));
|
||||
ERR_FAIL_COND_MSG(signal_map.has(p_signal.name), vformat("Trying to add already existing signal '%s'.", p_signal.name));
|
||||
SignalData s;
|
||||
s.user = p_signal;
|
||||
signal_map[p_signal.name] = s;
|
||||
|
|
@ -1093,7 +1142,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;
|
||||
|
|
@ -1124,7 +1173,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
|
|||
#ifdef DEBUG_ENABLED
|
||||
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_name);
|
||||
//check in script
|
||||
ERR_FAIL_COND_V_MSG(!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name), ERR_UNAVAILABLE, "Can't emit non-existing signal " + String("\"") + p_name + "\".");
|
||||
ERR_FAIL_COND_V_MSG(!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name), ERR_UNAVAILABLE, vformat("Can't emit non-existing signal \"%s\".", p_name));
|
||||
#endif
|
||||
//not connected? just return
|
||||
return ERR_UNAVAILABLE;
|
||||
|
|
@ -1197,7 +1246,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
|
|||
if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD && target && !ClassDB::class_exists(target->get_class_name())) {
|
||||
//most likely object is not initialized yet, do not throw error.
|
||||
} else {
|
||||
ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(callable, args, argc, ce) + ".");
|
||||
ERR_PRINT(vformat("Error calling from signal '%s' to callable: %s.", String(p_name), Variant::get_callable_error_text(callable, args, argc, ce)));
|
||||
err = ERR_METHOD_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
|
@ -1358,15 +1407,15 @@ void Object::get_signals_connected_to_this(List<Connection> *p_connections) cons
|
|||
}
|
||||
|
||||
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.");
|
||||
ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, vformat("Cannot connect to '%s': the provided callable is null.", p_signal));
|
||||
|
||||
if (p_callable.is_standard()) {
|
||||
// FIXME: This branch should probably removed in favor of the `is_valid()` branch, but there exist some classes
|
||||
// that call `connect()` before they are fully registered with ClassDB. Until all such classes can be found
|
||||
// and registered soon enough this branch is needed to allow `connect()` to succeed.
|
||||
ERR_FAIL_NULL_V_MSG(p_callable.get_object(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "' to callable '" + p_callable + "': the callable object is null.");
|
||||
ERR_FAIL_NULL_V_MSG(p_callable.get_object(), ERR_INVALID_PARAMETER, vformat("Cannot connect to '%s' to callable '%s': the callable object is null.", p_signal, p_callable));
|
||||
} else {
|
||||
ERR_FAIL_COND_V_MSG(!p_callable.is_valid(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is not valid: " + p_callable);
|
||||
ERR_FAIL_COND_V_MSG(!p_callable.is_valid(), ERR_INVALID_PARAMETER, vformat("Cannot connect to '%s': the provided callable is not valid: '%s'.", p_signal, p_callable));
|
||||
}
|
||||
|
||||
SignalData *s = signal_map.getptr(p_signal);
|
||||
|
|
@ -1387,7 +1436,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui
|
|||
#endif
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(!signal_is_valid, ERR_INVALID_PARAMETER, "In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to callable '" + p_callable + "'.");
|
||||
ERR_FAIL_COND_V_MSG(!signal_is_valid, ERR_INVALID_PARAMETER, vformat("In Object of type '%s': Attempt to connect nonexistent signal '%s' to callable '%s'.", String(get_class()), p_signal, p_callable));
|
||||
|
||||
signal_map[p_signal] = SignalData();
|
||||
s = &signal_map[p_signal];
|
||||
|
|
@ -1399,7 +1448,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui
|
|||
s->slot_map[*p_callable.get_base_comparator()].reference_count++;
|
||||
return OK;
|
||||
} else {
|
||||
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Signal '" + p_signal + "' is already connected to given callable '" + p_callable + "' in that object.");
|
||||
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("Signal '%s' is already connected to given callable '%s' in that object.", p_signal, p_callable));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1426,7 +1475,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui
|
|||
}
|
||||
|
||||
bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const {
|
||||
ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot determine if connected to '" + p_signal + "': the provided callable is null."); // Should use `is_null`, see note in `connect` about the use of `is_valid`.
|
||||
ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, vformat("Cannot determine if connected to '%s': the provided callable is null.", p_signal)); // Should use `is_null`, see note in `connect` about the use of `is_valid`.
|
||||
const SignalData *s = signal_map.getptr(p_signal);
|
||||
if (!s) {
|
||||
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
|
||||
|
|
@ -1438,28 +1487,46 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable
|
|||
return false;
|
||||
}
|
||||
|
||||
ERR_FAIL_V_MSG(false, "Nonexistent signal: " + p_signal + ".");
|
||||
ERR_FAIL_V_MSG(false, vformat("Nonexistent signal: '%s'.", p_signal));
|
||||
}
|
||||
|
||||
return s->slot_map.has(*p_callable.get_base_comparator());
|
||||
}
|
||||
|
||||
bool Object::has_connections(const StringName &p_signal) const {
|
||||
const SignalData *s = signal_map.getptr(p_signal);
|
||||
if (!s) {
|
||||
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
|
||||
if (signal_is_valid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ERR_FAIL_V_MSG(false, vformat("Nonexistent signal: '%s'.", p_signal));
|
||||
}
|
||||
|
||||
return !s->slot_map.is_empty();
|
||||
}
|
||||
|
||||
void Object::disconnect(const StringName &p_signal, const Callable &p_callable) {
|
||||
_disconnect(p_signal, p_callable);
|
||||
}
|
||||
|
||||
bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force) {
|
||||
ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot disconnect from '" + p_signal + "': the provided callable is null."); // Should use `is_null`, see note in `connect` about the use of `is_valid`.
|
||||
ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, vformat("Cannot disconnect from '%s': the provided callable is null.", p_signal)); // Should use `is_null`, see note in `connect` about the use of `is_valid`.
|
||||
|
||||
SignalData *s = signal_map.getptr(p_signal);
|
||||
if (!s) {
|
||||
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal) ||
|
||||
(!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal));
|
||||
ERR_FAIL_COND_V_MSG(signal_is_valid, false, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'.");
|
||||
ERR_FAIL_COND_V_MSG(signal_is_valid, false, vformat("Attempt to disconnect a nonexistent connection from '%s'. Signal: '%s', callable: '%s'.", to_string(), p_signal, p_callable));
|
||||
}
|
||||
ERR_FAIL_NULL_V_MSG(s, false, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string()));
|
||||
ERR_FAIL_NULL_V_MSG(s, false, vformat("Disconnecting nonexistent signal '%s' in '%s'.", p_signal, to_string()));
|
||||
|
||||
ERR_FAIL_COND_V_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), false, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'.");
|
||||
ERR_FAIL_COND_V_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), false, vformat("Attempt to disconnect a nonexistent connection from '%s'. Signal: '%s', callable: '%s'.", to_string(), p_signal, p_callable));
|
||||
|
||||
SignalData::Slot *slot = &s->slot_map[*p_callable.get_base_comparator()];
|
||||
|
||||
|
|
@ -1514,21 +1581,21 @@ void Object::initialize_class() {
|
|||
initialized = true;
|
||||
}
|
||||
|
||||
StringName Object::get_translation_domain() const {
|
||||
return _translation_domain;
|
||||
}
|
||||
|
||||
void Object::set_translation_domain(const StringName &p_domain) {
|
||||
_translation_domain = p_domain;
|
||||
}
|
||||
|
||||
String Object::tr(const StringName &p_message, const StringName &p_context) const {
|
||||
if (!_can_translate || !TranslationServer::get_singleton()) {
|
||||
return p_message;
|
||||
}
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) {
|
||||
String tr_msg = TranslationServer::get_singleton()->extractable_translate(p_message, p_context);
|
||||
if (!tr_msg.is_empty() && tr_msg != p_message) {
|
||||
return tr_msg;
|
||||
}
|
||||
|
||||
return TranslationServer::get_singleton()->tool_translate(p_message, p_context);
|
||||
}
|
||||
|
||||
return TranslationServer::get_singleton()->translate(p_message, p_context);
|
||||
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain(get_translation_domain());
|
||||
return domain->translate(p_message, p_context);
|
||||
}
|
||||
|
||||
String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
|
||||
|
|
@ -1540,23 +1607,15 @@ String Object::tr_n(const StringName &p_message, const StringName &p_message_plu
|
|||
return p_message_plural;
|
||||
}
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) {
|
||||
String tr_msg = TranslationServer::get_singleton()->extractable_translate_plural(p_message, p_message_plural, p_n, p_context);
|
||||
if (!tr_msg.is_empty() && tr_msg != p_message && tr_msg != p_message_plural) {
|
||||
return tr_msg;
|
||||
}
|
||||
|
||||
return TranslationServer::get_singleton()->tool_translate_plural(p_message, p_message_plural, p_n, p_context);
|
||||
}
|
||||
|
||||
return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context);
|
||||
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain(get_translation_domain());
|
||||
return domain->translate_plural(p_message, p_message_plural, p_n, p_context);
|
||||
}
|
||||
|
||||
void Object::_clear_internal_resource_paths(const Variant &p_var) {
|
||||
switch (p_var.get_type()) {
|
||||
case Variant::OBJECT: {
|
||||
Ref<Resource> r = p_var;
|
||||
if (!r.is_valid()) {
|
||||
if (r.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1692,6 +1751,7 @@ void Object::_bind_methods() {
|
|||
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);
|
||||
ClassDB::bind_method(D_METHOD("has_connections", "signal"), &Object::has_connections);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_block_signals", "enable"), &Object::set_block_signals);
|
||||
ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals);
|
||||
|
|
@ -1701,6 +1761,8 @@ void Object::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages);
|
||||
ClassDB::bind_method(D_METHOD("tr", "message", "context"), &Object::tr, DEFVAL(StringName()));
|
||||
ClassDB::bind_method(D_METHOD("tr_n", "message", "plural_message", "n", "context"), &Object::tr_n, DEFVAL(StringName()));
|
||||
ClassDB::bind_method(D_METHOD("get_translation_domain"), &Object::get_translation_domain);
|
||||
ClassDB::bind_method(D_METHOD("set_translation_domain", "domain"), &Object::set_translation_domain);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_queued_for_deletion"), &Object::is_queued_for_deletion);
|
||||
ClassDB::bind_method(D_METHOD("cancel_free"), &Object::cancel_free);
|
||||
|
|
@ -1713,33 +1775,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")));
|
||||
#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);
|
||||
BIND_OBJ_CORE_METHOD(MethodInfo("_init"));
|
||||
|
||||
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::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 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 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 +1995,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 +2026,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 +2039,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 +2063,6 @@ void Object::free_instance_binding(void *p_token) {
|
|||
if (found) {
|
||||
_instance_binding_count--;
|
||||
}
|
||||
_instance_binding_mutex.unlock();
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
|
@ -2075,7 +2164,7 @@ Object::~Object() {
|
|||
|
||||
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.");
|
||||
ERR_PRINT(vformat("Object '%s' 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.", to_string()));
|
||||
}
|
||||
|
||||
// Drop all connections to the signals of this object.
|
||||
|
|
@ -2097,7 +2186,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 +2218,7 @@ bool predelete_handler(Object *p_object) {
|
|||
}
|
||||
|
||||
void postinitialize_handler(Object *p_object) {
|
||||
p_object->_initialize();
|
||||
p_object->_postinitialize();
|
||||
}
|
||||
|
||||
|
|
@ -2286,7 +2380,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 +2390,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));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue