diff --git a/core/array.cpp b/core/array.cpp index 2253d05605ae..7eb15ea934ee 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 583a44846ff2..f5a351f16a29 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 000000000000..34b79cea1058 --- /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