feat: updated godot version
This commit is contained in:
parent
0c508b0831
commit
42b028dbb5
4694 changed files with 236470 additions and 401376 deletions
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include "object.h"
|
||||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/extension/gdextension_manager.h"
|
||||
#include "core/io/resource.h"
|
||||
#include "core/object/class_db.h"
|
||||
|
|
@ -66,45 +65,163 @@ struct _ObjectDebugLock {
|
|||
|
||||
#endif
|
||||
|
||||
struct ObjectSignalLock {
|
||||
Mutex *mutex1 = nullptr;
|
||||
Mutex *mutex2 = nullptr;
|
||||
|
||||
ObjectSignalLock(const Object *p_obj1, const Object *p_obj2 = nullptr) {
|
||||
mutex1 = p_obj1->signal_mutex;
|
||||
|
||||
if (p_obj2 != nullptr) {
|
||||
mutex2 = p_obj2->signal_mutex;
|
||||
|
||||
if (mutex2 < mutex1) {
|
||||
// We must always lock two locks in the same order.
|
||||
SWAP(mutex1, mutex2);
|
||||
} else if (unlikely(mutex2 == mutex1)) {
|
||||
// No point locking the same lock twice.
|
||||
mutex2 = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (mutex1) {
|
||||
mutex1->lock();
|
||||
}
|
||||
|
||||
if (mutex2) {
|
||||
mutex2->lock();
|
||||
struct _ObjectSignalLock {
|
||||
Mutex *mutex;
|
||||
_ObjectSignalLock(const Object *const p_obj) {
|
||||
mutex = p_obj->signal_mutex;
|
||||
if (mutex) {
|
||||
mutex->lock();
|
||||
}
|
||||
}
|
||||
|
||||
~ObjectSignalLock() {
|
||||
if (mutex2) {
|
||||
mutex2->unlock();
|
||||
}
|
||||
|
||||
if (mutex1) {
|
||||
mutex1->unlock();
|
||||
~_ObjectSignalLock() {
|
||||
if (mutex) {
|
||||
mutex->unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define OBJ_SIGNAL_LOCK _ObjectSignalLock _signal_lock(this);
|
||||
|
||||
PropertyInfo::operator Dictionary() const {
|
||||
Dictionary d;
|
||||
d["name"] = name;
|
||||
d["class_name"] = class_name;
|
||||
d["type"] = type;
|
||||
d["hint"] = hint;
|
||||
d["hint_string"] = hint_string;
|
||||
d["usage"] = usage;
|
||||
return d;
|
||||
}
|
||||
|
||||
PropertyInfo PropertyInfo::from_dict(const Dictionary &p_dict) {
|
||||
PropertyInfo pi;
|
||||
|
||||
if (p_dict.has("type")) {
|
||||
pi.type = Variant::Type(int(p_dict["type"]));
|
||||
}
|
||||
|
||||
if (p_dict.has("name")) {
|
||||
pi.name = p_dict["name"];
|
||||
}
|
||||
|
||||
if (p_dict.has("class_name")) {
|
||||
pi.class_name = p_dict["class_name"];
|
||||
}
|
||||
|
||||
if (p_dict.has("hint")) {
|
||||
pi.hint = PropertyHint(int(p_dict["hint"]));
|
||||
}
|
||||
|
||||
if (p_dict.has("hint_string")) {
|
||||
pi.hint_string = p_dict["hint_string"];
|
||||
}
|
||||
|
||||
if (p_dict.has("usage")) {
|
||||
pi.usage = p_dict["usage"];
|
||||
}
|
||||
|
||||
return pi;
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
return va;
|
||||
}
|
||||
|
||||
TypedArray<Dictionary> convert_property_list(const Vector<PropertyInfo> &p_vector) {
|
||||
TypedArray<Dictionary> va;
|
||||
for (const PropertyInfo &E : p_vector) {
|
||||
va.push_back(Dictionary(E));
|
||||
}
|
||||
|
||||
return va;
|
||||
}
|
||||
|
||||
MethodInfo::operator Dictionary() const {
|
||||
Dictionary d;
|
||||
d["name"] = name;
|
||||
d["args"] = convert_property_list(arguments);
|
||||
Array da;
|
||||
for (int i = 0; i < default_arguments.size(); i++) {
|
||||
da.push_back(default_arguments[i]);
|
||||
}
|
||||
d["default_args"] = da;
|
||||
d["flags"] = flags;
|
||||
d["id"] = id;
|
||||
Dictionary r = return_val;
|
||||
d["return"] = r;
|
||||
return d;
|
||||
}
|
||||
|
||||
MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) {
|
||||
MethodInfo mi;
|
||||
|
||||
if (p_dict.has("name")) {
|
||||
mi.name = p_dict["name"];
|
||||
}
|
||||
Array args;
|
||||
if (p_dict.has("args")) {
|
||||
args = p_dict["args"];
|
||||
}
|
||||
|
||||
for (const Variant &arg : args) {
|
||||
Dictionary d = arg;
|
||||
mi.arguments.push_back(PropertyInfo::from_dict(d));
|
||||
}
|
||||
Array defargs;
|
||||
if (p_dict.has("default_args")) {
|
||||
defargs = p_dict["default_args"];
|
||||
}
|
||||
for (const Variant &defarg : defargs) {
|
||||
mi.default_arguments.push_back(defarg);
|
||||
}
|
||||
|
||||
if (p_dict.has("return")) {
|
||||
mi.return_val = PropertyInfo::from_dict(p_dict["return"]);
|
||||
}
|
||||
|
||||
if (p_dict.has("flags")) {
|
||||
mi.flags = p_dict["flags"];
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -117,7 +234,6 @@ void ObjectGDExtension::create_gdtype() {
|
|||
ERR_FAIL_COND(gdtype);
|
||||
|
||||
gdtype = memnew(GDType(ClassDB::get_gdtype(parent_class_name), class_name));
|
||||
gdtype->initialize();
|
||||
}
|
||||
|
||||
void ObjectGDExtension::destroy_gdtype() {
|
||||
|
|
@ -500,8 +616,9 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
|
|||
|
||||
_get_property_listv(p_list, p_reversed);
|
||||
|
||||
const uint32_t base_script_usage = is_class(Script::get_class_static()) ? PROPERTY_USAGE_NO_EDITOR : PROPERTY_USAGE_DEFAULT;
|
||||
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, Script::get_class_static(), base_script_usage | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_NEVER_DUPLICATE));
|
||||
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 | PROPERTY_USAGE_NEVER_DUPLICATE));
|
||||
}
|
||||
|
||||
if (script_instance && !p_reversed) {
|
||||
script_instance->get_property_list(p_list);
|
||||
|
|
@ -513,10 +630,10 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
|
|||
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
|
||||
Object *obj = K.value;
|
||||
if (Object::cast_to<Script>(obj)) {
|
||||
pi.hint_string = Script::get_class_static();
|
||||
pi.hint_string = "Script";
|
||||
pi.usage |= PROPERTY_USAGE_NEVER_DUPLICATE;
|
||||
} else {
|
||||
pi.hint_string = Resource::get_class_static();
|
||||
pi.hint_string = "Resource";
|
||||
}
|
||||
}
|
||||
p_list->push_back(pi);
|
||||
|
|
@ -1093,7 +1210,7 @@ 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), vformat("User signal's name conflicts with a built-in signal of '%s'.", get_class_name()));
|
||||
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
ERR_FAIL_COND_MSG(signal_map.has(p_signal.name), vformat("Trying to add already existing signal '%s'.", p_signal.name));
|
||||
SignalData s;
|
||||
|
|
@ -1102,7 +1219,7 @@ void Object::add_user_signal(const MethodInfo &p_signal) {
|
|||
}
|
||||
|
||||
bool Object::_has_user_signal(const StringName &p_name) const {
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
if (!signal_map.has(p_name)) {
|
||||
return false;
|
||||
|
|
@ -1111,26 +1228,19 @@ bool Object::_has_user_signal(const StringName &p_name) const {
|
|||
}
|
||||
|
||||
void Object::_remove_user_signal(const StringName &p_name) {
|
||||
HashMap<Callable, Object::SignalData::Slot> slots_to_disconnect;
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
{
|
||||
ObjectSignalLock signal_lock(this);
|
||||
|
||||
SignalData *s = signal_map.getptr(p_name);
|
||||
ERR_FAIL_NULL_MSG(s, "Provided signal does not exist.");
|
||||
ERR_FAIL_COND_MSG(!s->removable, "Signal is not removable (not added with add_user_signal).");
|
||||
|
||||
slots_to_disconnect = std::move(s->slot_map);
|
||||
signal_map.erase(p_name);
|
||||
}
|
||||
|
||||
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : slots_to_disconnect) {
|
||||
SignalData *s = signal_map.getptr(p_name);
|
||||
ERR_FAIL_NULL_MSG(s, "Provided signal does not exist.");
|
||||
ERR_FAIL_COND_MSG(!s->removable, "Signal is not removable (not added with add_user_signal).");
|
||||
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
|
||||
Object *target = slot_kv.key.get_object();
|
||||
if (likely(target)) {
|
||||
ObjectSignalLock signal_lock(target);
|
||||
target->connections.erase(slot_kv.value.cE);
|
||||
}
|
||||
}
|
||||
|
||||
signal_map.erase(p_name);
|
||||
}
|
||||
|
||||
Error Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
|
||||
|
|
@ -1176,7 +1286,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
|
|||
uint32_t slot_count = 0;
|
||||
|
||||
{
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
SignalData *s = signal_map.getptr(p_name);
|
||||
if (!s) {
|
||||
|
|
@ -1203,19 +1313,19 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
|
|||
}
|
||||
|
||||
DEV_ASSERT(slot_count == s->slot_map.size());
|
||||
}
|
||||
|
||||
// Disconnect all one-shot connections before emitting to prevent recursion.
|
||||
for (uint32_t i = 0; i < slot_count; ++i) {
|
||||
bool disconnect = slot_flags[i] & CONNECT_ONE_SHOT;
|
||||
// Disconnect all one-shot connections before emitting to prevent recursion.
|
||||
for (uint32_t i = 0; i < slot_count; ++i) {
|
||||
bool disconnect = slot_flags[i] & CONNECT_ONE_SHOT;
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (disconnect && (slot_flags[i] & 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.
|
||||
disconnect = false;
|
||||
}
|
||||
if (disconnect && (slot_flags[i] & 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.
|
||||
disconnect = false;
|
||||
}
|
||||
#endif
|
||||
if (disconnect) {
|
||||
_disconnect(p_name, slot_callables[i]);
|
||||
if (disconnect) {
|
||||
_disconnect(p_name, slot_callables[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1331,16 +1441,12 @@ void Object::_reset_gdtype() const {
|
|||
}
|
||||
}
|
||||
|
||||
void Object::autorelease_gdtype(GDType **r_type) {
|
||||
ClassDB::gdtype_autorelease_pool.push_back(r_type);
|
||||
}
|
||||
|
||||
void Object::_add_user_signal(const String &p_name, const Array &p_args) {
|
||||
// this version of add_user_signal is meant to be used from scripts or external apis
|
||||
// without access to ADD_SIGNAL in bind_methods
|
||||
// added events are per instance, as opposed to the other ones, which are global
|
||||
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
MethodInfo mi;
|
||||
mi.name = p_name;
|
||||
|
|
@ -1394,8 +1500,6 @@ TypedArray<Dictionary> Object::_get_signal_connection_list(const StringName &p_s
|
|||
}
|
||||
|
||||
TypedArray<Dictionary> Object::_get_incoming_connections() const {
|
||||
ObjectSignalLock signal_lock(this);
|
||||
|
||||
TypedArray<Dictionary> ret;
|
||||
for (const Object::Connection &connection : connections) {
|
||||
ret.push_back(connection);
|
||||
|
|
@ -1421,7 +1525,7 @@ bool Object::has_signal(const StringName &p_name) const {
|
|||
}
|
||||
|
||||
void Object::get_signal_list(List<MethodInfo> *p_signals) const {
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
if (script_instance) {
|
||||
script_instance->get_script()->get_script_signal_list(p_signals);
|
||||
|
|
@ -1439,7 +1543,7 @@ void Object::get_signal_list(List<MethodInfo> *p_signals) const {
|
|||
}
|
||||
|
||||
void Object::get_all_signal_connections(List<Connection> *p_connections) const {
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
for (const KeyValue<StringName, SignalData> &E : signal_map) {
|
||||
const SignalData *s = &E.value;
|
||||
|
|
@ -1451,7 +1555,7 @@ void Object::get_all_signal_connections(List<Connection> *p_connections) const {
|
|||
}
|
||||
|
||||
void Object::get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const {
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
const SignalData *s = signal_map.getptr(p_signal);
|
||||
if (!s) {
|
||||
|
|
@ -1464,7 +1568,7 @@ void Object::get_signal_connection_list(const StringName &p_signal, List<Connect
|
|||
}
|
||||
|
||||
int Object::get_persistent_signal_connection_count() const {
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
int count = 0;
|
||||
|
||||
for (const KeyValue<StringName, SignalData> &E : signal_map) {
|
||||
|
|
@ -1481,7 +1585,7 @@ int Object::get_persistent_signal_connection_count() const {
|
|||
}
|
||||
|
||||
uint32_t Object::get_signal_connection_flags(const StringName &p_name, const Callable &p_callable) const {
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
const SignalData *signal_data = signal_map.getptr(p_name);
|
||||
if (signal_data) {
|
||||
const SignalData::Slot *slot = signal_data->slot_map.getptr(p_callable);
|
||||
|
|
@ -1493,7 +1597,7 @@ uint32_t Object::get_signal_connection_flags(const StringName &p_name, const Cal
|
|||
}
|
||||
|
||||
void Object::get_signals_connected_to_this(List<Connection> *p_connections) const {
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
for (const Connection &E : connections) {
|
||||
p_connections->push_back(E);
|
||||
|
|
@ -1502,14 +1606,13 @@ 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, vformat("Cannot connect to '%s': the provided callable is null.", p_signal));
|
||||
Object *target_object = p_callable.get_object();
|
||||
ObjectSignalLock signal_lock(this, target_object);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
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(target_object, ERR_INVALID_PARAMETER, vformat("Cannot connect to '%s' to callable '%s': the callable object is null.", p_signal, p_callable));
|
||||
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, vformat("Cannot connect to '%s': the provided callable is not valid: '%s'.", p_signal, p_callable));
|
||||
}
|
||||
|
|
@ -1548,6 +1651,8 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui
|
|||
}
|
||||
}
|
||||
|
||||
Object *target_object = p_callable.get_object();
|
||||
|
||||
SignalData::Slot slot;
|
||||
|
||||
Connection conn;
|
||||
|
|
@ -1570,7 +1675,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, 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`.
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
const SignalData *s = signal_map.getptr(p_signal);
|
||||
if (!s) {
|
||||
|
|
@ -1590,7 +1695,7 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable
|
|||
}
|
||||
|
||||
bool Object::has_connections(const StringName &p_signal) const {
|
||||
ObjectSignalLock signal_lock(this);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
const SignalData *s = signal_map.getptr(p_signal);
|
||||
if (!s) {
|
||||
|
|
@ -1615,8 +1720,7 @@ void Object::disconnect(const StringName &p_signal, const Callable &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, 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`.
|
||||
Object *target_object = p_callable.get_object();
|
||||
ObjectSignalLock signal_lock(this, target_object);
|
||||
OBJ_SIGNAL_LOCK
|
||||
|
||||
SignalData *s = signal_map.getptr(p_signal);
|
||||
if (!s) {
|
||||
|
|
@ -1637,8 +1741,11 @@ bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
|
|||
}
|
||||
}
|
||||
|
||||
if (likely(target_object)) {
|
||||
target_object->connections.erase(slot->cE);
|
||||
if (slot->cE) {
|
||||
Object *target_object = p_callable.get_object();
|
||||
if (target_object) {
|
||||
target_object->connections.erase(slot->cE);
|
||||
}
|
||||
}
|
||||
|
||||
s->slot_map.erase(*p_callable.get_base_comparator());
|
||||
|
|
@ -1686,18 +1793,10 @@ Variant Object::_get_indexed_bind(const NodePath &p_name) const {
|
|||
|
||||
void Object::initialize_class() {
|
||||
static bool initialized = false;
|
||||
if (likely(initialized)) {
|
||||
return;
|
||||
}
|
||||
|
||||
static BinaryMutex __init_mutex;
|
||||
MutexLock lock(__init_mutex);
|
||||
if (initialized) {
|
||||
// Initialized on another thread while we were waiting.
|
||||
return;
|
||||
}
|
||||
_add_class_to_classdb(get_gdtype_static_mutable(), nullptr);
|
||||
get_gdtype_static_mutable().initialize();
|
||||
_add_class_to_classdb(get_gdtype_static(), nullptr);
|
||||
_bind_methods();
|
||||
_bind_compatibility_methods();
|
||||
initialized = true;
|
||||
|
|
@ -1773,7 +1872,7 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) {
|
|||
}
|
||||
}
|
||||
|
||||
void Object::_add_class_to_classdb(GDType &p_type, const GDType *p_inherits) {
|
||||
void Object::_add_class_to_classdb(const GDType &p_type, const GDType *p_inherits) {
|
||||
ClassDB::_add_class(p_type, p_inherits);
|
||||
}
|
||||
|
||||
|
|
@ -1974,15 +2073,11 @@ void Object::_bind_methods() {
|
|||
BIND_CONSTANT(NOTIFICATION_PREDELETE);
|
||||
BIND_CONSTANT(NOTIFICATION_EXTENSION_RELOADED);
|
||||
|
||||
BIND_BITFIELD_FLAG(CONNECT_DEFERRED);
|
||||
BIND_BITFIELD_FLAG(CONNECT_PERSIST);
|
||||
BIND_BITFIELD_FLAG(CONNECT_ONE_SHOT);
|
||||
BIND_BITFIELD_FLAG(CONNECT_REFERENCE_COUNTED);
|
||||
BIND_BITFIELD_FLAG(CONNECT_APPEND_SOURCE_OBJECT);
|
||||
}
|
||||
|
||||
void Object::call_deferredp(const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
|
||||
MessageQueue::get_singleton()->push_callp(this, p_method, p_args, p_argcount);
|
||||
BIND_ENUM_CONSTANT(CONNECT_DEFERRED);
|
||||
BIND_ENUM_CONSTANT(CONNECT_PERSIST);
|
||||
BIND_ENUM_CONSTANT(CONNECT_ONE_SHOT);
|
||||
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
|
||||
BIND_ENUM_CONSTANT(CONNECT_APPEND_SOURCE_OBJECT);
|
||||
}
|
||||
|
||||
void Object::set_deferred(const StringName &p_property, const Variant &p_value) {
|
||||
|
|
@ -2164,8 +2259,8 @@ void *Object::get_instance_binding(void *p_token, const GDExtensionInstanceBindi
|
|||
}
|
||||
}
|
||||
if (unlikely(!binding && p_callbacks)) {
|
||||
uint32_t current_size = Math::next_power_of_2(_instance_binding_count);
|
||||
uint32_t new_size = Math::next_power_of_2(_instance_binding_count + 1);
|
||||
uint32_t current_size = next_power_of_2(_instance_binding_count);
|
||||
uint32_t new_size = next_power_of_2(_instance_binding_count + 1);
|
||||
|
||||
if (current_size == 0 || new_size > current_size) {
|
||||
_instance_bindings = (InstanceBinding *)memrealloc(_instance_bindings, new_size * sizeof(InstanceBinding));
|
||||
|
|
@ -2308,36 +2403,56 @@ void Object::detach_from_objectdb() {
|
|||
}
|
||||
}
|
||||
|
||||
void Object::assign_type_static(GDType **type_ptr, const char *p_name, const GDType *super_type) {
|
||||
static BinaryMutex _mutex;
|
||||
MutexLock lock(_mutex);
|
||||
GDType *type = *type_ptr;
|
||||
if (type) {
|
||||
// Assigned while we were waiting.
|
||||
return;
|
||||
}
|
||||
type = memnew(GDType(super_type, StringName(p_name)));
|
||||
*type_ptr = type;
|
||||
|
||||
ClassDB::gdtype_autorelease_pool.push_back(type_ptr);
|
||||
}
|
||||
|
||||
Object::~Object() {
|
||||
if (_emitting) {
|
||||
//@todo this may need to actually reach the debugger prioritarily somehow because it may crash before
|
||||
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.
|
||||
while (signal_map.size()) {
|
||||
// Avoid regular iteration so erasing is safe.
|
||||
KeyValue<StringName, SignalData> &E = *signal_map.begin();
|
||||
SignalData *s = &E.value;
|
||||
{
|
||||
OBJ_SIGNAL_LOCK
|
||||
// Drop all connections to the signals of this object.
|
||||
while (signal_map.size()) {
|
||||
// Avoid regular iteration so erasing is safe.
|
||||
KeyValue<StringName, SignalData> &E = *signal_map.begin();
|
||||
SignalData *s = &E.value;
|
||||
|
||||
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
|
||||
Object *target = slot_kv.value.conn.callable.get_object();
|
||||
if (likely(target)) {
|
||||
ObjectSignalLock signal_lock(this, target);
|
||||
target->connections.erase(slot_kv.value.cE);
|
||||
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
|
||||
Object *target = slot_kv.value.conn.callable.get_object();
|
||||
if (likely(target)) {
|
||||
target->connections.erase(slot_kv.value.cE);
|
||||
}
|
||||
}
|
||||
|
||||
signal_map.erase(E.key);
|
||||
}
|
||||
|
||||
signal_map.erase(E.key);
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (unlikely(!disconnected)) {
|
||||
// If the disconnect has failed, abandon the connection to avoid getting trapped in an infinite loop here.
|
||||
connections.pop_front();
|
||||
// Disconnect signals that connect to this object.
|
||||
while (connections.size()) {
|
||||
Connection c = connections.front()->get();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2523,7 +2638,7 @@ void ObjectDB::cleanup() {
|
|||
spin_lock.lock();
|
||||
|
||||
if (slot_count > 0) {
|
||||
WARN_PRINT(vformat("%d ObjectDB %s leaked at exit (run with `--verbose` for details).", slot_count, slot_count == 1 ? "instance was" : "instances were"));
|
||||
WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details).");
|
||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||
// 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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue