diff options
Diffstat (limited to 'core')
39 files changed, 1265 insertions, 422 deletions
diff --git a/core/array.cpp b/core/array.cpp index 2253d05605..7eb15ea934 100644 --- a/core/array.cpp +++ b/core/array.cpp @@ -308,9 +308,9 @@ struct _ArrayVariantSortCustom { _FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const { const Variant *args[2] = { &p_l, &p_r }; - Variant::CallError err; + Callable::CallError err; bool res = obj->call(func, args, 2, err); - if (err.error != Variant::CallError::CALL_OK) + if (err.error != Callable::CallError::CALL_OK) res = false; return res; } diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 583a44846f..f5a351f16a 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -2620,29 +2620,29 @@ void _Thread::_start_func(void *ud) { Ref<_Thread> *tud = (Ref<_Thread> *)ud; Ref<_Thread> t = *tud; memdelete(tud); - Variant::CallError ce; + Callable::CallError ce; const Variant *arg[1] = { &t->userdata }; Thread::set_name(t->target_method); t->ret = t->target_instance->call(t->target_method, arg, 1, ce); - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { String reason; switch (ce.error) { - case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT: { + case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { reason = "Invalid Argument #" + itos(ce.argument); } break; - case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { + case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { reason = "Too Many Arguments"; } break; - case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { + case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { reason = "Too Few Arguments"; } break; - case Variant::CallError::CALL_ERROR_INVALID_METHOD: { + case Callable::CallError::CALL_ERROR_INVALID_METHOD: { reason = "Method Not Found"; } break; diff --git a/core/callable.cpp b/core/callable.cpp new file mode 100644 index 0000000000..34b79cea10 --- /dev/null +++ b/core/callable.cpp @@ -0,0 +1,357 @@ +/*************************************************************************/ +/* callable.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "callable.h" +#include "core/script_language.h" +#include "message_queue.h" +#include "object.h" +#include "reference.h" + +void Callable::call_deferred(const Variant **p_arguments, int p_argcount) const { + MessageQueue::get_singleton()->push_callable(*this, p_arguments, p_argcount); +} + +void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const { + + if (is_null()) { + r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL; + r_call_error.argument = 0; + r_call_error.expected = 0; + r_return_value = Variant(); + } else if (is_custom()) { + custom->call(p_arguments, p_argcount, r_return_value, r_call_error); + } else { + Object *obj = ObjectDB::get_instance(ObjectID(object)); + r_return_value = obj->call(method, p_arguments, p_argcount, r_call_error); + } +} + +Object *Callable::get_object() const { + if (is_null()) { + return nullptr; + } else if (is_custom()) { + return ObjectDB::get_instance(custom->get_object()); + } else { + return ObjectDB::get_instance(ObjectID(object)); + } +} + +ObjectID Callable::get_object_id() const { + if (is_null()) { + return ObjectID(); + } else if (is_custom()) { + return custom->get_object(); + } else { + return ObjectID(object); + } +} +StringName Callable::get_method() const { + ERR_FAIL_COND_V(is_custom(), StringName()); + return method; +} +uint32_t Callable::hash() const { + if (is_custom()) { + return custom->hash(); + } else { + uint32_t hash = method.hash(); + return hash_djb2_one_64(object, hash); + } +} + +bool Callable::operator==(const Callable &p_callable) const { + bool custom_a = is_custom(); + bool custom_b = p_callable.is_custom(); + + if (custom_a == custom_b) { + if (custom_a) { + if (custom == p_callable.custom) { + return true; //same pointer, dont even compare + } + + CallableCustom::CompareEqualFunc eq_a = custom->get_compare_equal_func(); + CallableCustom::CompareEqualFunc eq_b = p_callable.custom->get_compare_equal_func(); + if (eq_a == eq_b) { + return eq_a(custom, p_callable.custom); + } else { + return false; + } + } else { + return object == p_callable.object && method == p_callable.method; + } + } else { + return false; + } +} +bool Callable::operator!=(const Callable &p_callable) const { + return !(*this == p_callable); +} +bool Callable::operator<(const Callable &p_callable) const { + bool custom_a = is_custom(); + bool custom_b = p_callable.is_custom(); + + if (custom_a == custom_b) { + if (custom_a) { + if (custom == p_callable.custom) { + return false; //same pointer, dont even compare + } + + CallableCustom::CompareLessFunc less_a = custom->get_compare_less_func(); + CallableCustom::CompareLessFunc less_b = p_callable.custom->get_compare_less_func(); + if (less_a == less_b) { + return less_a(custom, p_callable.custom); + } else { + return less_a < less_b; //it's something.. + } + + } else { + if (object == p_callable.object) { + return method < p_callable.method; + } else { + return object < p_callable.object; + } + } + } else { + return int(custom_a ? 1 : 0) < int(custom_b ? 1 : 0); + } +} + +void Callable::operator=(const Callable &p_callable) { + if (is_custom()) { + if (p_callable.is_custom()) { + if (custom == p_callable.custom) { + return; + } + } + + if (custom->ref_count.unref()) { + memdelete(custom); + } + } + + if (p_callable.is_custom()) { + method = StringName(); + if (!p_callable.custom->ref_count.ref()) { + object = 0; + } else { + object = 0; + custom = p_callable.custom; + } + } else { + method = p_callable.method; + object = p_callable.object; + } +} + +Callable::operator String() const { + + if (is_custom()) { + return custom->get_as_text(); + } else { + if (is_null()) { + return "null::null"; + } + + Object *base = get_object(); + if (base) { + String class_name = base->get_class(); + Ref<Script> script = base->get_script(); + if (script.is_valid() && script->get_path().is_resource_file()) { + + class_name += "(" + script->get_path().get_file() + ")"; + } + return class_name + "::" + String(method); + } else { + return "null::" + String(method); + } + } +} + +Callable::Callable(const Object *p_object, const StringName &p_method) { + if (p_method == StringName()) { + object = 0; + ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string"); + } + if (p_object == nullptr) { + object = 0; + ERR_FAIL_MSG("Object argument to Callable constructor must be non-null"); + } + + object = p_object->get_instance_id(); + method = p_method; +} + +Callable::Callable(ObjectID p_object, const StringName &p_method) { + if (p_method == StringName()) { + object = 0; + ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string"); + } + + object = p_object; + method = p_method; +} +Callable::Callable(CallableCustom *p_custom) { + if (p_custom->referenced) { + object = 0; + ERR_FAIL_MSG("Callable custom is already referenced"); + } + p_custom->referenced = true; + object = 0; //ensure object is all zero, since pointer may be 32 bits + custom = p_custom; +} +Callable::Callable(const Callable &p_callable) { + if (p_callable.is_custom()) { + if (!p_callable.custom->ref_count.ref()) { + object = 0; + } else { + object = 0; + custom = p_callable.custom; + } + } else { + method = p_callable.method; + object = p_callable.object; + } +} + +Callable::~Callable() { + if (is_custom()) { + if (custom->ref_count.unref()) { + memdelete(custom); + } + } +} + +Callable::Callable() { + object = 0; +} + +CallableCustom::CallableCustom() { + referenced = false; + ref_count.init(); +} + +////////////////////////////////// + +Object *Signal::get_object() const { + return ObjectDB::get_instance(object); +} +ObjectID Signal::get_object_id() const { + return object; +} +StringName Signal::get_name() const { + return name; +} + +bool Signal::operator==(const Signal &p_signal) const { + return object == p_signal.object && name == p_signal.name; +} + +bool Signal::operator!=(const Signal &p_signal) const { + return object != p_signal.object || name != p_signal.name; +} + +bool Signal::operator<(const Signal &p_signal) const { + if (object == p_signal.object) { + return name < p_signal.name; + } else { + return object < p_signal.object; + } +} + +Signal::operator String() const { + Object *base = get_object(); + if (base) { + String class_name = base->get_class(); + Ref<Script> script = base->get_script(); + if (script.is_valid() && script->get_path().is_resource_file()) { + + class_name += "(" + script->get_path().get_file() + ")"; + } + return class_name + "::[signal]" + String(name); + } else { + return "null::[signal]" + String(name); + } +} + +Error Signal::emit(const Variant **p_arguments, int p_argcount) const { + Object *obj = ObjectDB::get_instance(object); + if (!obj) { + return ERR_INVALID_DATA; + } + + return obj->emit_signal(name, p_arguments, p_argcount); +} +Error Signal::connect(const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) { + + Object *object = get_object(); + ERR_FAIL_COND_V(!object, ERR_UNCONFIGURED); + + return object->connect(name, p_callable, p_binds, p_flags); +} +void Signal::disconnect(const Callable &p_callable) { + Object *object = get_object(); + ERR_FAIL_COND(!object); + object->disconnect(name, p_callable); +} +bool Signal::is_connected(const Callable &p_callable) const { + Object *object = get_object(); + ERR_FAIL_COND_V(!object, false); + + return object->is_connected(name, p_callable); +} + +Array Signal::get_connections() const { + Object *object = get_object(); + if (!object) { + return Array(); + } + + List<Object::Connection> connections; + object->get_signal_connection_list(name, &connections); + + Array arr; + for (List<Object::Connection>::Element *E = connections.front(); E; E = E->next()) { + arr.push_back(E->get()); + } + return arr; +} +Signal::Signal(const Object *p_object, const StringName &p_name) { + + ERR_FAIL_COND_MSG(p_object == nullptr, "Object argument to Signal constructor must be non-null"); + + object = p_object->get_instance_id(); + name = p_name; +} +Signal::Signal(ObjectID p_object, const StringName &p_name) { + + object = p_object; + name = p_name; +} +Signal::Signal() { +} diff --git a/core/callable.h b/core/callable.h new file mode 100644 index 0000000000..8ea5377ce8 --- /dev/null +++ b/core/callable.h @@ -0,0 +1,162 @@ +/*************************************************************************/ +/* callable.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CALLABLE_H +#define CALLABLE_H + +#include "core/list.h" +#include "core/object_id.h" +#include "core/string_name.h" + +class Object; +class Variant; +class CallableCustom; + +// This is an abstraction of things that can be called +// it is used for signals and other cases where effient +// calling of functions is required. +// It is designed for the standard case (object and method) +// but can be optimized or customized. + +class Callable { + + //needs to be max 16 bytes in 64 bits + StringName method; + union { + uint64_t object; + CallableCustom *custom; + }; + +public: + struct CallError { + enum Error { + CALL_OK, + CALL_ERROR_INVALID_METHOD, + CALL_ERROR_INVALID_ARGUMENT, // expected is variant type + CALL_ERROR_TOO_MANY_ARGUMENTS, // expected is number of arguments + CALL_ERROR_TOO_FEW_ARGUMENTS, // expected is number of arguments + CALL_ERROR_INSTANCE_IS_NULL, + }; + Error error; + int argument; + int expected; + }; + + void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const; + void call_deferred(const Variant **p_arguments, int p_argcount) const; + + _FORCE_INLINE_ bool is_null() const { + return method == StringName() && object == 0; + } + _FORCE_INLINE_ bool is_custom() const { + return method == StringName() && custom != 0; + } + _FORCE_INLINE_ bool is_standard() const { + return method != StringName(); + } + + Object *get_object() const; + ObjectID get_object_id() const; + StringName get_method() const; + + uint32_t hash() const; + + bool operator==(const Callable &p_callable) const; + bool operator!=(const Callable &p_callable) const; + bool operator<(const Callable &p_callable) const; + + void operator=(const Callable &p_callable); + + operator String() const; + + Callable(const Object *p_object, const StringName &p_method); + Callable(ObjectID p_object, const StringName &p_method); + Callable(CallableCustom *p_custom); + Callable(const Callable &p_callable); + Callable(); + ~Callable(); +}; + +class CallableCustom { + friend class Callable; + SafeRefCount ref_count; + bool referenced; + +public: + typedef bool (*CompareEqualFunc)(const CallableCustom *p_a, const CallableCustom *p_b); + typedef bool (*CompareLessFunc)(const CallableCustom *p_a, const CallableCustom *p_b); + + //for every type that inherits, these must always be the same for this type + virtual uint32_t hash() const = 0; + virtual String get_as_text() const = 0; + virtual CompareEqualFunc get_compare_equal_func() const = 0; + virtual CompareLessFunc get_compare_less_func() const = 0; + virtual ObjectID get_object() const = 0; //must always be able to provide an object + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const = 0; + + CallableCustom(); + virtual ~CallableCustom() {} +}; + +// This is just a proxy object to object signals, its only +// allocated on demand by/for scripting languages so it can +// be put inside a Variant, but it is not +// used by the engine itself. + +class Signal { + StringName name; + ObjectID object; + +public: + _FORCE_INLINE_ bool is_null() const { + return object.is_null() && name == StringName(); + } + Object *get_object() const; + ObjectID get_object_id() const; + StringName get_name() const; + + bool operator==(const Signal &p_signal) const; + bool operator!=(const Signal &p_signal) const; + bool operator<(const Signal &p_signal) const; + + operator String() const; + + Error emit(const Variant **p_arguments, int p_argcount) const; + Error connect(const Callable &p_callable, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); + void disconnect(const Callable &p_callable); + bool is_connected(const Callable &p_callable) const; + + Array get_connections() const; + Signal(const Object *p_object, const StringName &p_name); + Signal(ObjectID p_object, const StringName &p_name); + Signal(); +}; + +#endif // CALLABLE_H diff --git a/core/class_db.cpp b/core/class_db.cpp index a2941d70f6..35e216a58f 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -1033,7 +1033,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const return true; //return true but do nothing } - Variant::CallError ce; + Callable::CallError ce; if (psg->index >= 0) { Variant index = psg->index; @@ -1055,7 +1055,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const } if (r_valid) - *r_valid = ce.error == Variant::CallError::CALL_OK; + *r_valid = ce.error == Callable::CallError::CALL_OK; return true; } @@ -1078,12 +1078,12 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia if (psg->index >= 0) { Variant index = psg->index; const Variant *arg[1] = { &index }; - Variant::CallError ce; + Callable::CallError ce; r_value = p_object->call(psg->getter, arg, 1, ce); } else { - Variant::CallError ce; + Callable::CallError ce; if (psg->_getptr) { r_value = psg->_getptr->call(p_object, NULL, 0, ce); @@ -1094,13 +1094,23 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia return true; } - const int *c = check->constant_map.getptr(p_property); + const int *c = check->constant_map.getptr(p_property); //constants count if (c) { r_value = *c; return true; } + if (check->method_map.has(p_property)) { //methods count + r_value = Callable(p_object, p_property); + return true; + } + + if (check->signal_map.has(p_property)) { //signals count + r_value = Signal(p_object, p_property); + return true; + } + check = check->inherits_ptr; } diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp index bafb800e41..253d5f1acb 100644 --- a/core/core_string_names.cpp +++ b/core/core_string_names.cpp @@ -70,5 +70,9 @@ CoreStringNames::CoreStringNames() : r8(StaticCString::create("r8")), g8(StaticCString::create("g8")), b8(StaticCString::create("b8")), - a8(StaticCString::create("a8")) { + a8(StaticCString::create("a8")), + call(StaticCString::create("call")), + call_deferred(StaticCString::create("call_deferred")), + emit(StaticCString::create("emit")), + notification(StaticCString::create("notification")) { } diff --git a/core/core_string_names.h b/core/core_string_names.h index a507a20935..42416d3f75 100644 --- a/core/core_string_names.h +++ b/core/core_string_names.h @@ -90,6 +90,11 @@ public: StringName g8; StringName b8; StringName a8; + + StringName call; + StringName call_deferred; + StringName emit; + StringName notification; }; #endif // SCENE_STRING_NAMES_H diff --git a/core/func_ref.cpp b/core/func_ref.cpp index e20188c813..338c17946b 100644 --- a/core/func_ref.cpp +++ b/core/func_ref.cpp @@ -30,16 +30,16 @@ #include "func_ref.h" -Variant FuncRef::call_func(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +Variant FuncRef::call_func(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (id.is_null()) { - r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; + r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; return Variant(); } Object *obj = ObjectDB::get_instance(id); if (!obj) { - r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; + r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; return Variant(); } diff --git a/core/func_ref.h b/core/func_ref.h index 1d1ca47ad7..8cb3be6e61 100644 --- a/core/func_ref.h +++ b/core/func_ref.h @@ -43,7 +43,7 @@ protected: static void _bind_methods(); public: - Variant call_func(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + Variant call_func(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Variant call_funcv(const Array &p_args); void set_instance(Object *p_obj); void set_function(const StringName &p_func); diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 94713b4ee6..b990ec9276 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -609,6 +609,8 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH); // 15 BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_RID", Variant::_RID); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_OBJECT", Variant::OBJECT); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_CALLABLE", Variant::CALLABLE); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_SIGNAL", Variant::SIGNAL); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_DICTIONARY", Variant::DICTIONARY); // 20 BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_ARRAY", Variant::ARRAY); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_RAW_ARRAY", Variant::PACKED_BYTE_ARRAY); diff --git a/core/io/dtls_server.cpp b/core/io/dtls_server.cpp index aa302ced8f..07e6abb1c9 100644 --- a/core/io/dtls_server.cpp +++ b/core/io/dtls_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/core/io/dtls_server.h b/core/io/dtls_server.h index ebef13da64..7b08138f7f 100644 --- a/core/io/dtls_server.h +++ b/core/io/dtls_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 6548faac9f..ab88f4d85c 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -455,6 +455,15 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } } break; + case Variant::CALLABLE: { + + r_variant = Callable(); + } break; + case Variant::SIGNAL: { + + r_variant = Signal(); + } break; + case Variant::DICTIONARY: { ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); @@ -1075,6 +1084,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo case Variant::_RID: { } break; + case Variant::CALLABLE: { + + } break; + case Variant::SIGNAL: { + + } break; case Variant::OBJECT: { if (p_full_objects) { diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index abe629ecba..1fcd00c0e4 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -145,22 +145,22 @@ void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_pee "Supplied NetworkedMultiplayerPeer must be connecting or connected."); if (network_peer.is_valid()) { - network_peer->disconnect("peer_connected", this, "_add_peer"); - network_peer->disconnect("peer_disconnected", this, "_del_peer"); - network_peer->disconnect("connection_succeeded", this, "_connected_to_server"); - network_peer->disconnect("connection_failed", this, "_connection_failed"); - network_peer->disconnect("server_disconnected", this, "_server_disconnected"); + network_peer->disconnect_compat("peer_connected", this, "_add_peer"); + network_peer->disconnect_compat("peer_disconnected", this, "_del_peer"); + network_peer->disconnect_compat("connection_succeeded", this, "_connected_to_server"); + network_peer->disconnect_compat("connection_failed", this, "_connection_failed"); + network_peer->disconnect_compat("server_disconnected", this, "_server_disconnected"); clear(); } network_peer = p_peer; if (network_peer.is_valid()) { - network_peer->connect("peer_connected", this, "_add_peer"); - network_peer->connect("peer_disconnected", this, "_del_peer"); - network_peer->connect("connection_succeeded", this, "_connected_to_server"); - network_peer->connect("connection_failed", this, "_connection_failed"); - network_peer->connect("server_disconnected", this, "_server_disconnected"); + network_peer->connect_compat("peer_connected", this, "_add_peer"); + network_peer->connect_compat("peer_disconnected", this, "_del_peer"); + network_peer->connect_compat("connection_succeeded", this, "_connected_to_server"); + network_peer->connect_compat("connection_failed", this, "_connection_failed"); + network_peer->connect_compat("server_disconnected", this, "_server_disconnected"); } } @@ -368,10 +368,10 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, p_offset += vlen; } - Variant::CallError ce; + Callable::CallError ce; p_node->call(name, (const Variant **)argp.ptr(), argc, ce); - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { String error = Variant::get_call_error_text(p_node, name, (const Variant **)argp.ptr(), argc, ce); error = "RPC - " + error; ERR_PRINT(error); @@ -989,10 +989,10 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const if (call_local_native) { int temp_id = rpc_sender_id; rpc_sender_id = get_network_unique_id(); - Variant::CallError ce; + Callable::CallError ce; p_node->call(p_method, p_arg, p_argcount, ce); rpc_sender_id = temp_id; - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); error = "rpc() aborted in local call: - " + error + "."; ERR_PRINT(error); @@ -1003,11 +1003,11 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const if (call_local_script) { int temp_id = rpc_sender_id; rpc_sender_id = get_network_unique_id(); - Variant::CallError ce; - ce.error = Variant::CallError::CALL_OK; + Callable::CallError ce; + ce.error = Callable::CallError::CALL_OK; p_node->get_script_instance()->call(p_method, p_arg, p_argcount, ce); rpc_sender_id = temp_id; - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); error = "rpc() aborted in script local call: - " + error + "."; ERR_PRINT(error); diff --git a/core/io/packet_peer_dtls.cpp b/core/io/packet_peer_dtls.cpp index 64007c7e3b..01218a6881 100644 --- a/core/io/packet_peer_dtls.cpp +++ b/core/io/packet_peer_dtls.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/core/io/packet_peer_dtls.h b/core/io/packet_peer_dtls.h index b7cabb6ae0..4f9f4535bc 100644 --- a/core/io/packet_peer_dtls.h +++ b/core/io/packet_peer_dtls.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index d4c1fd2e9b..991853e86d 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -73,6 +73,8 @@ enum { VARIANT_VECTOR2_ARRAY = 37, VARIANT_INT64 = 40, VARIANT_DOUBLE = 41, + VARIANT_CALLABLE = 42, + VARIANT_SIGNAL = 43, OBJECT_EMPTY = 0, OBJECT_EXTERNAL_RESOURCE = 1, OBJECT_INTERNAL_RESOURCE = 2, @@ -363,6 +365,15 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { } } break; + case VARIANT_CALLABLE: { + + r_v = Callable(); + } break; + case VARIANT_SIGNAL: { + + r_v = Signal(); + } break; + case VARIANT_DICTIONARY: { uint32_t len = f->get_32(); @@ -1440,6 +1451,17 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia } } break; + case Variant::CALLABLE: { + + f->store_32(VARIANT_CALLABLE); + WARN_PRINT("Can't save Callables."); + } break; + case Variant::SIGNAL: { + + f->store_32(VARIANT_SIGNAL); + WARN_PRINT("Can't save Signals."); + } break; + case Variant::DICTIONARY: { f->store_32(VARIANT_DICTIONARY); diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp index f041bf097f..16b7863cdd 100644 --- a/core/io/udp_server.cpp +++ b/core/io/udp_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/core/io/udp_server.h b/core/io/udp_server.h index 5182a04246..90bb82b62b 100644 --- a/core/io/udp_server.h +++ b/core/io/udp_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/core/make_binders.py b/core/make_binders.py index 11cfbf6e79..c42b91fbe5 100644 --- a/core/make_binders.py +++ b/core/make_binders.py @@ -32,22 +32,22 @@ public: return T::get_class_static(); } - virtual Variant call(Object* p_object,const Variant** p_args,int p_arg_count, Variant::CallError& r_error) { + virtual Variant call(Object* p_object,const Variant** p_args,int p_arg_count, Callable::CallError& r_error) { T *instance=Object::cast_to<T>(p_object); - r_error.error=Variant::CallError::CALL_OK; + r_error.error=Callable::CallError::CALL_OK; #ifdef DEBUG_METHODS_ENABLED ERR_FAIL_COND_V(!instance,Variant()); if (p_arg_count>get_argument_count()) { - r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.error=Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=get_argument_count(); return Variant(); } if (p_arg_count<(get_argument_count()-get_default_argument_count())) { - r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.error=Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=get_argument_count()-get_default_argument_count(); return Variant(); } @@ -126,23 +126,23 @@ public: return type_name; } - virtual Variant call(Object* p_object,const Variant** p_args,int p_arg_count, Variant::CallError& r_error) { + virtual Variant call(Object* p_object,const Variant** p_args,int p_arg_count, Callable::CallError& r_error) { __UnexistingClass *instance = (__UnexistingClass*)p_object; - r_error.error=Variant::CallError::CALL_OK; + r_error.error=Callable::CallError::CALL_OK; #ifdef DEBUG_METHODS_ENABLED ERR_FAIL_COND_V(!instance,Variant()); if (p_arg_count>get_argument_count()) { - r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.error=Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=get_argument_count(); return Variant(); } if (p_arg_count<(get_argument_count()-get_default_argument_count())) { - r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.error=Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=get_argument_count()-get_default_argument_count(); return Variant(); } @@ -223,22 +223,22 @@ public: return T::get_class_static(); } - virtual Variant call(Object* p_object,const Variant** p_args,int p_arg_count, Variant::CallError& r_error) { + virtual Variant call(Object* p_object,const Variant** p_args,int p_arg_count, Callable::CallError& r_error) { T *instance=Object::cast_to<T>(p_object); - r_error.error=Variant::CallError::CALL_OK; + r_error.error=Callable::CallError::CALL_OK; #ifdef DEBUG_METHODS_ENABLED ERR_FAIL_COND_V(!instance,Variant()); if (p_arg_count>get_argument_count()) { - r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.error=Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=get_argument_count(); return Variant(); } if (p_arg_count<(get_argument_count()-get_default_argument_count())) { - r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.error=Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=get_argument_count()-get_default_argument_count(); return Variant(); } diff --git a/core/math/expression.cpp b/core/math/expression.cpp index c7229ef688..1130935567 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -208,16 +208,16 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) { return 0; } -#define VALIDATE_ARG_NUM(m_arg) \ - if (!p_inputs[m_arg]->is_num()) { \ - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; \ - r_error.argument = m_arg; \ - r_error.expected = Variant::REAL; \ - return; \ +#define VALIDATE_ARG_NUM(m_arg) \ + if (!p_inputs[m_arg]->is_num()) { \ + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \ + r_error.argument = m_arg; \ + r_error.expected = Variant::REAL; \ + return; \ } -void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Variant::CallError &r_error, String &r_error_str) { - r_error.error = Variant::CallError::CALL_OK; +void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Callable::CallError &r_error, String &r_error_str) { + r_error.error = Callable::CallError::CALL_OK; switch (p_func) { case MATH_SIN: { @@ -320,7 +320,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return = Math::abs(r); } else { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::REAL; } @@ -337,7 +337,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0); } else { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::REAL; } @@ -580,7 +580,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant if (p_inputs[0]->get_type() != Variant::OBJECT) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; @@ -614,7 +614,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant if (p_inputs[0]->get_type() != Variant::OBJECT) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; @@ -622,7 +622,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant } if (p_inputs[1]->get_type() != Variant::STRING && p_inputs[1]->get_type() != Variant::NODE_PATH) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; r_error.expected = Variant::STRING; @@ -644,7 +644,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant if (type < 0 || type >= Variant::VARIANT_MAX) { r_error_str = RTR("Invalid type argument to convert(), use TYPE_* constants."); - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::INT; return; @@ -675,7 +675,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant if (p_inputs[0]->get_type() != Variant::STRING) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; @@ -687,7 +687,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant if (str.length() != 1) { r_error_str = RTR("Expected a string of length 1 (a character)."); - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; @@ -732,7 +732,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant case STR_TO_VAR: { if (p_inputs[0]->get_type() != Variant::STRING) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; @@ -747,7 +747,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant Error err = VariantParser::parse(&ss, *r_return, errs, line); if (err != OK) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; *r_return = "Parse error at line " + itos(line) + ": " + errs; @@ -762,7 +762,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant int len; Error err = encode_variant(*p_inputs[0], NULL, len, full_objects); if (err) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::NIL; r_error_str = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; @@ -779,7 +779,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant case BYTES_TO_VAR: { if (p_inputs[0]->get_type() != Variant::PACKED_BYTE_ARRAY) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::PACKED_BYTE_ARRAY; @@ -794,7 +794,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant Error err = decode_variant(ret, r, varr.size(), NULL, allow_objects); if (err != OK) { r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format."); - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::PACKED_BYTE_ARRAY; return; @@ -2071,10 +2071,10 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: argp.write[i] = &arr[i]; } - Variant::CallError ce; + Callable::CallError ce; r_ret = Variant::construct(constructor->data_type, (const Variant **)argp.ptr(), argp.size(), ce); - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { r_error_str = vformat(RTR("Invalid arguments to construct '%s'"), Variant::get_type_name(constructor->data_type)); return true; } @@ -2099,10 +2099,10 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: argp.write[i] = &arr[i]; } - Variant::CallError ce; + Callable::CallError ce; exec_func(bifunc->func, (const Variant **)argp.ptr(), &r_ret, ce, r_error_str); - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { r_error_str = "Builtin Call Failed. " + r_error_str; return true; } @@ -2134,10 +2134,10 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: argp.write[i] = &arr[i]; } - Variant::CallError ce; + Callable::CallError ce; r_ret = base.call(call->method, (const Variant **)argp.ptr(), argp.size(), ce); - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { r_error_str = vformat(RTR("On call to '%s':"), String(call->method)); return true; } diff --git a/core/math/expression.h b/core/math/expression.h index 1cd1415dcf..bbf946bb0a 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -111,7 +111,7 @@ public: static int get_func_argument_count(BuiltinFunc p_func); static String get_func_name(BuiltinFunc p_func); - static void exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Variant::CallError &r_error, String &r_error_str); + static void exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Callable::CallError &r_error, String &r_error_str); static BuiltinFunc find_function(const String &p_string); private: diff --git a/core/message_queue.cpp b/core/message_queue.cpp index 42390935d4..235003627e 100644 --- a/core/message_queue.cpp +++ b/core/message_queue.cpp @@ -30,6 +30,7 @@ #include "message_queue.h" +#include "core/core_string_names.h" #include "core/project_settings.h" #include "core/script_language.h" @@ -42,37 +43,7 @@ MessageQueue *MessageQueue::get_singleton() { Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) { - _THREAD_SAFE_METHOD_ - - int room_needed = sizeof(Message) + sizeof(Variant) * p_argcount; - - if ((buffer_end + room_needed) >= buffer_size) { - String type; - if (ObjectDB::get_instance(p_id)) - type = ObjectDB::get_instance(p_id)->get_class(); - print_line("Failed method: " + type + ":" + p_method + " target ID: " + itos(p_id)); - statistics(); - ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Message queue out of memory. Try increasing 'memory/limits/message_queue/max_size_kb' in project settings."); - } - - Message *msg = memnew_placement(&buffer[buffer_end], Message); - msg->args = p_argcount; - msg->instance_id = p_id; - msg->target = p_method; - msg->type = TYPE_CALL; - if (p_show_error) - msg->type |= FLAG_SHOW_ERROR; - - buffer_end += sizeof(Message); - - for (int i = 0; i < p_argcount; i++) { - - Variant *v = memnew_placement(&buffer[buffer_end], Variant); - buffer_end += sizeof(Variant); - *v = *p_args[i]; - } - - return OK; + return push_callable(Callable(p_id, p_method), p_args, p_argcount, p_show_error); } Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { @@ -107,8 +78,7 @@ Error MessageQueue::push_set(ObjectID p_id, const StringName &p_prop, const Vari Message *msg = memnew_placement(&buffer[buffer_end], Message); msg->args = 1; - msg->instance_id = p_id; - msg->target = p_prop; + msg->callable = Callable(p_id, p_prop); msg->type = TYPE_SET; buffer_end += sizeof(Message); @@ -137,7 +107,7 @@ Error MessageQueue::push_notification(ObjectID p_id, int p_notification) { Message *msg = memnew_placement(&buffer[buffer_end], Message); msg->type = TYPE_NOTIFICATION; - msg->instance_id = p_id; + msg->callable = Callable(p_id, CoreStringNames::get_singleton()->notification); //name is meaningless but callable needs it //msg->target; msg->notification = p_notification; @@ -160,18 +130,49 @@ Error MessageQueue::push_set(Object *p_object, const StringName &p_prop, const V return push_set(p_object->get_instance_id(), p_prop, p_value); } +Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error) { + + _THREAD_SAFE_METHOD_ + + int room_needed = sizeof(Message) + sizeof(Variant) * p_argcount; + + if ((buffer_end + room_needed) >= buffer_size) { + print_line("Failed method: " + p_callable); + statistics(); + ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Message queue out of memory. Try increasing 'memory/limits/message_queue/max_size_kb' in project settings."); + } + + Message *msg = memnew_placement(&buffer[buffer_end], Message); + msg->args = p_argcount; + msg->callable = p_callable; + msg->type = TYPE_CALL; + if (p_show_error) + msg->type |= FLAG_SHOW_ERROR; + + buffer_end += sizeof(Message); + + for (int i = 0; i < p_argcount; i++) { + + Variant *v = memnew_placement(&buffer[buffer_end], Variant); + buffer_end += sizeof(Variant); + *v = *p_args[i]; + } + + return OK; +} + void MessageQueue::statistics() { Map<StringName, int> set_count; Map<int, int> notify_count; - Map<StringName, int> call_count; + Map<Callable, int> call_count; int null_count = 0; uint32_t read_pos = 0; while (read_pos < buffer_end) { Message *message = (Message *)&buffer[read_pos]; - Object *target = ObjectDB::get_instance(message->instance_id); + Object *target = message->callable.get_object(); if (target != NULL) { @@ -179,10 +180,10 @@ void MessageQueue::statistics() { case TYPE_CALL: { - if (!call_count.has(message->target)) - call_count[message->target] = 0; + if (!call_count.has(message->callable)) + call_count[message->callable] = 0; - call_count[message->target]++; + call_count[message->callable]++; } break; case TYPE_NOTIFICATION: { @@ -195,10 +196,11 @@ void MessageQueue::statistics() { } break; case TYPE_SET: { - if (!set_count.has(message->target)) - set_count[message->target] = 0; + StringName t = message->callable.get_method(); + if (!set_count.has(t)) + set_count[t] = 0; - set_count[message->target]++; + set_count[t]++; } break; } @@ -222,7 +224,7 @@ void MessageQueue::statistics() { print_line("SET " + E->key() + ": " + itos(E->get())); } - for (Map<StringName, int>::Element *E = call_count.front(); E; E = E->next()) { + for (Map<Callable, int>::Element *E = call_count.front(); E; E = E->next()) { print_line("CALL " + E->key() + ": " + itos(E->get())); } @@ -236,7 +238,7 @@ int MessageQueue::get_max_buffer_usage() const { return buffer_max_used; } -void MessageQueue::_call_function(Object *p_target, const StringName &p_func, const Variant *p_args, int p_argcount, bool p_show_error) { +void MessageQueue::_call_function(const Callable &p_callable, const Variant *p_args, int p_argcount, bool p_show_error) { const Variant **argptrs = NULL; if (p_argcount) { @@ -246,11 +248,12 @@ void MessageQueue::_call_function(Object *p_target, const StringName &p_func, co } } - Variant::CallError ce; - p_target->call(p_func, argptrs, p_argcount, ce); - if (p_show_error && ce.error != Variant::CallError::CALL_OK) { + Callable::CallError ce; + Variant ret; + p_callable.call(argptrs, p_argcount, ret, ce); + if (p_show_error && ce.error != Callable::CallError::CALL_OK) { - ERR_PRINT("Error calling deferred method: " + Variant::get_call_error_text(p_target, p_func, argptrs, p_argcount, ce) + "."); + ERR_PRINT("Error calling deferred method: " + Variant::get_callable_error_text(p_callable, argptrs, p_argcount, ce) + "."); } } @@ -283,7 +286,7 @@ void MessageQueue::flush() { _THREAD_SAFE_UNLOCK_ - Object *target = ObjectDB::get_instance(message->instance_id); + Object *target = message->callable.get_object(); if (target != NULL) { @@ -294,7 +297,7 @@ void MessageQueue::flush() { // messages don't expect a return value - _call_function(target, message->target, args, message->args, message->type & FLAG_SHOW_ERROR); + _call_function(message->callable, args, message->args, message->type & FLAG_SHOW_ERROR); } break; case TYPE_NOTIFICATION: { @@ -307,7 +310,7 @@ void MessageQueue::flush() { Variant *arg = (Variant *)(message + 1); // messages don't expect a return value - target->set(message->target, *arg); + target->set(message->callable.get_method(), *arg); } break; } diff --git a/core/message_queue.h b/core/message_queue.h index e9a92ff5b7..9ba748bb42 100644 --- a/core/message_queue.h +++ b/core/message_queue.h @@ -54,8 +54,7 @@ class MessageQueue { struct Message { - ObjectID instance_id; - StringName target; + Callable callable; int16_t type; union { int16_t notification; @@ -68,7 +67,7 @@ class MessageQueue { uint32_t buffer_max_used; uint32_t buffer_size; - void _call_function(Object *p_target, const StringName &p_func, const Variant *p_args, int p_argcount, bool p_show_error); + void _call_function(const Callable &p_callable, const Variant *p_args, int p_argcount, bool p_show_error); static MessageQueue *singleton; @@ -81,6 +80,7 @@ public: Error push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_LIST); Error push_notification(ObjectID p_id, int p_notification); Error push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value); + Error push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false); Error push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST); Error push_notification(Object *p_object, int p_notification); diff --git a/core/method_bind.h b/core/method_bind.h index 1860d227f7..72be141fd3 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -155,7 +155,7 @@ struct VariantObjectClassChecker<Control *> { Variant::Type argtype = get_argument_type(m_arg - 1); \ if (!Variant::can_convert_strict(p_args[m_arg - 1]->get_type(), argtype) || \ !VariantObjectClassChecker<P##m_arg>::check(*p_args[m_arg - 1])) { \ - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; \ + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \ r_error.argument = m_arg - 1; \ r_error.expected = argtype; \ return Variant(); \ @@ -278,7 +278,7 @@ public: _FORCE_INLINE_ int get_argument_count() const { return argument_count; }; - virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Variant::CallError &r_error) = 0; + virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) = 0; #ifdef PTRCALL_ENABLED virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) = 0; @@ -300,7 +300,7 @@ public: template <class T> class MethodBindVarArg : public MethodBind { public: - typedef Variant (T::*NativeCall)(const Variant **, int, Variant::CallError &); + typedef Variant (T::*NativeCall)(const Variant **, int, Callable::CallError &); protected: NativeCall call_method; @@ -338,7 +338,7 @@ public: } #endif - virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Variant::CallError &r_error) { + virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { T *instance = static_cast<T *>(p_object); return (instance->*call_method)(p_args, p_arg_count, r_error); @@ -389,7 +389,7 @@ public: }; template <class T> -MethodBind *create_vararg_method_bind(Variant (T::*p_method)(const Variant **, int, Variant::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) { +MethodBind *create_vararg_method_bind(Variant (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) { MethodBindVarArg<T> *a = memnew((MethodBindVarArg<T>)); a->set_method(p_method); diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h index 6ccf41229f..42d71dea46 100644 --- a/core/method_ptrcall.h +++ b/core/method_ptrcall.h @@ -128,6 +128,8 @@ MAKE_PTRARG_BY_REFERENCE(Color); MAKE_PTRARG(NodePath); MAKE_PTRARG(RID); MAKE_PTRARG(Dictionary); +MAKE_PTRARG(Callable); +MAKE_PTRARG(Signal); MAKE_PTRARG(Array); MAKE_PTRARG(PackedByteArray); MAKE_PTRARG(PackedIntArray); diff --git a/core/object.cpp b/core/object.cpp index f0b708f047..d5db383cbc 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -335,10 +335,8 @@ MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const Pr Object::Connection::operator Variant() const { Dictionary d; - d["source"] = source; d["signal"] = signal; - d["target"] = target; - d["method"] = method; + d["callable"] = callable; d["flags"] = flags; d["binds"] = binds; return d; @@ -346,34 +344,19 @@ Object::Connection::operator Variant() const { bool Object::Connection::operator<(const Connection &p_conn) const { - if (source == p_conn.source) { - - if (signal == p_conn.signal) { - - if (target == p_conn.target) { - - return method < p_conn.method; - } else { - - return target < p_conn.target; - } - } else - return signal < p_conn.signal; + if (signal == p_conn.signal) { + return callable < p_conn.callable; } else { - return source < p_conn.source; + return signal < p_conn.signal; } } Object::Connection::Connection(const Variant &p_variant) { Dictionary d = p_variant; - if (d.has("source")) - source = d["source"]; if (d.has("signal")) signal = d["signal"]; - if (d.has("target")) - target = d["target"]; - if (d.has("method")) - method = d["method"]; + if (d.has("callable")) + callable = d["callable"]; if (d.has("flags")) flags = d["flags"]; if (d.has("binds")) @@ -655,16 +638,16 @@ void Object::get_method_list(List<MethodInfo> *p_list) const { } } -Variant Object::_call_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 1) { - r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 0; return Variant(); } if (p_args[0]->get_type() != Variant::STRING) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; return Variant(); @@ -675,22 +658,22 @@ Variant Object::_call_bind(const Variant **p_args, int p_argcount, Variant::Call return call(method, &p_args[1], p_argcount - 1, r_error); } -Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 1) { - r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 0; return Variant(); } if (p_args[0]->get_type() != Variant::STRING) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; return Variant(); } - r_error.error = Variant::CallError::CALL_OK; + r_error.error = Callable::CallError::CALL_OK; StringName method = *p_args[0]; @@ -700,29 +683,29 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Vari } #ifdef DEBUG_ENABLED -static void _test_call_error(const StringName &p_func, const Variant::CallError &error) { +static void _test_call_error(const StringName &p_func, const Callable::CallError &error) { switch (error.error) { - case Variant::CallError::CALL_OK: - case Variant::CallError::CALL_ERROR_INVALID_METHOD: + case Callable::CallError::CALL_OK: + case Callable::CallError::CALL_ERROR_INVALID_METHOD: break; - case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT: { + case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(error.expected) + "."); + ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(Variant::Type(error.expected)) + "."); break; } - case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { + case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument) + "."); break; } - case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { + case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument) + "."); break; } - case Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL: + case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: break; } } @@ -749,7 +732,7 @@ void Object::call_multilevel(const StringName &p_method, const Variant **p_args, //Variant ret; OBJ_DEBUG_LOCK - Variant::CallError error; + Callable::CallError error; if (script_instance) { script_instance->call_multilevel(p_method, p_args, p_argcount); @@ -769,7 +752,7 @@ void Object::call_multilevel_reversed(const StringName &p_method, const Variant MethodBind *method = ClassDB::get_method(get_class_name(), p_method); - Variant::CallError error; + Callable::CallError error; OBJ_DEBUG_LOCK if (method) { @@ -823,9 +806,9 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) { } } - Variant::CallError ce; + Callable::CallError ce; Variant ret = call(p_method, argptrs, p_args.size(), ce); - if (ce.error != Variant::CallError::CALL_OK) { + 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) + "."); } return ret; @@ -842,7 +825,7 @@ Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) { argc++; } - Variant::CallError error; + Callable::CallError error; Variant ret = call(p_name, argptr, argc, error); return ret; @@ -859,38 +842,38 @@ void Object::call_multilevel(const StringName &p_name, VARIANT_ARG_DECLARE) { argc++; } - //Variant::CallError error; + //Callable::CallError error; call_multilevel(p_name, argptr, argc); } -Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - r_error.error = Variant::CallError::CALL_OK; + r_error.error = Callable::CallError::CALL_OK; if (p_method == CoreStringNames::get_singleton()->_free) { //free must be here, before anything, always ready #ifdef DEBUG_ENABLED if (p_argcount != 0) { r_error.argument = 0; - r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; return Variant(); } if (Object::cast_to<Reference>(this)) { r_error.argument = 0; - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference."); } if (_lock_index.get() > 1) { r_error.argument = 0; - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL_V_MSG(Variant(), "Object is locked and can't be freed."); } #endif //must be here, must be before everything, memdelete(this); - r_error.error = Variant::CallError::CALL_OK; + r_error.error = Callable::CallError::CALL_OK; return Variant(); } @@ -901,15 +884,15 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a //force jumptable switch (r_error.error) { - case Variant::CallError::CALL_OK: + case Callable::CallError::CALL_OK: return ret; - case Variant::CallError::CALL_ERROR_INVALID_METHOD: + case Callable::CallError::CALL_ERROR_INVALID_METHOD: break; - case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT: - case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: - case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: + case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: + case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: + case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: return ret; - case Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL: { + case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: { } } } @@ -919,7 +902,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a if (method) { ret = method->call(this, p_args, p_argcount, r_error); } else { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; } return ret; @@ -1102,7 +1085,7 @@ void Object::add_user_signal(const MethodInfo &p_signal) { ERR_FAIL_COND_MSG(p_signal.name == "", "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 + "'."); - Signal s; + SignalData s; s.user = p_signal; signal_map[p_signal.name] = s; } @@ -1117,23 +1100,22 @@ bool Object::_has_user_signal(const StringName &p_name) const { struct _ObjectSignalDisconnectData { StringName signal; - Object *target; - StringName method; + Callable callable; }; -Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; ERR_FAIL_COND_V(p_argcount < 1, Variant()); if (p_args[0]->get_type() != Variant::STRING) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING, Variant()); } - r_error.error = Variant::CallError::CALL_OK; + r_error.error = Callable::CallError::CALL_OK; StringName signal = *p_args[0]; @@ -1154,7 +1136,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int if (_block_signals) return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked - Signal *s = signal_map.getptr(p_name); + SignalData *s = signal_map.getptr(p_name); if (!s) { #ifdef DEBUG_ENABLED bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_name); @@ -1170,7 +1152,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int //copy on write will ensure that disconnecting the signal or even deleting the object will not affect the signal calling. //this happens automatically and will not change the performance of calling. //awesome, isn't it? - VMap<Signal::Target, Signal::Slot> slot_map = s->slot_map; + VMap<Callable, SignalData::Slot> slot_map = s->slot_map; int ssize = slot_map.size(); @@ -1184,7 +1166,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int const Connection &c = slot_map.getv(i).conn; - Object *target = ObjectDB::get_instance(slot_map.getk(i)._id); + Object *target = c.callable.get_object(); if (!target) { // Target might have been deleted during signal callback, this is expected and OK. continue; @@ -1209,22 +1191,23 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int } if (c.flags & CONNECT_DEFERRED) { - MessageQueue::get_singleton()->push_call(target->get_instance_id(), c.method, args, argc, true); + MessageQueue::get_singleton()->push_callable(c.callable, args, argc, true); } else { - Variant::CallError ce; + Callable::CallError ce; _emitting = true; - target->call(c.method, args, argc, ce); + Variant ret; + c.callable.call(args, argc, ret, ce); _emitting = false; - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { #ifdef DEBUG_ENABLED if (c.flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint() && (script.is_null() || !Ref<Script>(script)->is_tool())) continue; #endif - if (ce.error == Variant::CallError::CALL_ERROR_INVALID_METHOD && !ClassDB::class_exists(target->get_class_name())) { + if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD && !ClassDB::class_exists(target->get_class_name())) { //most likely object is not initialized yet, do not throw error. } else { - ERR_PRINT("Error calling method from signal '" + String(p_name) + "': " + Variant::get_call_error_text(target, c.method, args, argc, ce) + "."); + ERR_PRINT("Error calling from signal '" + String(p_name) + "': " + Variant::get_callable_error_text(c.callable, args, argc, ce) + "."); err = ERR_METHOD_NOT_FOUND; } } @@ -1241,8 +1224,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int _ObjectSignalDisconnectData dd; dd.signal = p_name; - dd.target = target; - dd.method = c.method; + dd.callable = c.callable; disconnect_data.push_back(dd); } } @@ -1250,7 +1232,8 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int while (!disconnect_data.empty()) { const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get(); - disconnect(dd.signal, dd.target, dd.method); + + _disconnect(dd.signal, dd.callable); disconnect_data.pop_front(); } @@ -1322,15 +1305,8 @@ Array Object::_get_signal_connection_list(const String &p_signal) const { for (List<Connection>::Element *E = conns.front(); E; E = E->next()) { Connection &c = E->get(); - if (c.signal == p_signal) { - Dictionary rc; - rc["signal"] = c.signal; - rc["method"] = c.method; - rc["source"] = c.source; - rc["target"] = c.target; - rc["binds"] = c.binds; - rc["flags"] = c.flags; - ret.push_back(rc); + if (c.signal.get_name() == p_signal) { + ret.push_back(c); } } @@ -1342,11 +1318,7 @@ Array Object::_get_incoming_connections() const { Array ret; int connections_amount = connections.size(); for (int idx_conn = 0; idx_conn < connections_amount; idx_conn++) { - Dictionary conn_data; - conn_data["source"] = connections[idx_conn].source; - conn_data["signal_name"] = connections[idx_conn].signal; - conn_data["method_name"] = connections[idx_conn].method; - ret.push_back(conn_data); + ret.push_back(connections[idx_conn]); } return ret; @@ -1380,7 +1352,7 @@ void Object::get_all_signal_connections(List<Connection> *p_connections) const { while ((S = signal_map.next(S))) { - const Signal *s = &signal_map[*S]; + const SignalData *s = &signal_map[*S]; for (int i = 0; i < s->slot_map.size(); i++) { @@ -1391,7 +1363,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 { - const Signal *s = signal_map.getptr(p_signal); + const SignalData *s = signal_map.getptr(p_signal); if (!s) return; //nothing @@ -1406,7 +1378,7 @@ int Object::get_persistent_signal_connection_count() const { while ((S = signal_map.next(S))) { - const Signal *s = &signal_map[*S]; + const SignalData *s = &signal_map[*S]; for (int i = 0; i < s->slot_map.size(); i++) { if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST) { @@ -1425,11 +1397,15 @@ void Object::get_signals_connected_to_this(List<Connection> *p_connections) cons } } -Error Object::connect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds, uint32_t p_flags) { +Error Object::connect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds, uint32_t p_flags) { + + return connect(p_signal, Callable(p_to_object, p_to_method), p_binds, p_flags); +} +Error Object::connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) { - ERR_FAIL_NULL_V(p_to_object, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_callable.is_null(), ERR_INVALID_PARAMETER); - Signal *s = signal_map.getptr(p_signal); + SignalData *s = signal_map.getptr(p_signal); if (!s) { bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal); //check in script @@ -1448,33 +1424,32 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str #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 method '" + p_to_object->get_class() + "." + p_to_method + "'."); + 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 + "'."); - signal_map[p_signal] = Signal(); + signal_map[p_signal] = SignalData(); s = &signal_map[p_signal]; } - Signal::Target target(p_to_object->get_instance_id(), p_to_method); + Callable target = p_callable; + if (s->slot_map.has(target)) { if (p_flags & CONNECT_REFERENCE_COUNTED) { s->slot_map[target].reference_count++; return OK; } else { - ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object."); + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Signal '" + p_signal + "' is already connected to given callable '" + p_callable + "' in that object."); } } - Signal::Slot slot; + SignalData::Slot slot; Connection conn; - conn.source = this; - conn.target = p_to_object; - conn.method = p_to_method; - conn.signal = p_signal; + conn.callable = target; + conn.signal = ::Signal(this, p_signal); conn.flags = p_flags; conn.binds = p_binds; slot.conn = conn; - slot.cE = p_to_object->connections.push_back(conn); + slot.cE = p_callable.get_object()->connections.push_back(conn); if (p_flags & CONNECT_REFERENCE_COUNTED) { slot.reference_count = 1; } @@ -1484,10 +1459,15 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str return OK; } -bool Object::is_connected(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const { +bool Object::is_connected_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const { - ERR_FAIL_NULL_V(p_to_object, false); - const Signal *s = signal_map.getptr(p_signal); + return is_connected(p_signal, Callable(p_to_object, p_to_method)); +} + +bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const { + + ERR_FAIL_COND_V(p_callable.is_null(), false); + 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) @@ -1499,28 +1479,31 @@ bool Object::is_connected(const StringName &p_signal, Object *p_to_object, const ERR_FAIL_V_MSG(false, "Nonexistent signal: " + p_signal + "."); } - Signal::Target target(p_to_object->get_instance_id(), p_to_method); + Callable target = p_callable; return s->slot_map.has(target); //const Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.find(target); //return (E!=NULL); } -void Object::disconnect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) { +void Object::disconnect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) { - _disconnect(p_signal, p_to_object, p_to_method); + _disconnect(p_signal, Callable(p_to_object, p_to_method)); } -void Object::_disconnect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, bool p_force) { - ERR_FAIL_NULL(p_to_object); - Signal *s = signal_map.getptr(p_signal); - ERR_FAIL_COND_MSG(!s, vformat("Nonexistent signal '%s' in %s.", p_signal, to_string())); +void Object::disconnect(const StringName &p_signal, const Callable &p_callable) { + _disconnect(p_signal, p_callable); +} + +void Object::_disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force) { - Signal::Target target(p_to_object->get_instance_id(), p_to_method); + ERR_FAIL_COND(p_callable.is_null()); + SignalData *s = signal_map.getptr(p_signal); + ERR_FAIL_COND_MSG(!s, vformat("Nonexistent signal '%s' in %s.", p_signal, to_string())); - ERR_FAIL_COND_MSG(!s->slot_map.has(target), "Disconnecting nonexistent signal '" + p_signal + "', slot: " + itos(target._id) + ":" + target.method + "."); + ERR_FAIL_COND_MSG(!s->slot_map.has(p_callable), "Disconnecting nonexistent signal '" + p_signal + "', callable: " + p_callable + "."); - Signal::Slot *slot = &s->slot_map[target]; + SignalData::Slot *slot = &s->slot_map[p_callable]; if (!p_force) { slot->reference_count--; // by default is zero, if it was not referenced it will go below it @@ -1528,9 +1511,10 @@ void Object::_disconnect(const StringName &p_signal, Object *p_to_object, const return; } } - - p_to_object->connections.erase(slot->cE); - s->slot_map.erase(target); + Object *object = p_callable.get_object(); + ERR_FAIL_COND(!object); + object->connections.erase(slot->cE); + s->slot_map.erase(p_callable); if (s->slot_map.empty() && ClassDB::has_signal(get_class_name(), p_signal)) { //not user signal, delete @@ -1710,9 +1694,9 @@ void Object::_bind_methods() { ClassDB::bind_method(D_METHOD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list); ClassDB::bind_method(D_METHOD("get_incoming_connections"), &Object::_get_incoming_connections); - ClassDB::bind_method(D_METHOD("connect", "signal", "target", "method", "binds", "flags"), &Object::connect, DEFVAL(Array()), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("disconnect", "signal", "target", "method"), &Object::disconnect); - ClassDB::bind_method(D_METHOD("is_connected", "signal", "target", "method"), &Object::is_connected); + ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "binds", "flags"), &Object::connect, DEFVAL(Array()), 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("set_block_signals", "enable"), &Object::set_block_signals); ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals); @@ -1829,7 +1813,7 @@ Variant::Type Object::get_static_property_type_indexed(const Vector<StringName> return Variant::NIL; } - Variant::CallError ce; + Callable::CallError ce; Variant check = Variant::construct(t, NULL, 0, ce); for (int i = 1; i < p_path.size(); i++) { @@ -1956,15 +1940,15 @@ Object::~Object() { while ((S = signal_map.next(NULL))) { - Signal *s = &signal_map[*S]; + SignalData *s = &signal_map[*S]; //brute force disconnect for performance int slot_count = s->slot_map.size(); - const VMap<Signal::Target, Signal::Slot>::Pair *slot_list = s->slot_map.get_array(); + const VMap<Callable, SignalData::Slot>::Pair *slot_list = s->slot_map.get_array(); for (int i = 0; i < slot_count; i++) { - slot_list[i].value.conn.target->connections.erase(slot_list[i].value.cE); + slot_list[i].value.conn.callable.get_object()->connections.erase(slot_list[i].value.cE); } signal_map.erase(*S); @@ -1974,7 +1958,7 @@ Object::~Object() { while (connections.size()) { Connection c = connections.front()->get(); - c.source->_disconnect(c.signal, c.target, c.method, true); + c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true); } ObjectDB::remove_instance(this); diff --git a/core/object.h b/core/object.h index afbdbda814..dc7d49f534 100644 --- a/core/object.h +++ b/core/object.h @@ -413,18 +413,15 @@ public: struct Connection { - Object *source; - StringName signal; - Object *target; - StringName method; + ::Signal signal; + Callable callable; + uint32_t flags; Vector<Variant> binds; bool operator<(const Connection &p_conn) const; operator Variant() const; Connection() { - source = NULL; - target = NULL; flags = 0; } Connection(const Variant &p_variant); @@ -441,21 +438,7 @@ private: friend bool predelete_handler(Object *); friend void postinitialize_handler(Object *); - struct Signal { - - struct Target { - - ObjectID _id; - StringName method; - - _FORCE_INLINE_ bool operator<(const Target &p_target) const { return (_id == p_target._id) ? (method < p_target.method) : (_id < p_target._id); } - - Target(const ObjectID &p_id, const StringName &p_method) : - _id(p_id), - method(p_method) { - } - Target() { _id = ObjectID(); } - }; + struct SignalData { struct Slot { @@ -466,11 +449,11 @@ private: }; MethodInfo user; - VMap<Target, Slot> slot_map; - Signal() {} + VMap<Callable, Slot> slot_map; + SignalData() {} }; - HashMap<StringName, Signal> signal_map; + HashMap<StringName, SignalData> signal_map; List<Connection> connections; #ifdef DEBUG_ENABLED SafeRefCount _lock_index; @@ -496,7 +479,7 @@ private: void _add_user_signal(const String &p_name, const Array &p_args = Array()); bool _has_user_signal(const StringName &p_name) const; - Variant _emit_signal(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + Variant _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Array _get_signal_list() const; Array _get_signal_connection_list(const String &p_signal) const; Array _get_incoming_connections() const; @@ -554,8 +537,8 @@ protected: //Variant _call_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant()); //void _call_deferred_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant()); - Variant _call_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error); - Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + Variant _call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); + Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); virtual const StringName *_get_class_namev() const { if (!_class_name) @@ -572,7 +555,7 @@ protected: friend class ClassDB; virtual void _validate_property(PropertyInfo &property) const; - void _disconnect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, bool p_force = false); + void _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false); public: //should be protected, but bug in clang++ static void initialize_class(); @@ -670,7 +653,7 @@ public: bool has_method(const StringName &p_method) const; void get_method_list(List<MethodInfo> *p_list) const; Variant callv(const StringName &p_method, const Array &p_args); - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); + virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper @@ -716,9 +699,13 @@ public: int get_persistent_signal_connection_count() const; void get_signals_connected_to_this(List<Connection> *p_connections) const; - Error connect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); - void disconnect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method); - bool is_connected(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const; + Error connect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); + void disconnect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method); + bool is_connected_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const; + + Error connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); + void disconnect(const StringName &p_signal, const Callable &p_callable); + bool is_connected(const StringName &p_signal, const Callable &p_callable) const; void call_deferred(const StringName &p_method, VARIANT_ARG_LIST); void set_deferred(const StringName &p_property, const Variant &p_value); diff --git a/core/object_id.h b/core/object_id.h index 6ab1a3031a..63b0c27af8 100644 --- a/core/object_id.h +++ b/core/object_id.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* object_id.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #ifndef OBJECT_ID_H #define OBJECT_ID_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 45b600a23d..bb017f43e5 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -99,6 +99,9 @@ extern void unregister_variant_methods(); void register_core_types() { + //consistency check + ERR_FAIL_COND(sizeof(Callable) > 16); + ObjectDB::setup(); ResourceCache::setup(); diff --git a/core/script_language.cpp b/core/script_language.cpp index 1149feac38..0b00247502 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -307,17 +307,17 @@ Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) { argc++; } - Variant::CallError error; + Callable::CallError error; return call(p_method, argptr, argc, error); } void ScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - Variant::CallError ce; + Callable::CallError ce; call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls } void ScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - Variant::CallError ce; + Callable::CallError ce; call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls } diff --git a/core/script_language.h b/core/script_language.h index 2209f78fe4..48570ae546 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -197,7 +197,7 @@ public: virtual void get_method_list(List<MethodInfo> *p_list) const = 0; virtual bool has_method(const StringName &p_method) const = 0; virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST); - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) = 0; + virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0; virtual void call_multilevel(const StringName &p_method, VARIANT_ARG_LIST); virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); @@ -424,12 +424,12 @@ public: virtual void get_method_list(List<MethodInfo> *p_list) const; virtual bool has_method(const StringName &p_method) const; virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST) { return Variant(); } - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } //virtual void call_multilevel(const StringName& p_method,VARIANT_ARG_LIST) { return Variant(); } - //virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) { return Variant(); } + //virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount,Callable::CallError &r_error) { return Variant(); } virtual void notification(int p_notification) {} virtual Ref<Script> get_script() const { return script; } diff --git a/core/type_info.h b/core/type_info.h index 379735fd67..8e86567f51 100644 --- a/core/type_info.h +++ b/core/type_info.h @@ -153,6 +153,8 @@ MAKE_TYPE_INFO(Transform, Variant::TRANSFORM) MAKE_TYPE_INFO(Color, Variant::COLOR) MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH) MAKE_TYPE_INFO(RID, Variant::_RID) +MAKE_TYPE_INFO(Callable, Variant::CALLABLE) +MAKE_TYPE_INFO(Signal, Variant::SIGNAL) MAKE_TYPE_INFO(Dictionary, Variant::DICTIONARY) MAKE_TYPE_INFO(Array, Variant::ARRAY) MAKE_TYPE_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY) diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 577879d448..0eef75d587 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -290,9 +290,9 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) { } argptrs.resize(argc); - Variant::CallError ce; + Callable::CallError ce; obj->call(op.name, (const Variant **)argptrs.ptr(), argc, ce); - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { ERR_PRINT("Error calling method from signal '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce)); } #ifdef TOOLS_ENABLED @@ -431,29 +431,29 @@ UndoRedo::~UndoRedo() { clear_history(); } -Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 2) { - r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 0; return Variant(); } if (p_args[0]->get_type() != Variant::OBJECT) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; return Variant(); } if (p_args[1]->get_type() != Variant::STRING) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; r_error.expected = Variant::STRING; return Variant(); } - r_error.error = Variant::CallError::CALL_OK; + r_error.error = Callable::CallError::CALL_OK; Object *object = *p_args[0]; String method = *p_args[1]; @@ -469,29 +469,29 @@ Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Variant return Variant(); } -Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 2) { - r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 0; return Variant(); } if (p_args[0]->get_type() != Variant::OBJECT) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; return Variant(); } if (p_args[1]->get_type() != Variant::STRING) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; r_error.expected = Variant::STRING; return Variant(); } - r_error.error = Variant::CallError::CALL_OK; + r_error.error = Callable::CallError::CALL_OK; Object *object = *p_args[0]; String method = *p_args[1]; diff --git a/core/undo_redo.h b/core/undo_redo.h index bb9a4d1642..e707979291 100644 --- a/core/undo_redo.h +++ b/core/undo_redo.h @@ -47,8 +47,8 @@ public: }; typedef void (*CommitNotifyCallback)(void *p_ud, const String &p_name); - Variant _add_do_method(const Variant **p_args, int p_argcount, Variant::CallError &r_error); - Variant _add_undo_method(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + Variant _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); + Variant _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, VARIANT_ARG_DECLARE); typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value); diff --git a/core/variant.cpp b/core/variant.cpp index b849a83cb4..cdc9e47fc8 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -128,6 +128,14 @@ String Variant::get_type_name(Variant::Type p_type) { return "Object"; } break; + case CALLABLE: { + + return "Callable"; + } break; + case SIGNAL: { + + return "Signal"; + } break; case NODE_PATH: { return "NodePath"; @@ -792,6 +800,14 @@ bool Variant::is_zero() const { return _get_obj().obj == NULL; } break; + case CALLABLE: { + + return reinterpret_cast<const Callable *>(_data._mem)->is_null(); + } break; + case SIGNAL: { + + return reinterpret_cast<const Signal *>(_data._mem)->is_null(); + } break; case NODE_PATH: { return reinterpret_cast<const NodePath *>(_data._mem)->is_empty(); @@ -1022,6 +1038,14 @@ void Variant::reference(const Variant &p_variant) { _get_obj().id = p_variant._get_obj().id; } break; + case CALLABLE: { + + memnew_placement(_data._mem, Callable(*reinterpret_cast<const Callable *>(p_variant._data._mem))); + } break; + case SIGNAL: { + + memnew_placement(_data._mem, Signal(*reinterpret_cast<const Signal *>(p_variant._data._mem))); + } break; case NODE_PATH: { memnew_placement(_data._mem, NodePath(*reinterpret_cast<const NodePath *>(p_variant._data._mem))); @@ -1149,6 +1173,14 @@ void Variant::clear() { // not much need probably reinterpret_cast<RID *>(_data._mem)->~RID(); } break; + case CALLABLE: { + + reinterpret_cast<Callable *>(_data._mem)->~Callable(); + } break; + case SIGNAL: { + + reinterpret_cast<Signal *>(_data._mem)->~Signal(); + } break; case DICTIONARY: { reinterpret_cast<Dictionary *>(_data._mem)->~Dictionary(); @@ -1627,6 +1659,18 @@ String Variant::stringify(List<const void *> &stack) const { return "[Object:null]"; } break; + case CALLABLE: { + const Callable &c = *reinterpret_cast<const Callable *>(_data._mem); + return c; + } break; + case SIGNAL: { + const Signal &s = *reinterpret_cast<const Signal *>(_data._mem); + return s; + } break; + case _RID: { + const RID &s = *reinterpret_cast<const RID *>(_data._mem); + return "RID(" + itos(s.get_id()) + ")"; + } break; default: { return "[" + get_type_name(type) + "]"; } @@ -1776,9 +1820,9 @@ Variant::operator RID() const { ERR_FAIL_COND_V_MSG(ObjectDB::get_instance(_get_obj().id) == nullptr, RID(), "Invalid pointer (object was freed)."); }; #endif - Variant::CallError ce; + Callable::CallError ce; Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid, NULL, 0, ce); - if (ce.error == Variant::CallError::CALL_OK && ret.get_type() == Variant::_RID) { + if (ce.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::_RID) { return ret; } return RID(); @@ -1836,6 +1880,22 @@ Variant::operator Dictionary() const { return Dictionary(); } +Variant::operator Callable() const { + + if (type == CALLABLE) + return *reinterpret_cast<const Callable *>(_data._mem); + else + return Callable(); +} + +Variant::operator Signal() const { + + if (type == SIGNAL) + return *reinterpret_cast<const Signal *>(_data._mem); + else + return Signal(); +} + template <class DA, class SA> inline DA _convert_array(const SA &p_array) { @@ -2243,6 +2303,17 @@ Variant::Variant(const Object *p_object) { } } +Variant::Variant(const Callable &p_callable) { + + type = CALLABLE; + memnew_placement(_data._mem, Callable(p_callable)); +} +Variant::Variant(const Signal &p_callable) { + + type = SIGNAL; + memnew_placement(_data._mem, Signal(p_callable)); +} + Variant::Variant(const Dictionary &p_dictionary) { type = DICTIONARY; @@ -2469,6 +2540,15 @@ void Variant::operator=(const Variant &p_variant) { _get_obj().id = p_variant._get_obj().id; } break; + case CALLABLE: { + + *reinterpret_cast<Callable *>(_data._mem) = *reinterpret_cast<const Callable *>(p_variant._data._mem); + } break; + case SIGNAL: { + + *reinterpret_cast<Signal *>(_data._mem) = *reinterpret_cast<const Signal *>(p_variant._data._mem); + } break; + case NODE_PATH: { *reinterpret_cast<NodePath *>(_data._mem) = *reinterpret_cast<const NodePath *>(p_variant._data._mem); @@ -2676,6 +2756,17 @@ uint32_t Variant::hash() const { return reinterpret_cast<const Dictionary *>(_data._mem)->hash(); } break; + case CALLABLE: { + + return reinterpret_cast<const Callable *>(_data._mem)->hash(); + + } break; + case SIGNAL: { + + const Signal &s = *reinterpret_cast<const Signal *>(_data._mem); + uint32_t hash = s.get_name().hash(); + return hash_djb2_one_64(s.get_object_id(), hash); + } break; case ARRAY: { const Array &arr = *reinterpret_cast<const Array *>(_data._mem); @@ -3054,24 +3145,24 @@ Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) { argc++; } - CallError error; + Callable::CallError error; Variant ret = call(p_method, argptr, argc, error); switch (error.error) { - case CallError::CALL_ERROR_INVALID_ARGUMENT: { + case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { - String err = "Invalid type for argument #" + itos(error.argument) + ", expected '" + Variant::get_type_name(error.expected) + "'."; + String err = "Invalid type for argument #" + itos(error.argument) + ", expected '" + Variant::get_type_name(Variant::Type(error.expected)) + "'."; ERR_PRINT(err.utf8().get_data()); } break; - case CallError::CALL_ERROR_INVALID_METHOD: { + case Callable::CallError::CALL_ERROR_INVALID_METHOD: { String err = "Invalid method '" + p_method + "' for type '" + Variant::get_type_name(type) + "'."; ERR_PRINT(err.utf8().get_data()); } break; - case CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { + case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { String err = "Too many arguments for method '" + p_method + "'"; ERR_PRINT(err.utf8().get_data()); @@ -3096,26 +3187,26 @@ String Variant::get_construct_string() const { return vars; } -String Variant::get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Variant::CallError &ce) { +String Variant::get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) { String err_text; - if (ce.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { + if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) { int errorarg = ce.argument; if (p_argptrs) { - err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + "."; + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + "."; } else { - err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(ce.expected) + "."; + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + "."; } - } else if (ce.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { + } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; - } else if (ce.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { + } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; - } else if (ce.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) { + } else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { err_text = "Method not found."; - } else if (ce.error == Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) { + } else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) { err_text = "Instance is null"; - } else if (ce.error == Variant::CallError::CALL_OK) { + } else if (ce.error == Callable::CallError::CALL_OK) { return "Call OK"; } @@ -3128,6 +3219,32 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method, return "'" + class_name + "::" + String(p_method) + "': " + err_text; } +String Variant::get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) { + + String err_text; + + if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) { + int errorarg = ce.argument; + if (p_argptrs) { + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + "."; + } else { + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + "."; + } + } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { + err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; + } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { + err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; + } else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { + err_text = "Method not found."; + } else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) { + err_text = "Instance is null"; + } else if (ce.error == Callable::CallError::CALL_OK) { + return "Call OK"; + } + + return String(p_callable) + " : " + err_text; +} + String vformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) { Array args; diff --git a/core/variant.h b/core/variant.h index 51f23b4b49..d41144f4c5 100644 --- a/core/variant.h +++ b/core/variant.h @@ -32,6 +32,7 @@ #define VARIANT_H #include "core/array.h" +#include "core/callable.h" #include "core/color.h" #include "core/dictionary.h" #include "core/io/ip_address.h" @@ -101,9 +102,10 @@ public: NODE_PATH, // 15 _RID, OBJECT, + CALLABLE, + SIGNAL, DICTIONARY, ARRAY, - // arrays PACKED_BYTE_ARRAY, // 20 PACKED_INT_ARRAY, @@ -202,6 +204,9 @@ public: operator Node *() const; operator Control *() const; + operator Callable() const; + operator Signal() const; + operator Dictionary() const; operator Array() const; @@ -262,6 +267,8 @@ public: Variant(const NodePath &p_node_path); Variant(const RID &p_rid); Variant(const Object *p_object); + Variant(const Callable &p_callable); + Variant(const Signal &p_signal); Variant(const Dictionary &p_dictionary); Variant(const Array &p_array); @@ -333,27 +340,14 @@ public: static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst); static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst); - struct CallError { - enum Error { - CALL_OK, - CALL_ERROR_INVALID_METHOD, - CALL_ERROR_INVALID_ARGUMENT, - CALL_ERROR_TOO_MANY_ARGUMENTS, - CALL_ERROR_TOO_FEW_ARGUMENTS, - CALL_ERROR_INSTANCE_IS_NULL, - }; - Error error; - int argument; - Type expected; - }; - - void call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, CallError &r_error); - Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, CallError &r_error); + void call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, Callable::CallError &r_error); + Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant()); - static String get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Variant::CallError &ce); + static String get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce); + static String get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce); - static Variant construct(const Variant::Type, const Variant **p_args, int p_argcount, CallError &r_error, bool p_strict = true); + static Variant construct(const Variant::Type, const Variant **p_args, int p_argcount, Callable::CallError &r_error, bool p_strict = true); void get_method_list(List<MethodInfo> *p_list) const; bool has_method(const StringName &p_method) const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 6506da58d4..37c35d7c64 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -61,7 +61,7 @@ struct _VariantCall { VariantFunc func; - _FORCE_INLINE_ bool verify_arguments(const Variant **p_args, Variant::CallError &r_error) { + _FORCE_INLINE_ bool verify_arguments(const Variant **p_args, Callable::CallError &r_error) { if (arg_count == 0) return true; @@ -73,7 +73,7 @@ struct _VariantCall { if (tptr[i] == Variant::NIL || tptr[i] == p_args[i]->type) continue; // all good if (!Variant::can_convert(p_args[i]->type, tptr[i])) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = i; r_error.expected = tptr[i]; return false; @@ -82,10 +82,10 @@ struct _VariantCall { return true; } - _FORCE_INLINE_ void call(Variant &r_ret, Variant &p_self, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + _FORCE_INLINE_ void call(Variant &r_ret, Variant &p_self, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { #ifdef DEBUG_ENABLED if (p_argcount > arg_count) { - r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument = arg_count; return; } else @@ -94,7 +94,7 @@ struct _VariantCall { int def_argcount = default_args.size(); #ifdef DEBUG_ENABLED if (p_argcount < (arg_count - def_argcount)) { - r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = arg_count - def_argcount; return; } @@ -519,6 +519,23 @@ struct _VariantCall { VCALL_LOCALMEM1R(Dictionary, duplicate); VCALL_LOCALMEM2R(Dictionary, get); + VCALL_LOCALMEM0R(Callable, is_null); + VCALL_LOCALMEM0R(Callable, is_custom); + VCALL_LOCALMEM0(Callable, is_standard); + VCALL_LOCALMEM0(Callable, get_object); + VCALL_LOCALMEM0(Callable, get_object_id); + VCALL_LOCALMEM0(Callable, get_method); + VCALL_LOCALMEM0(Callable, hash); + + VCALL_LOCALMEM0R(Signal, is_null); + VCALL_LOCALMEM0R(Signal, get_object); + VCALL_LOCALMEM0R(Signal, get_object_id); + VCALL_LOCALMEM0R(Signal, get_name); + VCALL_LOCALMEM3R(Signal, connect); + VCALL_LOCALMEM1(Signal, disconnect); + VCALL_LOCALMEM1R(Signal, is_connected); + VCALL_LOCALMEM0R(Signal, get_connections); + VCALL_LOCALMEM2(Array, set); VCALL_LOCALMEM1R(Array, get); VCALL_LOCALMEM0R(Array, size); @@ -1010,6 +1027,16 @@ struct _VariantCall { r_ret = Transform(p_args[0]->operator Basis(), p_args[1]->operator Vector3()); } + static void Callable_init2(Variant &r_ret, const Variant **p_args) { + + r_ret = Callable(p_args[0]->operator ObjectID(), p_args[1]->operator String()); + } + + static void Signal_init2(Variant &r_ret, const Variant **p_args) { + + r_ret = Signal(p_args[0]->operator ObjectID(), p_args[1]->operator String()); + } + static void add_constructor(VariantConstructFunc p_func, const Variant::Type p_type, const String &p_name1 = "", const Variant::Type p_type1 = Variant::NIL, const String &p_name2 = "", const Variant::Type p_type2 = Variant::NIL, @@ -1078,26 +1105,26 @@ _VariantCall::TypeFunc *_VariantCall::type_funcs = NULL; _VariantCall::ConstructFunc *_VariantCall::construct_funcs = NULL; _VariantCall::ConstantData *_VariantCall::constant_data = NULL; -Variant Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, CallError &r_error) { +Variant Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { Variant ret; call_ptr(p_method, p_args, p_argcount, &ret, r_error); return ret; } -void Variant::call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, CallError &r_error) { +void Variant::call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, Callable::CallError &r_error) { Variant ret; if (type == Variant::OBJECT) { //call object Object *obj = _get_obj().obj; if (!obj) { - r_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL; + r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; return; } #ifdef DEBUG_ENABLED if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { - r_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL; + r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; return; } @@ -1108,31 +1135,57 @@ void Variant::call_ptr(const StringName &p_method, const Variant **p_args, int p } else { - r_error.error = Variant::CallError::CALL_OK; + r_error.error = Callable::CallError::CALL_OK; Map<StringName, _VariantCall::FuncData>::Element *E = _VariantCall::type_funcs[type].functions.find(p_method); -#ifdef DEBUG_ENABLED - if (!E) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - return; + + if (E) { + + _VariantCall::FuncData &funcdata = E->get(); + funcdata.call(ret, *this, p_args, p_argcount, r_error); + + } else { + //handle vararg functions manually + bool valid = false; + if (type == CALLABLE) { + if (p_method == CoreStringNames::get_singleton()->call) { + + reinterpret_cast<const Callable *>(_data._mem)->call(p_args, p_argcount, ret, r_error); + valid = true; + } + if (p_method == CoreStringNames::get_singleton()->call_deferred) { + reinterpret_cast<const Callable *>(_data._mem)->call_deferred(p_args, p_argcount); + valid = true; + } + } else if (type == SIGNAL) { + if (p_method == CoreStringNames::get_singleton()->emit) { + if (r_ret) { + *r_ret = Variant(); + } + reinterpret_cast<const Signal *>(_data._mem)->emit(p_args, p_argcount); + valid = true; + } + } + if (!valid) { + //ok fail because not found + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; + return; + } } -#endif - _VariantCall::FuncData &funcdata = E->get(); - funcdata.call(ret, *this, p_args, p_argcount, r_error); } - if (r_error.error == Variant::CallError::CALL_OK && r_ret) + if (r_error.error == Callable::CallError::CALL_OK && r_ret) *r_ret = ret; } #define VCALL(m_type, m_method) _VariantCall::_call_##m_type##_##m_method -Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, int p_argcount, CallError &r_error, bool p_strict) { +Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, int p_argcount, Callable::CallError &r_error, bool p_strict) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, Variant()); - r_error.error = Variant::CallError::CALL_OK; + r_error.error = Callable::CallError::CALL_OK; if (p_argcount == 0) { //generic construct switch (p_type) { @@ -1166,6 +1219,8 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i return NodePath(); // 15 case _RID: return RID(); case OBJECT: return (Object *)NULL; + case CALLABLE: return Callable(); + case SIGNAL: return Signal(); case DICTIONARY: return Dictionary(); case ARRAY: return Array(); // 20 @@ -1249,7 +1304,7 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i //validate parameters for (int i = 0; i < cd.arg_count; i++) { if (!Variant::can_convert(p_args[i]->type, cd.arg_types[i])) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; //no such constructor + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; //no such constructor r_error.argument = i; r_error.expected = cd.arg_types[i]; return Variant(); @@ -1261,7 +1316,7 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i return v; } } - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; //no such constructor + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; //no such constructor return Variant(); } @@ -1373,6 +1428,30 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const { p_list->push_back(mi); } + + if (type == CALLABLE) { + + MethodInfo mi; + mi.name = "call"; + mi.return_val.usage = PROPERTY_USAGE_NIL_IS_VARIANT; + mi.flags |= METHOD_FLAG_VARARG; + + p_list->push_back(mi); + + mi.name = "call_deferred"; + mi.return_val.usage = 0; + + p_list->push_back(mi); + } + + if (type == SIGNAL) { + + MethodInfo mi; + mi.name = "emit"; + mi.flags |= METHOD_FLAG_VARARG; + + p_list->push_back(mi); + } } void Variant::get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list) { @@ -1756,6 +1835,25 @@ void register_variant_methods() { ADDFUNC1R(DICTIONARY, DICTIONARY, Dictionary, duplicate, BOOL, "deep", varray(false)); ADDFUNC2R(DICTIONARY, NIL, Dictionary, get, NIL, "key", NIL, "default", varray(Variant())); + ADDFUNC0R(CALLABLE, BOOL, Callable, is_null, varray()); + ADDFUNC0R(CALLABLE, BOOL, Callable, is_custom, varray()); + ADDFUNC0R(CALLABLE, BOOL, Callable, is_standard, varray()); + ADDFUNC0R(CALLABLE, OBJECT, Callable, get_object, varray()); + ADDFUNC0R(CALLABLE, INT, Callable, get_object_id, varray()); + ADDFUNC0R(CALLABLE, STRING, Callable, get_method, varray()); + ADDFUNC0R(CALLABLE, INT, Callable, hash, varray()); + + ADDFUNC0R(SIGNAL, BOOL, Signal, is_null, varray()); + ADDFUNC0R(SIGNAL, OBJECT, Signal, get_object, varray()); + ADDFUNC0R(SIGNAL, INT, Signal, get_object_id, varray()); + ADDFUNC0R(SIGNAL, STRING, Signal, get_name, varray()); + + ADDFUNC3R(SIGNAL, INT, Signal, connect, CALLABLE, "callable", ARRAY, "binds", INT, "flags", varray(Array(), 0)); + + ADDFUNC1R(SIGNAL, NIL, Signal, disconnect, CALLABLE, "callable", varray()); + ADDFUNC1R(SIGNAL, BOOL, Signal, is_connected, CALLABLE, "callable", varray()); + ADDFUNC0R(SIGNAL, ARRAY, Signal, get_connections, varray()); + ADDFUNC0R(ARRAY, INT, Array, size, varray()); ADDFUNC0R(ARRAY, BOOL, Array, empty, varray()); ADDFUNC0NC(ARRAY, NIL, Array, clear, varray()); @@ -1972,6 +2070,9 @@ void register_variant_methods() { _VariantCall::add_constructor(_VariantCall::Transform_init1, Variant::TRANSFORM, "x_axis", Variant::VECTOR3, "y_axis", Variant::VECTOR3, "z_axis", Variant::VECTOR3, "origin", Variant::VECTOR3); _VariantCall::add_constructor(_VariantCall::Transform_init2, Variant::TRANSFORM, "basis", Variant::BASIS, "origin", Variant::VECTOR3); + _VariantCall::add_constructor(_VariantCall::Callable_init2, Variant::CALLABLE, "object", Variant::OBJECT, "method_name", Variant::STRING); + _VariantCall::add_constructor(_VariantCall::Signal_init2, Variant::SIGNAL, "object", Variant::OBJECT, "signal_name", Variant::STRING); + /* REGISTER CONSTANTS */ _populate_named_colors(); diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 566c87dac1..6c98cf4de1 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -56,6 +56,8 @@ CASE_TYPE(PREFIX, OP, NODE_PATH) \ CASE_TYPE(PREFIX, OP, _RID) \ CASE_TYPE(PREFIX, OP, OBJECT) \ + CASE_TYPE(PREFIX, OP, CALLABLE) \ + CASE_TYPE(PREFIX, OP, SIGNAL) \ CASE_TYPE(PREFIX, OP, DICTIONARY) \ CASE_TYPE(PREFIX, OP, ARRAY) \ CASE_TYPE(PREFIX, OP, PACKED_BYTE_ARRAY) \ @@ -89,6 +91,8 @@ TYPE(PREFIX, OP, NODE_PATH), \ TYPE(PREFIX, OP, _RID), \ TYPE(PREFIX, OP, OBJECT), \ + TYPE(PREFIX, OP, CALLABLE), \ + TYPE(PREFIX, OP, SIGNAL), \ TYPE(PREFIX, OP, DICTIONARY), \ TYPE(PREFIX, OP, ARRAY), \ TYPE(PREFIX, OP, PACKED_BYTE_ARRAY), \ @@ -101,32 +105,32 @@ } /* clang-format on */ -#define CASES(PREFIX) static const void *switch_table_##PREFIX[25][27] = { \ - TYPES(PREFIX, OP_EQUAL), \ - TYPES(PREFIX, OP_NOT_EQUAL), \ - TYPES(PREFIX, OP_LESS), \ - TYPES(PREFIX, OP_LESS_EQUAL), \ - TYPES(PREFIX, OP_GREATER), \ - TYPES(PREFIX, OP_GREATER_EQUAL), \ - TYPES(PREFIX, OP_ADD), \ - TYPES(PREFIX, OP_SUBTRACT), \ - TYPES(PREFIX, OP_MULTIPLY), \ - TYPES(PREFIX, OP_DIVIDE), \ - TYPES(PREFIX, OP_NEGATE), \ - TYPES(PREFIX, OP_POSITIVE), \ - TYPES(PREFIX, OP_MODULE), \ - TYPES(PREFIX, OP_STRING_CONCAT), \ - TYPES(PREFIX, OP_SHIFT_LEFT), \ - TYPES(PREFIX, OP_SHIFT_RIGHT), \ - TYPES(PREFIX, OP_BIT_AND), \ - TYPES(PREFIX, OP_BIT_OR), \ - TYPES(PREFIX, OP_BIT_XOR), \ - TYPES(PREFIX, OP_BIT_NEGATE), \ - TYPES(PREFIX, OP_AND), \ - TYPES(PREFIX, OP_OR), \ - TYPES(PREFIX, OP_XOR), \ - TYPES(PREFIX, OP_NOT), \ - TYPES(PREFIX, OP_IN), \ +#define CASES(PREFIX) static const void *switch_table_##PREFIX[25][Variant::VARIANT_MAX] = { \ + TYPES(PREFIX, OP_EQUAL), \ + TYPES(PREFIX, OP_NOT_EQUAL), \ + TYPES(PREFIX, OP_LESS), \ + TYPES(PREFIX, OP_LESS_EQUAL), \ + TYPES(PREFIX, OP_GREATER), \ + TYPES(PREFIX, OP_GREATER_EQUAL), \ + TYPES(PREFIX, OP_ADD), \ + TYPES(PREFIX, OP_SUBTRACT), \ + TYPES(PREFIX, OP_MULTIPLY), \ + TYPES(PREFIX, OP_DIVIDE), \ + TYPES(PREFIX, OP_NEGATE), \ + TYPES(PREFIX, OP_POSITIVE), \ + TYPES(PREFIX, OP_MODULE), \ + TYPES(PREFIX, OP_STRING_CONCAT), \ + TYPES(PREFIX, OP_SHIFT_LEFT), \ + TYPES(PREFIX, OP_SHIFT_RIGHT), \ + TYPES(PREFIX, OP_BIT_AND), \ + TYPES(PREFIX, OP_BIT_OR), \ + TYPES(PREFIX, OP_BIT_XOR), \ + TYPES(PREFIX, OP_BIT_NEGATE), \ + TYPES(PREFIX, OP_AND), \ + TYPES(PREFIX, OP_OR), \ + TYPES(PREFIX, OP_XOR), \ + TYPES(PREFIX, OP_NOT), \ + TYPES(PREFIX, OP_IN), \ } #define SWITCH(PREFIX, op, val) goto *switch_table_##PREFIX[op][val]; @@ -423,6 +427,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN_FAIL; } + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, CALLABLE, ==, Callable); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, SIGNAL, ==, Signal); + CASE_TYPE(math, OP_EQUAL, DICTIONARY) { if (p_b.type != DICTIONARY) { if (p_b.type == NIL) @@ -511,6 +518,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN_FAIL; } + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, CALLABLE, !=, Callable); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, SIGNAL, !=, Signal); + CASE_TYPE(math, OP_NOT_EQUAL, DICTIONARY) { if (p_b.type != DICTIONARY) { if (p_b.type == NIL) @@ -592,6 +602,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, _RETURN((p_a._get_obj().obj < p_b._get_obj().obj)); } + DEFAULT_OP_LOCALMEM_NULL(math, OP_LESS, CALLABLE, <, Callable); + DEFAULT_OP_LOCALMEM_NULL(math, OP_LESS, SIGNAL, <, Signal); + CASE_TYPE(math, OP_LESS, ARRAY) { if (p_b.type != ARRAY) _RETURN_FAIL; @@ -664,6 +677,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM) CASE_TYPE(math, OP_LESS_EQUAL, COLOR) CASE_TYPE(math, OP_LESS_EQUAL, NODE_PATH) + CASE_TYPE(math, OP_LESS_EQUAL, CALLABLE) + CASE_TYPE(math, OP_LESS_EQUAL, SIGNAL) + CASE_TYPE(math, OP_LESS_EQUAL, DICTIONARY) CASE_TYPE(math, OP_LESS_EQUAL, ARRAY) CASE_TYPE(math, OP_LESS_EQUAL, PACKED_BYTE_ARRAY); @@ -740,6 +756,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_GREATER, COLOR) CASE_TYPE(math, OP_GREATER, NODE_PATH) CASE_TYPE(math, OP_GREATER, DICTIONARY) + CASE_TYPE(math, OP_GREATER, CALLABLE) + CASE_TYPE(math, OP_GREATER, SIGNAL) + _RETURN_FAIL; } @@ -768,6 +787,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM) CASE_TYPE(math, OP_GREATER_EQUAL, COLOR) CASE_TYPE(math, OP_GREATER_EQUAL, NODE_PATH) + CASE_TYPE(math, OP_GREATER_EQUAL, CALLABLE) + CASE_TYPE(math, OP_GREATER_EQUAL, SIGNAL) + CASE_TYPE(math, OP_GREATER_EQUAL, DICTIONARY) CASE_TYPE(math, OP_GREATER_EQUAL, ARRAY) CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_BYTE_ARRAY); @@ -825,6 +847,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_ADD, NODE_PATH) CASE_TYPE(math, OP_ADD, _RID) CASE_TYPE(math, OP_ADD, OBJECT) + CASE_TYPE(math, OP_ADD, CALLABLE) + CASE_TYPE(math, OP_ADD, SIGNAL) + CASE_TYPE(math, OP_ADD, DICTIONARY) _RETURN_FAIL; } @@ -849,6 +874,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_SUBTRACT, NODE_PATH) CASE_TYPE(math, OP_SUBTRACT, _RID) CASE_TYPE(math, OP_SUBTRACT, OBJECT) + CASE_TYPE(math, OP_SUBTRACT, CALLABLE) + CASE_TYPE(math, OP_SUBTRACT, SIGNAL) + CASE_TYPE(math, OP_SUBTRACT, DICTIONARY) CASE_TYPE(math, OP_SUBTRACT, ARRAY) CASE_TYPE(math, OP_SUBTRACT, PACKED_BYTE_ARRAY); @@ -928,6 +956,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_MULTIPLY, NODE_PATH) CASE_TYPE(math, OP_MULTIPLY, _RID) CASE_TYPE(math, OP_MULTIPLY, OBJECT) + CASE_TYPE(math, OP_MULTIPLY, CALLABLE) + CASE_TYPE(math, OP_MULTIPLY, SIGNAL) + CASE_TYPE(math, OP_MULTIPLY, DICTIONARY) CASE_TYPE(math, OP_MULTIPLY, ARRAY) CASE_TYPE(math, OP_MULTIPLY, PACKED_BYTE_ARRAY); @@ -971,6 +1002,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_DIVIDE, NODE_PATH) CASE_TYPE(math, OP_DIVIDE, _RID) CASE_TYPE(math, OP_DIVIDE, OBJECT) + CASE_TYPE(math, OP_DIVIDE, CALLABLE) + CASE_TYPE(math, OP_DIVIDE, SIGNAL) + CASE_TYPE(math, OP_DIVIDE, DICTIONARY) CASE_TYPE(math, OP_DIVIDE, ARRAY) CASE_TYPE(math, OP_DIVIDE, PACKED_BYTE_ARRAY); @@ -1003,6 +1037,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_POSITIVE, NODE_PATH) CASE_TYPE(math, OP_POSITIVE, _RID) CASE_TYPE(math, OP_POSITIVE, OBJECT) + CASE_TYPE(math, OP_POSITIVE, CALLABLE) + CASE_TYPE(math, OP_POSITIVE, SIGNAL) + CASE_TYPE(math, OP_POSITIVE, DICTIONARY) CASE_TYPE(math, OP_POSITIVE, ARRAY) CASE_TYPE(math, OP_POSITIVE, PACKED_BYTE_ARRAY) @@ -1036,6 +1073,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_NEGATE, NODE_PATH) CASE_TYPE(math, OP_NEGATE, _RID) CASE_TYPE(math, OP_NEGATE, OBJECT) + CASE_TYPE(math, OP_NEGATE, CALLABLE) + CASE_TYPE(math, OP_NEGATE, SIGNAL) + CASE_TYPE(math, OP_NEGATE, DICTIONARY) CASE_TYPE(math, OP_NEGATE, ARRAY) CASE_TYPE(math, OP_NEGATE, PACKED_BYTE_ARRAY) @@ -1096,6 +1136,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_MODULE, NODE_PATH) CASE_TYPE(math, OP_MODULE, _RID) CASE_TYPE(math, OP_MODULE, OBJECT) + CASE_TYPE(math, OP_MODULE, CALLABLE) + CASE_TYPE(math, OP_MODULE, SIGNAL) + CASE_TYPE(math, OP_MODULE, DICTIONARY) CASE_TYPE(math, OP_MODULE, ARRAY) CASE_TYPE(math, OP_MODULE, PACKED_BYTE_ARRAY) @@ -2968,15 +3011,15 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { } #endif - Variant::CallError ce; - ce.error = Variant::CallError::CALL_OK; + Callable::CallError ce; + ce.error = Callable::CallError::CALL_OK; Array ref; ref.push_back(r_iter); Variant vref = ref; const Variant *refp[] = { &vref }; Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_init, refp, 1, ce); - if (ref.size() != 1 || ce.error != Variant::CallError::CALL_OK) { + if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) { valid = false; return false; } @@ -3138,15 +3181,15 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { } #endif - Variant::CallError ce; - ce.error = Variant::CallError::CALL_OK; + Callable::CallError ce; + ce.error = Callable::CallError::CALL_OK; Array ref; ref.push_back(r_iter); Variant vref = ref; const Variant *refp[] = { &vref }; Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_next, refp, 1, ce); - if (ref.size() != 1 || ce.error != Variant::CallError::CALL_OK) { + if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) { valid = false; return false; } @@ -3297,12 +3340,12 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { } #endif - Variant::CallError ce; - ce.error = Variant::CallError::CALL_OK; + Callable::CallError ce; + ce.error = Callable::CallError::CALL_OK; const Variant *refp[] = { &r_iter }; Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_get, refp, 1, ce); - if (ce.error != Variant::CallError::CALL_OK) { + if (ce.error != Callable::CallError::CALL_OK) { r_valid = false; return Variant(); } |