diff --git a/core/object/callable_method_pointer.h b/core/object/callable_method_pointer.h index 15849067108..2dbb7e468e4 100644 --- a/core/object/callable_method_pointer.h +++ b/core/object/callable_method_pointer.h @@ -198,7 +198,7 @@ class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase { } data; public: - virtual ObjectID get_object() const { + virtual ObjectID get_object() const override { #ifdef DEBUG_ENABLED if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) { return ObjectID(); @@ -207,7 +207,7 @@ public: return data.instance->get_instance_id(); } - virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { #ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method."); #endif @@ -254,11 +254,15 @@ class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase } data; public: - virtual ObjectID get_object() const { + virtual bool is_valid() const override { + return true; + } + + virtual ObjectID get_object() const override { return ObjectID(); } - virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error); r_return_value = Variant(); } @@ -292,11 +296,15 @@ class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerB } data; public: - virtual ObjectID get_object() const { + virtual bool is_valid() const override { + return true; + } + + virtual ObjectID get_object() const override { return ObjectID(); } - virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error); } diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp index 7a8dae2341f..83e0c4aea16 100644 --- a/core/object/message_queue.cpp +++ b/core/object/message_queue.cpp @@ -90,6 +90,10 @@ Error CallQueue::push_callablep(const Callable &p_callable, const Variant **p_ar if (p_show_error) { msg->type |= FLAG_SHOW_ERROR; } + // Support callables of static methods. + if (p_callable.get_object_id().is_null() && p_callable.is_valid()) { + msg->type |= FLAG_NULL_IS_OK; + } buffer_end += sizeof(Message); @@ -238,28 +242,24 @@ Error CallQueue::flush() { mutex.unlock(); - if (target != nullptr) { - switch (message->type & FLAG_MASK) { - case TYPE_CALL: { + switch (message->type & FLAG_MASK) { + case TYPE_CALL: { + if (target || (message->type & FLAG_NULL_IS_OK)) { Variant *args = (Variant *)(message + 1); - - // messages don't expect a return value - _call_function(message->callable, args, message->args, message->type & FLAG_SHOW_ERROR); - - } break; - case TYPE_NOTIFICATION: { - // messages don't expect a return value + } + } break; + case TYPE_NOTIFICATION: { + if (target) { target->notification(message->notification); - - } break; - case TYPE_SET: { + } + } break; + case TYPE_SET: { + if (target) { Variant *arg = (Variant *)(message + 1); - // messages don't expect a return value target->set(message->callable.get_method(), *arg); - - } break; - } + } + } break; } if ((message->type & FLAG_MASK) != TYPE_NOTIFICATION) { @@ -355,36 +355,41 @@ void CallQueue::statistics() { Object *target = message->callable.get_object(); - if (target != nullptr) { - switch (message->type & FLAG_MASK) { - case TYPE_CALL: { + bool null_target = true; + switch (message->type & FLAG_MASK) { + case TYPE_CALL: { + if (target || (message->type & FLAG_NULL_IS_OK)) { if (!call_count.has(message->callable)) { call_count[message->callable] = 0; } call_count[message->callable]++; - - } break; - case TYPE_NOTIFICATION: { + null_target = false; + } + } break; + case TYPE_NOTIFICATION: { + if (target) { if (!notify_count.has(message->notification)) { notify_count[message->notification] = 0; } notify_count[message->notification]++; - - } break; - case TYPE_SET: { + null_target = false; + } + } break; + case TYPE_SET: { + if (target) { StringName t = message->callable.get_method(); if (!set_count.has(t)) { set_count[t] = 0; } set_count[t]++; - - } break; - } - - } else { + null_target = false; + } + } break; + } + if (null_target) { //object was deleted print_line("Object was deleted while awaiting a callback"); diff --git a/core/object/message_queue.h b/core/object/message_queue.h index 525285e0617..68969dfd392 100644 --- a/core/object/message_queue.h +++ b/core/object/message_queue.h @@ -51,8 +51,9 @@ private: TYPE_NOTIFICATION, TYPE_SET, TYPE_END, // End marker. + FLAG_NULL_IS_OK = 1 << 13, FLAG_SHOW_ERROR = 1 << 14, - FLAG_MASK = FLAG_SHOW_ERROR - 1, + FLAG_MASK = FLAG_NULL_IS_OK - 1, }; struct Page { diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index 2f2acc55a60..630873ec2e6 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -122,7 +122,11 @@ Callable Callable::unbind(int p_argcount) const { } bool Callable::is_valid() const { - return get_object() && (is_custom() || get_object()->has_method(get_method())); + if (is_custom()) { + return get_custom()->is_valid(); + } else { + return get_object() && get_object()->has_method(get_method()); + } } Object *Callable::get_object() const { @@ -373,6 +377,11 @@ Callable::~Callable() { } } +bool CallableCustom::is_valid() const { + // Sensible default implementation so most custom callables don't need their own. + return ObjectDB::get_instance(get_object()); +} + StringName CallableCustom::get_method() const { ERR_FAIL_V_MSG(StringName(), vformat("Can't get method on CallableCustom \"%s\".", get_as_text())); } diff --git a/core/variant/callable.h b/core/variant/callable.h index 0abbb64c0bd..086e5d2a004 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -145,8 +145,9 @@ public: virtual String get_as_text() const = 0; virtual CompareEqualFunc get_compare_equal_func() const = 0; virtual CompareLessFunc get_compare_less_func() const = 0; + virtual bool is_valid() const; virtual StringName get_method() const; - virtual ObjectID get_object() const = 0; //must always be able to provide an object + virtual ObjectID get_object() const = 0; virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const = 0; virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const; virtual const Callable *get_base_comparator() const; diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp index 5be91c6e118..378d1ff618b 100644 --- a/core/variant/callable_bind.cpp +++ b/core/variant/callable_bind.cpp @@ -75,6 +75,10 @@ CallableCustom::CompareLessFunc CallableCustomBind::get_compare_less_func() cons return _less_func; } +bool CallableCustomBind::is_valid() const { + return callable.is_valid(); +} + StringName CallableCustomBind::get_method() const { return callable.get_method(); } @@ -193,6 +197,10 @@ CallableCustom::CompareLessFunc CallableCustomUnbind::get_compare_less_func() co return _less_func; } +bool CallableCustomUnbind::is_valid() const { + return callable.is_valid(); +} + StringName CallableCustomUnbind::get_method() const { return callable.get_method(); } diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h index 278ed335d08..b51076ad0ff 100644 --- a/core/variant/callable_bind.h +++ b/core/variant/callable_bind.h @@ -47,8 +47,9 @@ public: virtual String get_as_text() const override; virtual CompareEqualFunc get_compare_equal_func() const override; virtual CompareLessFunc get_compare_less_func() const override; + virtual bool is_valid() const override; virtual StringName get_method() const override; - virtual ObjectID get_object() const override; //must always be able to provide an object + virtual ObjectID get_object() const override; virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; virtual const Callable *get_base_comparator() const override; virtual int get_bound_arguments_count() const override; @@ -73,8 +74,9 @@ public: virtual String get_as_text() const override; virtual CompareEqualFunc get_compare_equal_func() const override; virtual CompareLessFunc get_compare_less_func() const override; + virtual bool is_valid() const override; virtual StringName get_method() const override; - virtual ObjectID get_object() const override; //must always be able to provide an object + virtual ObjectID get_object() const override; virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; virtual const Callable *get_base_comparator() const override; virtual int get_bound_arguments_count() const override;