diff options
Diffstat (limited to 'core')
56 files changed, 4369 insertions, 563 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..cecf2264a3 --- /dev/null +++ b/core/callable.h @@ -0,0 +1,161 @@ +/*************************************************************************/ +/* 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 efficient 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/callable_method_pointer.cpp b/core/callable_method_pointer.cpp new file mode 100644 index 0000000000..8774af6add --- /dev/null +++ b/core/callable_method_pointer.cpp @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* callable_method_pointer.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_method_pointer.h" + +bool CallableCustomMethodPointerBase::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { + const CallableCustomMethodPointerBase *a = static_cast<const CallableCustomMethodPointerBase *>(p_a); + const CallableCustomMethodPointerBase *b = static_cast<const CallableCustomMethodPointerBase *>(p_b); + + if (a->comp_size != b->comp_size) { + return false; + } + + for (uint32_t i = 0; i < a->comp_size; i++) { + if (a->comp_ptr[i] != b->comp_ptr[i]) { + return false; + } + } + + return true; +} + +bool CallableCustomMethodPointerBase::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { + + const CallableCustomMethodPointerBase *a = static_cast<const CallableCustomMethodPointerBase *>(p_a); + const CallableCustomMethodPointerBase *b = static_cast<const CallableCustomMethodPointerBase *>(p_b); + + if (a->comp_size != b->comp_size) { + return a->comp_size < b->comp_size; + } + + for (uint32_t i = 0; i < a->comp_size; i++) { + if (a->comp_ptr[i] == b->comp_ptr[i]) { + continue; + } + + return a->comp_ptr[i] < b->comp_ptr[i]; + } + + return false; +} + +CallableCustom::CompareEqualFunc CallableCustomMethodPointerBase::get_compare_equal_func() const { + return compare_equal; +} + +CallableCustom::CompareLessFunc CallableCustomMethodPointerBase::get_compare_less_func() const { + return compare_less; +} + +uint32_t CallableCustomMethodPointerBase::hash() const { + return h; +} + +void CallableCustomMethodPointerBase::_setup(uint32_t *p_base_ptr, uint32_t p_ptr_size) { + comp_ptr = p_base_ptr; + comp_size = p_ptr_size / 4; + + // Precompute hash. + for (uint32_t i = 0; i < comp_size; i++) { + if (i == 0) { + h = hash_djb2_one_32(comp_ptr[i]); + } else { + h = hash_djb2_one_32(comp_ptr[i], h); + } + } +} diff --git a/core/callable_method_pointer.h b/core/callable_method_pointer.h new file mode 100644 index 0000000000..fed793dfca --- /dev/null +++ b/core/callable_method_pointer.h @@ -0,0 +1,279 @@ +/*************************************************************************/ +/* callable_method_pointer.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_METHOD_POINTER_H +#define CALLABLE_METHOD_POINTER_H + +#include "core/callable.h" +#include "core/hashfuncs.h" +#include "core/object.h" +#include "core/simple_type.h" + +class CallableCustomMethodPointerBase : public CallableCustom { + + uint32_t *comp_ptr; + uint32_t comp_size; + uint32_t h; +#ifdef DEBUG_METHODS_ENABLED + const char *text = ""; +#endif + static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b); + static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b); + +protected: + void _setup(uint32_t *p_base_ptr, uint32_t p_ptr_size); + +public: +#ifdef DEBUG_METHODS_ENABLED + void set_text(const char *p_text) { + text = p_text; + } + virtual String get_as_text() const { + return text; + } +#else + virtual String get_as_text() const { + return String(); + } +#endif + virtual CompareEqualFunc get_compare_equal_func() const; + virtual CompareLessFunc get_compare_less_func() const; + + virtual uint32_t hash() const; +}; + +#ifdef DEBUG_METHODS_ENABLED + +template <class T> +struct VariantCasterAndValidate { + + static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) { + Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE; + if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype)) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = p_arg_idx; + r_error.expected = argtype; + } + + return VariantCaster<T>::cast(*p_args[p_arg_idx]); + } +}; + +template <class T> +struct VariantCasterAndValidate<T &> { + + static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) { + Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE; + if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype)) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = p_arg_idx; + r_error.expected = argtype; + } + + return VariantCaster<T>::cast(*p_args[p_arg_idx]); + } +}; + +template <class T> +struct VariantCasterAndValidate<const T &> { + + static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) { + Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE; + if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype)) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = p_arg_idx; + r_error.expected = argtype; + } + + return VariantCaster<T>::cast(*p_args[p_arg_idx]); + } +}; + +#endif // DEBUG_METHODS_ENABLED + +// GCC 8 raises "parameter 'p_args' set but not used" here, probably using a +// template version that does not have arguments and thus sees it unused, but +// obviously the template can be used for functions with and without them, and +// the optimizer will get rid of it anyway. +#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-but-set-parameter" +#endif + +template <class T, class... P, size_t... Is> +void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) { + r_error.error = Callable::CallError::CALL_OK; + +#ifdef DEBUG_METHODS_ENABLED + (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); +#else + (p_instance->*p_method)(VariantCaster<P...>::cast(p_args[Is])...); +#endif +} + +#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + +template <class T, class... P> +void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +#ifdef DEBUG_METHODS_ENABLED + if ((size_t)p_argcount > sizeof...(P)) { + r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.argument = sizeof...(P); + return; + } + + if ((size_t)p_argcount < sizeof...(P)) { + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = sizeof...(P); + return; + } +#endif + call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{}); +} + +template <class T, class... P> +class CallableCustomMethodPointer : public CallableCustomMethodPointerBase { + + struct Data { + T *instance; + void (T::*method)(P...); + } data; + +public: + virtual ObjectID get_object() const { return data.instance->get_instance_id(); } + + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { + + call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error); + } + + CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) { + zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes. + data.instance = p_instance; + data.method = p_method; + _setup((uint32_t *)&data, sizeof(Data)); + } +}; + +template <class T, class... P> +Callable create_custom_callable_function_pointer(T *p_instance, +#ifdef DEBUG_METHODS_ENABLED + const char *p_func_text, +#endif + void (T::*p_method)(P...)) { + + typedef CallableCustomMethodPointer<T, P...> CCMP; // Messes with memnew otherwise. + CCMP *ccmp = memnew(CCMP(p_instance, p_method)); +#ifdef DEBUG_METHODS_ENABLED + ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand. +#endif + return Callable(ccmp); +} + +// VERSION WITH RETURN + +template <class T, class R, class... P, size_t... Is> +void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) { + r_error.error = Callable::CallError::CALL_OK; + +#ifdef DEBUG_METHODS_ENABLED + r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); +#else + (p_instance->*p_method)(VariantCaster<P...>::cast(p_args[Is])...); +#endif +} + +template <class T, class R, class... P> +void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) { +#ifdef DEBUG_METHODS_ENABLED + if ((size_t)p_argcount > sizeof...(P)) { + r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.argument = sizeof...(P); + return; + } + + if ((size_t)p_argcount < sizeof...(P)) { + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = sizeof...(P); + return; + } +#endif + call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{}); +} + +template <class T, class R, class... P> +class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase { + + struct Data { + T *instance; + R(T::*method) + (P...); + } data; + +public: + virtual ObjectID get_object() const { return data.instance->get_instance_id(); } + + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { + + call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error); + } + + CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) { + zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes. + data.instance = p_instance; + data.method = p_method; + _setup((uint32_t *)&data, sizeof(Data)); + } +}; + +template <class T, class R, class... P> +Callable create_custom_callable_function_pointer(T *p_instance, +#ifdef DEBUG_METHODS_ENABLED + const char *p_func_text, +#endif + R (T::*p_method)(P...)) { + + typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise. + CCMP *ccmp = memnew(CCMP(p_instance, p_method)); +#ifdef DEBUG_METHODS_ENABLED + ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand. +#endif + return Callable(ccmp); +} + +#ifdef DEBUG_METHODS_ENABLED +#define callable_mp(I, M) create_custom_callable_function_pointer(I, #M, M) +#else +#define callable_mp(I, M) create_custom_callable_function_pointer(I, M) +#endif + +#endif // CALLABLE_METHOD_POINTER_H diff --git a/core/class_db.cpp b/core/class_db.cpp index 2fd0ee2d89..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; } @@ -1410,10 +1420,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con cleanup_c = false; } else if (ClassDB::can_instance(p_class)) { c = ClassDB::instance(p_class); -#ifndef _MSC_VER -#warning FIXME: ObjectID refactoring broke GDScript handling of reference pointers, this needs a proper fix. -#endif - cleanup_c = (p_class != StringName("GDScript")); + cleanup_c = true; } if (c) { diff --git a/core/class_db.h b/core/class_db.h index 404b04f2d0..398eca9132 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -35,13 +35,15 @@ #include "core/object.h" #include "core/print_string.h" -/** To bind more then 6 parameters include this: +/** To bind more then 6 parameters include this: * #include "core/method_bind_ext.gen.inc" */ -#define DEFVAL(m_defval) (m_defval) +// Makes callable_mp readily available in all classes connecting signals. +// Needs to come after method_bind and object have been included. +#include "core/callable_method_pointer.h" -//#define SIMPLE_METHODDEF +#define DEFVAL(m_defval) (m_defval) #ifdef DEBUG_METHODS_ENABLED 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..3de36dcb9d 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -606,9 +606,12 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM", Variant::TRANSFORM); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME); // 15 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..e97c26e05d 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -187,6 +187,18 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int (*r_len) += 4 * 2; } break; // 5 + case Variant::VECTOR2I: { + + ERR_FAIL_COND_V(len < 4 * 2, ERR_INVALID_DATA); + Vector2i val; + val.x = decode_uint32(&buf[0]); + val.y = decode_uint32(&buf[4]); + r_variant = val; + + if (r_len) + (*r_len) += 4 * 2; + + } break; // 5 case Variant::RECT2: { ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); @@ -201,6 +213,20 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int (*r_len) += 4 * 4; } break; + case Variant::RECT2I: { + + ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); + Rect2i val; + val.position.x = decode_uint32(&buf[0]); + val.position.y = decode_uint32(&buf[4]); + val.size.x = decode_uint32(&buf[8]); + val.size.y = decode_uint32(&buf[12]); + r_variant = val; + + if (r_len) + (*r_len) += 4 * 4; + + } break; case Variant::VECTOR3: { ERR_FAIL_COND_V(len < 4 * 3, ERR_INVALID_DATA); @@ -214,6 +240,19 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int (*r_len) += 4 * 3; } break; + case Variant::VECTOR3I: { + + ERR_FAIL_COND_V(len < 4 * 3, ERR_INVALID_DATA); + Vector3i val; + val.x = decode_uint32(&buf[0]); + val.y = decode_uint32(&buf[4]); + val.z = decode_uint32(&buf[8]); + r_variant = val; + + if (r_len) + (*r_len) += 4 * 3; + + } break; case Variant::TRANSFORM2D: { ERR_FAIL_COND_V(len < 4 * 6, ERR_INVALID_DATA); @@ -328,6 +367,16 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int (*r_len) += 4 * 4; } break; + case Variant::STRING_NAME: { + + String str; + Error err = _decode_string(buf, len, r_len, str); + if (err) + return err; + r_variant = StringName(str); + + } break; + case Variant::NODE_PATH: { ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); @@ -455,6 +504,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); @@ -930,6 +988,11 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo _encode_string(p_variant, buf, r_len); } break; + case Variant::STRING_NAME: { + + _encode_string(p_variant, buf, r_len); + + } break; // math types case Variant::VECTOR2: { @@ -943,6 +1006,17 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len += 2 * 4; } break; // 5 + case Variant::VECTOR2I: { + + if (buf) { + Vector2i v2 = p_variant; + encode_uint32(v2.x, &buf[0]); + encode_uint32(v2.y, &buf[4]); + } + + r_len += 2 * 4; + + } break; // 5 case Variant::RECT2: { if (buf) { @@ -955,6 +1029,18 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len += 4 * 4; } break; + case Variant::RECT2I: { + + if (buf) { + Rect2i r2 = p_variant; + encode_uint32(r2.position.x, &buf[0]); + encode_uint32(r2.position.y, &buf[4]); + encode_uint32(r2.size.x, &buf[8]); + encode_uint32(r2.size.y, &buf[12]); + } + r_len += 4 * 4; + + } break; case Variant::VECTOR3: { if (buf) { @@ -967,6 +1053,18 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len += 3 * 4; } break; + case Variant::VECTOR3I: { + + if (buf) { + Vector3i v3 = p_variant; + encode_uint32(v3.x, &buf[0]); + encode_uint32(v3.y, &buf[4]); + encode_uint32(v3.z, &buf[8]); + } + + r_len += 3 * 4; + + } break; case Variant::TRANSFORM2D: { if (buf) { @@ -1075,6 +1173,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..6a0eeea513 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -51,7 +51,7 @@ _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_mas case MultiplayerAPI::RPC_MODE_MASTERSYNC: { if (is_master) r_skip_rpc = true; // I am the master, so skip remote call. - FALLTHROUGH; + [[fallthrough]]; } case MultiplayerAPI::RPC_MODE_REMOTESYNC: case MultiplayerAPI::RPC_MODE_PUPPETSYNC: { @@ -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..518323c5c4 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -73,6 +73,12 @@ enum { VARIANT_VECTOR2_ARRAY = 37, VARIANT_INT64 = 40, VARIANT_DOUBLE = 41, + VARIANT_CALLABLE = 42, + VARIANT_SIGNAL = 43, + VARIANT_STRING_NAME = 44, + VARIANT_VECTOR2I = 45, + VARIANT_RECT2I = 46, + VARIANT_VECTOR3I = 47, OBJECT_EMPTY = 0, OBJECT_EXTERNAL_RESOURCE = 1, OBJECT_INTERNAL_RESOURCE = 2, @@ -156,6 +162,14 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { r_v = v; } break; + case VARIANT_VECTOR2I: { + + Vector2i v; + v.x = f->get_32(); + v.y = f->get_32(); + r_v = v; + + } break; case VARIANT_RECT2: { Rect2 v; @@ -166,6 +180,16 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { r_v = v; } break; + case VARIANT_RECT2I: { + + Rect2i v; + v.position.x = f->get_32(); + v.position.y = f->get_32(); + v.size.x = f->get_32(); + v.size.y = f->get_32(); + r_v = v; + + } break; case VARIANT_VECTOR3: { Vector3 v; @@ -174,6 +198,14 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { v.z = f->get_real(); r_v = v; } break; + case VARIANT_VECTOR3I: { + + Vector3i v; + v.x = f->get_32(); + v.y = f->get_32(); + v.z = f->get_32(); + r_v = v; + } break; case VARIANT_PLANE: { Plane v; @@ -258,6 +290,10 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { r_v = v; } break; + case VARIANT_STRING_NAME: { + + r_v = StringName(get_unicode_string()); + } break; case VARIANT_NODE_PATH: { @@ -363,6 +399,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(); @@ -1277,6 +1322,14 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.y); } break; + case Variant::VECTOR2I: { + + f->store_32(VARIANT_VECTOR2I); + Vector2i val = p_property; + f->store_32(val.x); + f->store_32(val.y); + + } break; case Variant::RECT2: { f->store_32(VARIANT_RECT2); @@ -1287,6 +1340,16 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.size.y); } break; + case Variant::RECT2I: { + + f->store_32(VARIANT_RECT2I); + Rect2i val = p_property; + f->store_32(val.position.x); + f->store_32(val.position.y); + f->store_32(val.size.x); + f->store_32(val.size.y); + + } break; case Variant::VECTOR3: { f->store_32(VARIANT_VECTOR3); @@ -1296,6 +1359,15 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.z); } break; + case Variant::VECTOR3I: { + + f->store_32(VARIANT_VECTOR3I); + Vector3i val = p_property; + f->store_32(val.x); + f->store_32(val.y); + f->store_32(val.z); + + } break; case Variant::PLANE: { f->store_32(VARIANT_PLANE); @@ -1383,6 +1455,13 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.a); } break; + case Variant::STRING_NAME: { + + f->store_32(VARIANT_STRING_NAME); + String val = p_property; + save_unicode_string(f, val); + + } break; case Variant::NODE_PATH: { f->store_32(VARIANT_NODE_PATH); @@ -1440,6 +1519,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/resource_loader.cpp b/core/io/resource_loader.cpp index 1d5d8f9280..39bbebefa6 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -248,7 +248,7 @@ void ResourceFormatLoader::_bind_methods() { } ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_recognized_extensions")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles_type", PropertyInfo(Variant::STRING, "typename"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles_type", PropertyInfo(Variant::STRING_NAME, "typename"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type", PropertyInfo(Variant::STRING, "path"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames"))); 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/math/rect2.h b/core/math/rect2.h index 0d2e7eb6e5..e4ea615c22 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -387,6 +387,11 @@ struct Rect2i { size = end - begin; } + _FORCE_INLINE_ Rect2i abs() const { + + return Rect2i(Point2i(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); + } + operator String() const { return String(position) + ", " + String(size); } operator Rect2() const { return Rect2(position, size); } diff --git a/core/math/vector2.h b/core/math/vector2.h index 1dec830821..ba5558102f 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -311,10 +311,15 @@ struct Vector2i { bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } + bool operator<=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } + bool operator>=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } + bool operator==(const Vector2i &p_vec2) const; bool operator!=(const Vector2i &p_vec2) const; - real_t get_aspect() const { return width / (real_t)height; } + real_t aspect() const { return width / (real_t)height; } + Vector2i sign() const { return Vector2i(SGN(x), SGN(y)); } + Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); } operator String() const { return String::num(x) + ", " + String::num(y); } 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..726ce512f8 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -31,19 +31,18 @@ #ifndef METHOD_BIND_H #define METHOD_BIND_H +#ifdef DEBUG_ENABLED +#define DEBUG_METHODS_ENABLED +#endif + #include "core/list.h" #include "core/method_ptrcall.h" #include "core/object.h" +#include "core/type_info.h" #include "core/variant.h" #include <stdio.h> -#ifdef DEBUG_ENABLED -#define DEBUG_METHODS_ENABLED -#endif - -#include "core/type_info.h" - enum MethodFlags { METHOD_FLAG_NORMAL = 1, @@ -155,7 +154,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 +277,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 +299,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 +337,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 +388,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..7e21c2cc24 100644 --- a/core/method_ptrcall.h +++ b/core/method_ptrcall.h @@ -125,9 +125,12 @@ MAKE_PTRARG_BY_REFERENCE(AABB); MAKE_PTRARG_BY_REFERENCE(Basis); MAKE_PTRARG_BY_REFERENCE(Transform); MAKE_PTRARG_BY_REFERENCE(Color); +MAKE_PTRARG(StringName); MAKE_PTRARG(NodePath); MAKE_PTRARG(RID); MAKE_PTRARG(Dictionary); +MAKE_PTRARG(Callable); +MAKE_PTRARG(Signal); MAKE_PTRARG(Array); MAKE_PTRARG(PackedByteArray); MAKE_PTRARG(PackedIntArray); @@ -371,29 +374,7 @@ MAKE_VECARR(Plane); } \ } -//MAKE_DVECARR(Plane); -//for special case StringName - -#define MAKE_STRINGCONV(m_type) \ - template <> \ - struct PtrToArg<m_type> { \ - _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ - m_type s = *reinterpret_cast<const String *>(p_ptr); \ - return s; \ - } \ - _FORCE_INLINE_ static void encode(m_type p_vec, void *p_ptr) { \ - String *arr = reinterpret_cast<String *>(p_ptr); \ - *arr = p_vec; \ - } \ - }; \ - \ - template <> \ - struct PtrToArg<const m_type &> { \ - _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ - m_type s = *reinterpret_cast<const String *>(p_ptr); \ - return s; \ - } \ - } +// Special case for IP_Address. #define MAKE_STRINGCONV_BY_REFERENCE(m_type) \ template <> \ @@ -416,7 +397,6 @@ MAKE_VECARR(Plane); } \ } -MAKE_STRINGCONV(StringName); MAKE_STRINGCONV_BY_REFERENCE(IP_Address); template <> diff --git a/core/node_path.h b/core/node_path.h index 5439658910..05b6d844ff 100644 --- a/core/node_path.h +++ b/core/node_path.h @@ -54,15 +54,6 @@ class NodePath { void _update_hash_cache() const; public: - _FORCE_INLINE_ StringName get_sname() const { - - if (data && data->path.size() == 1 && data->subpath.empty()) { - return data->path[0]; - } else { - return operator String(); - } - } - bool is_absolute() const; int get_name_count() const; StringName get_name(int p_idx) const; diff --git a/core/object.cpp b/core/object.cpp index 0a7a46a7d2..a61c4ae392 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,18 +638,18 @@ 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; + if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; - r_error.expected = Variant::STRING; + r_error.expected = Variant::STRING_NAME; 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; + if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; - r_error.expected = Variant::STRING; + r_error.expected = Variant::STRING_NAME; 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: { } } } @@ -917,10 +900,9 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a MethodBind *method = ClassDB::get_method(get_class_name(), p_method); 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; @@ -1103,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; } @@ -1118,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; + if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) { + 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.expected = Variant::STRING_NAME; + ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING_NAME && 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]; @@ -1155,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); @@ -1171,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(); @@ -1185,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; @@ -1210,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) + "' to callable: " + Variant::get_callable_error_text(c.callable, args, argc, ce) + "."); err = ERR_METHOD_NOT_FOUND; } } @@ -1242,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); } } @@ -1251,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(); } @@ -1323,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); } } @@ -1343,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; @@ -1381,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++) { @@ -1392,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 @@ -1407,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) { @@ -1426,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 @@ -1449,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; } @@ -1485,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 { + + return is_connected(p_signal, Callable(p_to_object, p_to_method)); +} - ERR_FAIL_NULL_V(p_to_object, false); - const Signal *s = signal_map.getptr(p_signal); +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) @@ -1500,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 @@ -1529,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 @@ -1680,7 +1663,7 @@ void Object::_bind_methods() { { MethodInfo mi; mi.name = "emit_signal"; - mi.arguments.push_back(PropertyInfo(Variant::STRING, "signal")); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "signal")); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "emit_signal", &Object::_emit_signal, mi, varray(), false); } @@ -1688,7 +1671,7 @@ void Object::_bind_methods() { { MethodInfo mi; mi.name = "call"; - mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call", &Object::_call_bind, mi); } @@ -1696,7 +1679,7 @@ void Object::_bind_methods() { { MethodInfo mi; mi.name = "call_deferred"; - mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_deferred", &Object::_call_deferred_bind, mi, varray(), false); } @@ -1711,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); @@ -1730,9 +1713,9 @@ void Object::_bind_methods() { ADD_SIGNAL(MethodInfo("script_changed")); BIND_VMETHOD(MethodInfo("_notification", PropertyInfo(Variant::INT, "what"))); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "_set", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_set", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value"))); #ifdef TOOLS_ENABLED - MethodInfo miget("_get", PropertyInfo(Variant::STRING, "property")); + MethodInfo miget("_get", PropertyInfo(Variant::STRING_NAME, "property")); miget.return_val.name = "Variant"; miget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; BIND_VMETHOD(miget); @@ -1830,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++) { @@ -1957,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); @@ -1975,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/os/input_event.cpp b/core/os/input_event.cpp index 2e863c9c76..7d1ae872f4 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -1098,7 +1098,7 @@ void InputEventAction::_bind_methods() { // ClassDB::bind_method(D_METHOD("is_action", "name"), &InputEventAction::is_action); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "action"), "set_action", "get_action"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action"), "set_action", "get_action"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_strength", "get_strength"); } diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp index ae5f89e870..6a4fac971c 100644 --- a/core/packed_data_container.cpp +++ b/core/packed_data_container.cpp @@ -225,8 +225,8 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd string_cache[s] = tmpdata.size(); - FALLTHROUGH; - }; + [[fallthrough]]; + } case Variant::NIL: case Variant::BOOL: case Variant::INT: @@ -247,6 +247,7 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd case Variant::PACKED_VECTOR2_ARRAY: case Variant::PACKED_VECTOR3_ARRAY: case Variant::PACKED_COLOR_ARRAY: + case Variant::STRING_NAME: case Variant::NODE_PATH: { uint32_t pos = tmpdata.size(); diff --git a/core/reference.h b/core/reference.h index b01e0035a7..36e7d5c6a6 100644 --- a/core/reference.h +++ b/core/reference.h @@ -170,9 +170,9 @@ public: return; } - Reference *r = Object::cast_to<Reference>(object); + T *r = Object::cast_to<T>(object); if (r && r->reference()) { - reference = static_cast<T *>(r); + reference = r; } } @@ -226,9 +226,9 @@ public: return; } - Reference *r = Object::cast_to<Reference>(object); + T *r = Object::cast_to<T>(object); if (r && r->reference()) { - reference = static_cast<T *>(r); + reference = r; } else { reference = nullptr; } 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/resource.cpp b/core/resource.cpp index 30e09716aa..2afc9e4042 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -423,7 +423,7 @@ void Resource::_bind_methods() { ADD_GROUP("Resource", "resource_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_path", "get_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_name"), "set_name", "get_name"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "resource_name"), "set_name", "get_name"); BIND_VMETHOD(MethodInfo("_setup_local_to_scene")); } diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp new file mode 100644 index 0000000000..fdb6135edd --- /dev/null +++ b/core/script_debugger_remote.cpp @@ -0,0 +1,1145 @@ +/*************************************************************************/ +/* script_debugger_remote.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 "script_debugger_remote.h" + +#include "core/engine.h" +#include "core/io/ip.h" +#include "core/io/marshalls.h" +#include "core/os/input.h" +#include "core/os/os.h" +#include "core/project_settings.h" +#include "servers/visual_server.h" + +#define CHECK_SIZE(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() < (uint32_t)(expected), false, String("Malformed ") + what + " message from script debugger, message too short. Exptected size: " + itos(expected) + ", actual size: " + itos(arr.size())) +#define CHECK_END(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() > (uint32_t)expected, false, String("Malformed ") + what + " message from script debugger, message too short. Exptected size: " + itos(expected) + ", actual size: " + itos(arr.size())) + +Array ScriptDebuggerRemote::ScriptStackDump::serialize() { + Array arr; + arr.push_back(frames.size() * 3); + for (int i = 0; i < frames.size(); i++) { + arr.push_back(frames[i].file); + arr.push_back(frames[i].line); + arr.push_back(frames[i].func); + } + return arr; +} + +bool ScriptDebuggerRemote::ScriptStackDump::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 1, "ScriptStackDump"); + uint32_t size = p_arr[0]; + CHECK_SIZE(p_arr, size, "ScriptStackDump"); + int idx = 1; + for (uint32_t i = 0; i < size / 3; i++) { + ScriptLanguage::StackInfo sf; + sf.file = p_arr[idx]; + sf.line = p_arr[idx + 1]; + sf.func = p_arr[idx + 2]; + frames.push_back(sf); + idx += 3; + } + CHECK_END(p_arr, idx, "ScriptStackDump"); + return true; +} + +Array ScriptDebuggerRemote::ScriptStackVariable::serialize(int max_size) { + Array arr; + arr.push_back(name); + arr.push_back(type); + + Variant var = value; + if (value.get_type() == Variant::OBJECT && value.get_validated_object() == nullptr) { + var = Variant(); + } + + int len = 0; + Error err = encode_variant(var, NULL, len, true); + if (err != OK) + ERR_PRINT("Failed to encode variant."); + + if (len > max_size) { + arr.push_back(Variant()); + } else { + arr.push_back(var); + } + return arr; +} + +bool ScriptDebuggerRemote::ScriptStackVariable::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 3, "ScriptStackVariable"); + name = p_arr[0]; + type = p_arr[1]; + value = p_arr[2]; + CHECK_END(p_arr, 3, "ScriptStackVariable"); + return true; +} + +Array ScriptDebuggerRemote::OutputError::serialize() { + Array arr; + arr.push_back(hr); + arr.push_back(min); + arr.push_back(sec); + arr.push_back(msec); + arr.push_back(source_file); + arr.push_back(source_func); + arr.push_back(source_line); + arr.push_back(error); + arr.push_back(error_descr); + arr.push_back(warning); + unsigned int size = callstack.size(); + const ScriptLanguage::StackInfo *r = callstack.ptr(); + arr.push_back(size * 3); + for (int i = 0; i < callstack.size(); i++) { + arr.push_back(r[i].file); + arr.push_back(r[i].func); + arr.push_back(r[i].line); + } + return arr; +} + +bool ScriptDebuggerRemote::OutputError::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 11, "OutputError"); + hr = p_arr[0]; + min = p_arr[1]; + sec = p_arr[2]; + msec = p_arr[3]; + source_file = p_arr[4]; + source_func = p_arr[5]; + source_line = p_arr[6]; + error = p_arr[7]; + error_descr = p_arr[8]; + warning = p_arr[9]; + unsigned int stack_size = p_arr[10]; + CHECK_SIZE(p_arr, stack_size, "OutputError"); + int idx = 11; + callstack.resize(stack_size / 3); + ScriptLanguage::StackInfo *w = callstack.ptrw(); + for (unsigned int i = 0; i < stack_size / 3; i++) { + w[i].file = p_arr[idx]; + w[i].func = p_arr[idx + 1]; + w[i].line = p_arr[idx + 2]; + idx += 3; + } + CHECK_END(p_arr, idx, "OutputError"); + return true; +} + +Array ScriptDebuggerRemote::ResourceUsage::serialize() { + infos.sort(); + + Array arr; + arr.push_back(infos.size() * 4); + for (List<ResourceInfo>::Element *E = infos.front(); E; E = E->next()) { + arr.push_back(E->get().path); + arr.push_back(E->get().format); + arr.push_back(E->get().type); + arr.push_back(E->get().vram); + } + return arr; +} + +bool ScriptDebuggerRemote::ResourceUsage::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 1, "ResourceUsage"); + uint32_t size = p_arr[0]; + CHECK_SIZE(p_arr, size, "ResourceUsage"); + int idx = 1; + for (uint32_t i = 0; i < size / 4; i++) { + ResourceInfo info; + info.path = p_arr[idx]; + info.format = p_arr[idx + 1]; + info.type = p_arr[idx + 2]; + info.vram = p_arr[idx + 3]; + infos.push_back(info); + } + CHECK_END(p_arr, idx, "ResourceUsage"); + return true; +} + +Array ScriptDebuggerRemote::ProfilerSignature::serialize() { + Array arr; + arr.push_back(name); + arr.push_back(id); + return arr; +} + +bool ScriptDebuggerRemote::ProfilerSignature::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 2, "ProfilerSignature"); + name = p_arr[0]; + id = p_arr[1]; + CHECK_END(p_arr, 2, "ProfilerSignature"); + return true; +} + +Array ScriptDebuggerRemote::ProfilerFrame::serialize() { + Array arr; + arr.push_back(frame_number); + arr.push_back(frame_time); + arr.push_back(idle_time); + arr.push_back(physics_time); + arr.push_back(physics_frame_time); + arr.push_back(USEC_TO_SEC(script_time)); + + arr.push_back(frames_data.size()); + arr.push_back(frame_functions.size() * 4); + + // Servers profiling info. + for (int i = 0; i < frames_data.size(); i++) { + arr.push_back(frames_data[i].name); // Type (physics/process/audio/...) + arr.push_back(frames_data[i].data.size()); + for (int j = 0; j < frames_data[i].data.size() / 2; j++) { + arr.push_back(frames_data[i].data[2 * j]); // NAME + arr.push_back(frames_data[i].data[2 * j + 1]); // TIME + } + } + for (int i = 0; i < frame_functions.size(); i++) { + arr.push_back(frame_functions[i].sig_id); + arr.push_back(frame_functions[i].call_count); + arr.push_back(frame_functions[i].self_time); + arr.push_back(frame_functions[i].total_time); + } + return arr; +} + +bool ScriptDebuggerRemote::ProfilerFrame::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 8, "ProfilerFrame"); + frame_number = p_arr[0]; + frame_time = p_arr[1]; + idle_time = p_arr[2]; + physics_time = p_arr[3]; + physics_frame_time = p_arr[4]; + script_time = p_arr[5]; + uint32_t frame_data_size = p_arr[6]; + int frame_func_size = p_arr[7]; + int idx = 8; + while (frame_data_size) { + CHECK_SIZE(p_arr, idx + 2, "ProfilerFrame"); + frame_data_size--; + FrameData fd; + fd.name = p_arr[idx]; + int sub_data_size = p_arr[idx + 1]; + idx += 2; + CHECK_SIZE(p_arr, idx + sub_data_size, "ProfilerFrame"); + for (int j = 0; j < sub_data_size / 2; j++) { + fd.data.push_back(p_arr[idx]); // NAME + fd.data.push_back(p_arr[idx + 1]); // TIME + idx += 2; + } + frames_data.push_back(fd); + } + CHECK_SIZE(p_arr, idx + frame_func_size, "ProfilerFrame"); + for (int i = 0; i < frame_func_size / 4; i++) { + FrameFunction ff; + ff.sig_id = p_arr[idx]; + ff.call_count = p_arr[idx + 1]; + ff.self_time = p_arr[idx + 2]; + ff.total_time = p_arr[idx + 3]; + frame_functions.push_back(ff); + idx += 4; + } + CHECK_END(p_arr, idx, "ProfilerFrame"); + return true; +} + +Array ScriptDebuggerRemote::NetworkProfilerFrame::serialize() { + Array arr; + arr.push_back(infos.size() * 6); + for (int i = 0; i < infos.size(); ++i) { + arr.push_back(uint64_t(infos[i].node)); + arr.push_back(infos[i].node_path); + arr.push_back(infos[i].incoming_rpc); + arr.push_back(infos[i].incoming_rset); + arr.push_back(infos[i].outgoing_rpc); + arr.push_back(infos[i].outgoing_rset); + } + return arr; +} + +bool ScriptDebuggerRemote::NetworkProfilerFrame::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 1, "NetworkProfilerFrame"); + uint32_t size = p_arr[0]; + CHECK_SIZE(p_arr, size, "NetworkProfilerFrame"); + infos.resize(size); + int idx = 1; + for (uint32_t i = 0; i < size / 6; ++i) { + infos.write[i].node = uint64_t(p_arr[idx]); + infos.write[i].node_path = p_arr[idx + 1]; + infos.write[i].incoming_rpc = p_arr[idx + 2]; + infos.write[i].incoming_rset = p_arr[idx + 3]; + infos.write[i].outgoing_rpc = p_arr[idx + 4]; + infos.write[i].outgoing_rset = p_arr[idx + 5]; + } + CHECK_END(p_arr, idx, "NetworkProfilerFrame"); + return true; +} + +void ScriptDebuggerRemote::_put_msg(String p_message, Array p_data) { + Array msg; + msg.push_back(p_message); + msg.push_back(p_data); + packet_peer_stream->put_var(msg); +} + +bool ScriptDebuggerRemote::is_peer_connected() { + return tcp_client->is_connected_to_host() && tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED; +} + +void ScriptDebuggerRemote::_send_video_memory() { + + ResourceUsage usage; + if (resource_usage_func) + resource_usage_func(&usage); + + _put_msg("message:video_mem", usage.serialize()); +} + +Error ScriptDebuggerRemote::connect_to_host(const String &p_host, uint16_t p_port) { + + IP_Address ip; + if (p_host.is_valid_ip_address()) + ip = p_host; + else + ip = IP::get_singleton()->resolve_hostname(p_host); + + int port = p_port; + + const int tries = 6; + int waits[tries] = { 1, 10, 100, 1000, 1000, 1000 }; + + tcp_client->connect_to_host(ip, port); + + for (int i = 0; i < tries; i++) { + + if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) { + print_verbose("Remote Debugger: Connected!"); + break; + } else { + + const int ms = waits[i]; + OS::get_singleton()->delay_usec(ms * 1000); + print_verbose("Remote Debugger: Connection failed with status: '" + String::num(tcp_client->get_status()) + "', retrying in " + String::num(ms) + " msec."); + }; + }; + + if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) { + + ERR_PRINT("Remote Debugger: Unable to connect. Status: " + String::num(tcp_client->get_status()) + "."); + return FAILED; + }; + + packet_peer_stream->set_stream_peer(tcp_client); + Array msg; + msg.push_back(OS::get_singleton()->get_process_id()); + send_message("set_pid", msg); + + return OK; +} + +void ScriptDebuggerRemote::_parse_message(const String p_command, const Array &p_data, ScriptLanguage *p_script) { + + if (p_command == "request_video_mem") { + _send_video_memory(); + + } else if (p_command == "start_profiling") { + ERR_FAIL_COND(p_data.size() < 1); + + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->profiling_start(); + } + + max_frame_functions = p_data[0]; + profiler_function_signature_map.clear(); + profiling = true; + frame_time = 0; + idle_time = 0; + physics_time = 0; + physics_frame_time = 0; + print_line("PROFILING ALRIGHT!"); + + } else if (p_command == "stop_profiling") { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->profiling_stop(); + } + profiling = false; + _send_profiling_data(false); + print_line("PROFILING END!"); + + } else if (p_command == "start_visual_profiling") { + + visual_profiling = true; + VS::get_singleton()->set_frame_profiling_enabled(true); + } else if (p_command == "stop_visual_profiling") { + + visual_profiling = false; + VS::get_singleton()->set_frame_profiling_enabled(false); + + } else if (p_command == "start_network_profiling") { + + network_profiling = true; + multiplayer->profiling_start(); + + } else if (p_command == "stop_network_profiling") { + + network_profiling = false; + multiplayer->profiling_end(); + + } else if (p_command == "reload_scripts") { + reload_all_scripts = true; + + } else if (p_command == "breakpoint") { + ERR_FAIL_COND(p_data.size() < 3); + bool set = p_data[2]; + if (set) + insert_breakpoint(p_data[1], p_data[0]); + else + remove_breakpoint(p_data[1], p_data[0]); + + } else if (p_command == "set_skip_breakpoints") { + ERR_FAIL_COND(p_data.size() < 1); + skip_breakpoints = p_data[0]; + + } else if (p_command == "get_stack_dump") { + ERR_FAIL_COND(!p_script); + ScriptStackDump dump; + int slc = p_script->debug_get_stack_level_count(); + for (int i = 0; i < slc; i++) { + ScriptLanguage::StackInfo frame; + frame.file = p_script->debug_get_stack_level_source(i); + frame.line = p_script->debug_get_stack_level_line(i); + frame.func = p_script->debug_get_stack_level_function(i); + dump.frames.push_back(frame); + } + _put_msg("stack_dump", dump.serialize()); + + } else if (p_command == "get_stack_frame_vars") { + ERR_FAIL_COND(p_data.size() != 1); + ERR_FAIL_COND(!p_script); + int lv = p_data[0]; + + List<String> members; + List<Variant> member_vals; + if (ScriptInstance *inst = p_script->debug_get_stack_level_instance(lv)) { + members.push_back("self"); + member_vals.push_back(inst->get_owner()); + } + p_script->debug_get_stack_level_members(lv, &members, &member_vals); + ERR_FAIL_COND(members.size() != member_vals.size()); + + List<String> locals; + List<Variant> local_vals; + p_script->debug_get_stack_level_locals(lv, &locals, &local_vals); + ERR_FAIL_COND(locals.size() != local_vals.size()); + + List<String> globals; + List<Variant> globals_vals; + p_script->debug_get_globals(&globals, &globals_vals); + ERR_FAIL_COND(globals.size() != globals_vals.size()); + + _put_msg("stack_frame_vars", Array()); + + ScriptStackVariable stvar; + { //locals + List<String>::Element *E = locals.front(); + List<Variant>::Element *F = local_vals.front(); + while (E) { + stvar.name = E->get(); + stvar.value = F->get(); + stvar.type = 0; + _put_msg("stack_frame_var", stvar.serialize()); + + E = E->next(); + F = F->next(); + } + } + + { //members + List<String>::Element *E = members.front(); + List<Variant>::Element *F = member_vals.front(); + while (E) { + stvar.name = E->get(); + stvar.value = F->get(); + stvar.type = 1; + _put_msg("stack_frame_var", stvar.serialize()); + + E = E->next(); + F = F->next(); + } + } + + { //globals + List<String>::Element *E = globals.front(); + List<Variant>::Element *F = globals_vals.front(); + while (E) { + stvar.name = E->get(); + stvar.value = F->get(); + stvar.type = 2; + _put_msg("stack_frame_var", stvar.serialize()); + + E = E->next(); + F = F->next(); + } + } + + } else { + if (scene_tree_parse_func) { + scene_tree_parse_func(p_command, p_data); + } + // Unknown message... + } +} + +void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue, bool p_is_error_breakpoint) { + + //this function is called when there is a debugger break (bug on script) + //or when execution is paused from editor + + if (skip_breakpoints && !p_is_error_breakpoint) + return; + + ERR_FAIL_COND_MSG(!is_peer_connected(), "Script Debugger failed to connect, but being used anyway."); + + Array msg; + msg.push_back(p_can_continue); + msg.push_back(p_script->debug_get_error()); + _put_msg("debug_enter", msg); + + skip_profile_frame = true; // to avoid super long frame time for the frame + + Input::MouseMode mouse_mode = Input::get_singleton()->get_mouse_mode(); + if (mouse_mode != Input::MOUSE_MODE_VISIBLE) + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + + uint64_t loop_begin_usec = 0; + uint64_t loop_time_sec = 0; + while (true) { + loop_begin_usec = OS::get_singleton()->get_ticks_usec(); + + _get_output(); + + if (packet_peer_stream->get_available_packet_count() > 0) { + + Variant var; + Error err = packet_peer_stream->get_var(var); + + ERR_CONTINUE(err != OK); + ERR_CONTINUE(var.get_type() != Variant::ARRAY); + + Array cmd = var; + + ERR_CONTINUE(cmd.size() != 2); + ERR_CONTINUE(cmd[0].get_type() != Variant::STRING); + ERR_CONTINUE(cmd[1].get_type() != Variant::ARRAY); + + String command = cmd[0]; + Array data = cmd[1]; + if (command == "step") { + + set_depth(-1); + set_lines_left(1); + break; + } else if (command == "next") { + + set_depth(0); + set_lines_left(1); + break; + + } else if (command == "continue") { + set_depth(-1); + set_lines_left(-1); + OS::get_singleton()->move_window_to_foreground(); + break; + } else if (command == "break") { + ERR_PRINT("Got break when already broke!"); + break; + } + + _parse_message(command, data, p_script); + } else { + OS::get_singleton()->delay_usec(10000); + OS::get_singleton()->process_and_drop_events(); + } + + // This is for the camera override to stay live even when the game is paused from the editor + loop_time_sec = (OS::get_singleton()->get_ticks_usec() - loop_begin_usec) / 1000000.0f; + VisualServer::get_singleton()->sync(); + if (VisualServer::get_singleton()->has_changed()) { + VisualServer::get_singleton()->draw(true, loop_time_sec * Engine::get_singleton()->get_time_scale()); + } + } + + _put_msg("debug_exit", Array()); + + if (mouse_mode != Input::MOUSE_MODE_VISIBLE) + Input::get_singleton()->set_mouse_mode(mouse_mode); +} + +void ScriptDebuggerRemote::_get_output() { + + mutex->lock(); + if (output_strings.size()) { + + locking = true; + + while (output_strings.size()) { + + Array arr; + arr.push_back(output_strings.front()->get()); + _put_msg("output", arr); + output_strings.pop_front(); + } + locking = false; + } + + if (n_messages_dropped > 0) { + Message msg; + msg.message = "Too many messages! " + String::num_int64(n_messages_dropped) + " messages were dropped."; + messages.push_back(msg); + n_messages_dropped = 0; + } + + while (messages.size()) { + locking = true; + Message msg = messages.front()->get(); + _put_msg("message:" + msg.message, msg.data); + messages.pop_front(); + locking = false; + } + + if (n_errors_dropped == 1) { + // Only print one message about dropping per second + OutputError oe; + oe.error = "TOO_MANY_ERRORS"; + oe.error_descr = "Too many errors! Ignoring errors for up to 1 second."; + oe.warning = false; + uint64_t time = OS::get_singleton()->get_ticks_msec(); + oe.hr = time / 3600000; + oe.min = (time / 60000) % 60; + oe.sec = (time / 1000) % 60; + oe.msec = time % 1000; + errors.push_back(oe); + } + + if (n_warnings_dropped == 1) { + // Only print one message about dropping per second + OutputError oe; + oe.error = "TOO_MANY_WARNINGS"; + oe.error_descr = "Too many warnings! Ignoring warnings for up to 1 second."; + oe.warning = true; + uint64_t time = OS::get_singleton()->get_ticks_msec(); + oe.hr = time / 3600000; + oe.min = (time / 60000) % 60; + oe.sec = (time / 1000) % 60; + oe.msec = time % 1000; + errors.push_back(oe); + } + + while (errors.size()) { + locking = true; + OutputError oe = errors.front()->get(); + _put_msg("error", oe.serialize()); + errors.pop_front(); + locking = false; + } + mutex->unlock(); +} + +void ScriptDebuggerRemote::line_poll() { + + //the purpose of this is just processing events every now and then when the script might get too busy + //otherwise bugs like infinite loops can't be caught + if (poll_every % 2048 == 0) + _poll_events(); + poll_every++; +} + +void ScriptDebuggerRemote::_err_handler(void *ud, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, ErrorHandlerType p_type) { + + if (p_type == ERR_HANDLER_SCRIPT) + return; //ignore script errors, those go through debugger + + Vector<ScriptLanguage::StackInfo> si; + + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + si = ScriptServer::get_language(i)->debug_get_current_stack_info(); + if (si.size()) + break; + } + + ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote *)ud; + sdr->send_error(p_func, p_file, p_line, p_err, p_descr, p_type, si); +} + +void ScriptDebuggerRemote::_poll_events() { + + //this si called from ::idle_poll, happens only when running the game, + //does not get called while on debug break + + while (packet_peer_stream->get_available_packet_count() > 0) { + + _get_output(); + + //send over output_strings + + Variant var; + Error err = packet_peer_stream->get_var(var); + + ERR_CONTINUE(err != OK); + ERR_CONTINUE(var.get_type() != Variant::ARRAY); + + Array cmd = var; + + ERR_CONTINUE(cmd.size() < 2); + ERR_CONTINUE(cmd[0].get_type() != Variant::STRING); + ERR_CONTINUE(cmd[1].get_type() != Variant::ARRAY); + + String command = cmd[0]; + Array data = cmd[1]; + + if (command == "break") { + + if (get_break_language()) + debug(get_break_language()); + } else { + _parse_message(command, data); + } + } +} + +void ScriptDebuggerRemote::_send_profiling_data(bool p_for_frame) { + + int ofs = 0; + + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + if (p_for_frame) + ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&profile_info.write[ofs], profile_info.size() - ofs); + else + ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&profile_info.write[ofs], profile_info.size() - ofs); + } + + for (int i = 0; i < ofs; i++) { + profile_info_ptrs.write[i] = &profile_info.write[i]; + } + + SortArray<ScriptLanguage::ProfilingInfo *, ProfileInfoSort> sa; + sa.sort(profile_info_ptrs.ptrw(), ofs); + + int to_send = MIN(ofs, max_frame_functions); + + //check signatures first + uint64_t total_script_time = 0; + + for (int i = 0; i < to_send; i++) { + + if (!profiler_function_signature_map.has(profile_info_ptrs[i]->signature)) { + + int idx = profiler_function_signature_map.size(); + ProfilerSignature sig; + sig.name = profile_info_ptrs[i]->signature; + sig.id = idx; + _put_msg("profile_sig", sig.serialize()); + profiler_function_signature_map[profile_info_ptrs[i]->signature] = idx; + } + + total_script_time += profile_info_ptrs[i]->self_time; + } + + //send frames then + ProfilerFrame metric; + metric.frame_number = Engine::get_singleton()->get_frames_drawn(); + metric.frame_time = frame_time; + metric.idle_time = idle_time; + metric.physics_time = physics_time; + metric.physics_frame_time = physics_frame_time; + metric.script_time = total_script_time; + + // Add script functions information. + metric.frame_functions.resize(to_send); + FrameFunction *w = metric.frame_functions.ptrw(); + for (int i = 0; i < to_send; i++) { + + if (profiler_function_signature_map.has(profile_info_ptrs[i]->signature)) { + w[i].sig_id = profiler_function_signature_map[profile_info_ptrs[i]->signature]; + } + + w[i].call_count = profile_info_ptrs[i]->call_count; + w[i].total_time = profile_info_ptrs[i]->total_time / 1000000.0; + w[i].self_time = profile_info_ptrs[i]->self_time / 1000000.0; + } + if (p_for_frame) { + // Add profile frame data information. + metric.frames_data.append_array(profile_frame_data); + _put_msg("profile_frame", metric.serialize()); + profile_frame_data.clear(); + } else { + _put_msg("profile_total", metric.serialize()); + } +} + +void ScriptDebuggerRemote::idle_poll() { + + // this function is called every frame, except when there is a debugger break (::debug() in this class) + // execution stops and remains in the ::debug function + + _get_output(); + + if (requested_quit) { + + _put_msg("kill_me", Array()); + requested_quit = false; + } + + if (performance) { + + uint64_t pt = OS::get_singleton()->get_ticks_msec(); + if (pt - last_perf_time > 1000) { + + last_perf_time = pt; + int max = performance->get("MONITOR_MAX"); + Array arr; + arr.resize(max); + for (int i = 0; i < max; i++) { + arr[i] = performance->call("get_monitor", i); + } + _put_msg("performance", arr); + } + } + + if (visual_profiling) { + Vector<VS::FrameProfileArea> profile_areas = VS::get_singleton()->get_frame_profile(); + if (profile_areas.size()) { + Vector<String> area_names; + Vector<real_t> area_times; + area_names.resize(profile_areas.size()); + area_times.resize(profile_areas.size() * 2); + { + String *area_namesw = area_names.ptrw(); + real_t *area_timesw = area_times.ptrw(); + + for (int i = 0; i < profile_areas.size(); i++) { + area_namesw[i] = profile_areas[i].name; + area_timesw[i * 2 + 0] = profile_areas[i].cpu_msec; + area_timesw[i * 2 + 1] = profile_areas[i].gpu_msec; + } + } + Array msg; + msg.push_back(VS::get_singleton()->get_frame_profile_frame()); + msg.push_back(area_names); + msg.push_back(area_times); + _put_msg("visual_profile", msg); + } + } + + if (profiling) { + + if (skip_profile_frame) { + skip_profile_frame = false; + } else { + //send profiling info normally + _send_profiling_data(true); + } + } + + if (network_profiling) { + uint64_t pt = OS::get_singleton()->get_ticks_msec(); + if (pt - last_net_bandwidth_time > 200) { + last_net_bandwidth_time = pt; + _send_network_bandwidth_usage(); + } + if (pt - last_net_prof_time > 100) { + last_net_prof_time = pt; + _send_network_profiling_data(); + } + } + + if (reload_all_scripts) { + + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->reload_all_scripts(); + } + reload_all_scripts = false; + } + + _poll_events(); +} + +void ScriptDebuggerRemote::_send_network_profiling_data() { + ERR_FAIL_COND(multiplayer.is_null()); + + int n_nodes = multiplayer->get_profiling_frame(&network_profile_info.write[0]); + + NetworkProfilerFrame frame; + for (int i = 0; i < n_nodes; i++) { + frame.infos.push_back(network_profile_info[i]); + } + _put_msg("network_profile", frame.serialize()); +} + +void ScriptDebuggerRemote::_send_network_bandwidth_usage() { + ERR_FAIL_COND(multiplayer.is_null()); + + int incoming_bandwidth = multiplayer->get_incoming_bandwidth_usage(); + int outgoing_bandwidth = multiplayer->get_outgoing_bandwidth_usage(); + + Array arr; + arr.push_back(incoming_bandwidth); + arr.push_back(outgoing_bandwidth); + _put_msg("network_bandwidth", arr); +} + +void ScriptDebuggerRemote::send_message(const String &p_message, const Array &p_args) { + + mutex->lock(); + if (!locking && is_peer_connected()) { + + if (messages.size() >= max_messages_per_frame) { + n_messages_dropped++; + } else { + Message msg; + msg.message = p_message; + msg.data = p_args; + messages.push_back(msg); + } + } + mutex->unlock(); +} + +void ScriptDebuggerRemote::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info) { + + OutputError oe; + oe.error = p_err; + oe.error_descr = p_descr; + oe.source_file = p_file; + oe.source_line = p_line; + oe.source_func = p_func; + oe.warning = p_type == ERR_HANDLER_WARNING; + uint64_t time = OS::get_singleton()->get_ticks_msec(); + oe.hr = time / 3600000; + oe.min = (time / 60000) % 60; + oe.sec = (time / 1000) % 60; + oe.msec = time % 1000; + Array cstack; + + uint64_t ticks = OS::get_singleton()->get_ticks_usec() / 1000; + msec_count += ticks - last_msec; + last_msec = ticks; + + if (msec_count > 1000) { + msec_count = 0; + + err_count = 0; + n_errors_dropped = 0; + warn_count = 0; + n_warnings_dropped = 0; + } + + cstack.resize(p_stack_info.size() * 3); + for (int i = 0; i < p_stack_info.size(); i++) { + cstack[i * 3 + 0] = p_stack_info[i].file; + cstack[i * 3 + 1] = p_stack_info[i].func; + cstack[i * 3 + 2] = p_stack_info[i].line; + } + + //oe.callstack = cstack; + if (oe.warning) { + warn_count++; + } else { + err_count++; + } + + mutex->lock(); + + if (!locking && is_peer_connected()) { + + if (oe.warning) { + if (warn_count > max_warnings_per_second) { + n_warnings_dropped++; + } else { + errors.push_back(oe); + } + } else { + if (err_count > max_errors_per_second) { + n_errors_dropped++; + } else { + errors.push_back(oe); + } + } + } + + mutex->unlock(); +} + +void ScriptDebuggerRemote::_print_handler(void *p_this, const String &p_string, bool p_error) { + + ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote *)p_this; + + uint64_t ticks = OS::get_singleton()->get_ticks_usec() / 1000; + sdr->msec_count += ticks - sdr->last_msec; + sdr->last_msec = ticks; + + if (sdr->msec_count > 1000) { + sdr->char_count = 0; + sdr->msec_count = 0; + } + + String s = p_string; + int allowed_chars = MIN(MAX(sdr->max_cps - sdr->char_count, 0), s.length()); + + if (allowed_chars == 0) + return; + + if (allowed_chars < s.length()) { + s = s.substr(0, allowed_chars); + } + + sdr->char_count += allowed_chars; + bool overflowed = sdr->char_count >= sdr->max_cps; + + sdr->mutex->lock(); + if (!sdr->locking && sdr->is_peer_connected()) { + + if (overflowed) + s += "[...]"; + + sdr->output_strings.push_back(s); + + if (overflowed) { + sdr->output_strings.push_back("[output overflow, print less text!]"); + } + } + sdr->mutex->unlock(); +} + +void ScriptDebuggerRemote::request_quit() { + + requested_quit = true; +} + +void ScriptDebuggerRemote::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) { + multiplayer = p_multiplayer; +} + +bool ScriptDebuggerRemote::is_profiling() const { + + return profiling; +} +void ScriptDebuggerRemote::add_profiling_frame_data(const StringName &p_name, const Array &p_data) { + + int idx = -1; + for (int i = 0; i < profile_frame_data.size(); i++) { + if (profile_frame_data[i].name == p_name) { + idx = i; + break; + } + } + + FrameData fd; + fd.name = p_name; + fd.data = p_data; + + if (idx == -1) { + profile_frame_data.push_back(fd); + } else { + profile_frame_data.write[idx] = fd; + } +} + +void ScriptDebuggerRemote::profiling_start() { + //ignores this, uses it via connection +} + +void ScriptDebuggerRemote::profiling_end() { + //ignores this, uses it via connection +} + +void ScriptDebuggerRemote::profiling_set_frame_times(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { + + frame_time = p_frame_time; + idle_time = p_idle_time; + physics_time = p_physics_time; + physics_frame_time = p_physics_frame_time; +} + +void ScriptDebuggerRemote::set_skip_breakpoints(bool p_skip_breakpoints) { + skip_breakpoints = p_skip_breakpoints; +} + +ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func = NULL; +ScriptDebuggerRemote::ParseMessageFunc ScriptDebuggerRemote::scene_tree_parse_func = NULL; + +ScriptDebuggerRemote::ScriptDebuggerRemote() : + profiling(false), + visual_profiling(false), + network_profiling(false), + max_frame_functions(16), + skip_profile_frame(false), + reload_all_scripts(false), + tcp_client(Ref<StreamPeerTCP>(memnew(StreamPeerTCP))), + packet_peer_stream(Ref<PacketPeerStream>(memnew(PacketPeerStream))), + last_perf_time(0), + last_net_prof_time(0), + last_net_bandwidth_time(0), + performance(Engine::get_singleton()->get_singleton_object("Performance")), + requested_quit(false), + mutex(Mutex::create()), + max_messages_per_frame(GLOBAL_GET("network/limits/debugger_stdout/max_messages_per_frame")), + n_messages_dropped(0), + max_errors_per_second(GLOBAL_GET("network/limits/debugger_stdout/max_errors_per_second")), + max_warnings_per_second(GLOBAL_GET("network/limits/debugger_stdout/max_warnings_per_second")), + n_errors_dropped(0), + max_cps(GLOBAL_GET("network/limits/debugger_stdout/max_chars_per_second")), + char_count(0), + err_count(0), + warn_count(0), + last_msec(0), + msec_count(0), + locking(false), + poll_every(0) { + + packet_peer_stream->set_stream_peer(tcp_client); + packet_peer_stream->set_output_buffer_max_size((1024 * 1024 * 8) - 4); // 8 MiB should be way more than enough, minus 4 bytes for separator. + + phl.printfunc = _print_handler; + phl.userdata = this; + add_print_handler(&phl); + + eh.errfunc = _err_handler; + eh.userdata = this; + add_error_handler(&eh); + + profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions")); + network_profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions")); + profile_info_ptrs.resize(profile_info.size()); +} + +ScriptDebuggerRemote::~ScriptDebuggerRemote() { + + remove_print_handler(&phl); + remove_error_handler(&eh); + memdelete(mutex); +} diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h new file mode 100644 index 0000000000..682da1d276 --- /dev/null +++ b/core/script_debugger_remote.h @@ -0,0 +1,316 @@ +/*************************************************************************/ +/* script_debugger_remote.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 SCRIPT_DEBUGGER_REMOTE_H +#define SCRIPT_DEBUGGER_REMOTE_H + +#include "core/io/packet_peer.h" +#include "core/io/stream_peer_tcp.h" +#include "core/list.h" +#include "core/os/os.h" +#include "core/script_language.h" + +class ScriptDebuggerRemote : public ScriptDebugger { + +public: + class ResourceInfo { + public: + String path; + String format; + String type; + RID id; + int vram; + bool operator<(const ResourceInfo &p_img) const { return vram == p_img.vram ? id < p_img.id : vram > p_img.vram; } + ResourceInfo() { + vram = 0; + } + }; + + class ResourceUsage { + public: + List<ResourceInfo> infos; + + Array serialize(); + bool deserialize(const Array &p_arr); + }; + + class FrameInfo { + public: + StringName name; + float self_time; + float total_time; + + FrameInfo() { + self_time = 0; + total_time = 0; + } + }; + + class FrameFunction { + public: + int sig_id; + int call_count; + StringName name; + float self_time; + float total_time; + + FrameFunction() { + sig_id = -1; + call_count = 0; + self_time = 0; + total_time = 0; + } + }; + + class ScriptStackVariable { + public: + String name; + Variant value; + int type; + ScriptStackVariable() { + type = -1; + } + + Array serialize(int max_size = 1 << 20); // 1 MiB default. + bool deserialize(const Array &p_arr); + }; + + class ScriptStackDump { + public: + List<ScriptLanguage::StackInfo> frames; + ScriptStackDump() {} + + Array serialize(); + bool deserialize(const Array &p_arr); + }; + + class Message { + + public: + String message; + Array data; + + Message() {} + }; + + class OutputError { + public: + int hr; + int min; + int sec; + int msec; + String source_file; + String source_func; + int source_line; + String error; + String error_descr; + bool warning; + Vector<ScriptLanguage::StackInfo> callstack; + + OutputError() { + hr = -1; + min = -1; + sec = -1; + msec = -1; + source_line = -1; + warning = false; + } + + Array serialize(); + bool deserialize(const Array &p_arr); + }; + + struct FrameData { + + StringName name; + Array data; + }; + + class ProfilerSignature { + public: + StringName name; + int id; + + Array serialize(); + bool deserialize(const Array &p_arr); + + ProfilerSignature() { + id = -1; + }; + }; + + class ProfilerFrame { + public: + int frame_number; + float frame_time; + float idle_time; + float physics_time; + float physics_frame_time; + float script_time; + + Vector<FrameData> frames_data; + Vector<FrameFunction> frame_functions; + + ProfilerFrame() { + frame_number = 0; + frame_time = 0; + idle_time = 0; + physics_time = 0; + physics_frame_time = 0; + } + + Array serialize(); + bool deserialize(const Array &p_arr); + }; + + class NetworkProfilerFrame { + public: + Vector<MultiplayerAPI::ProfilingInfo> infos; + + Array serialize(); + bool deserialize(const Array &p_arr); + + NetworkProfilerFrame(){}; + }; + +protected: + struct ProfileInfoSort { + + bool operator()(ScriptLanguage::ProfilingInfo *A, ScriptLanguage::ProfilingInfo *B) const { + return A->total_time < B->total_time; + } + }; + + Vector<ScriptLanguage::ProfilingInfo> profile_info; + Vector<ScriptLanguage::ProfilingInfo *> profile_info_ptrs; + Vector<MultiplayerAPI::ProfilingInfo> network_profile_info; + + Map<StringName, int> profiler_function_signature_map; + float frame_time, idle_time, physics_time, physics_frame_time; + + bool profiling; + bool visual_profiling; + bool network_profiling; + int max_frame_functions; + bool skip_profile_frame; + bool reload_all_scripts; + + Ref<StreamPeerTCP> tcp_client; + Ref<PacketPeerStream> packet_peer_stream; + + uint64_t last_perf_time; + uint64_t last_net_prof_time; + uint64_t last_net_bandwidth_time; + Object *performance; + bool requested_quit; + Mutex *mutex; + + List<String> output_strings; + List<Message> messages; + int max_messages_per_frame; + int n_messages_dropped; + List<OutputError> errors; + int max_errors_per_second; + int max_warnings_per_second; + int n_errors_dropped; + int n_warnings_dropped; + + int max_cps; + int char_count; + int err_count; + int warn_count; + uint64_t last_msec; + uint64_t msec_count; + + bool locking; //hack to avoid a deadloop + static void _print_handler(void *p_this, const String &p_string, bool p_error); + + PrintHandlerList phl; + + void _get_output(); + void _poll_events(); + uint32_t poll_every; + + void _parse_message(const String p_command, const Array &p_data, ScriptLanguage *p_script = NULL); + + void _set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value); + + void _send_object_id(ObjectID p_id); + void _send_video_memory(); + + Ref<MultiplayerAPI> multiplayer; + + ErrorHandlerList eh; + static void _err_handler(void *, const char *, const char *, int p_line, const char *, const char *, ErrorHandlerType p_type); + + void _put_msg(String p_message, Array p_data); + void _send_profiling_data(bool p_for_frame); + void _send_network_profiling_data(); + void _send_network_bandwidth_usage(); + + Vector<FrameData> profile_frame_data; + + bool skip_breakpoints; + +public: + typedef void (*ResourceUsageFunc)(ResourceUsage *); + typedef Error (*ParseMessageFunc)(const String &p_name, const Array &p_msg); // Returns true if something was found (stopping propagation). + + static ResourceUsageFunc resource_usage_func; + static ParseMessageFunc scene_tree_parse_func; // Could be made into list, extensible... + + Error connect_to_host(const String &p_host, uint16_t p_port); + bool is_peer_connected(); + virtual void debug(ScriptLanguage *p_script, bool p_can_continue = true, bool p_is_error_breakpoint = false); + virtual void idle_poll(); + virtual void line_poll(); + + virtual bool is_remote() const { return true; } + virtual void request_quit(); + + virtual void send_message(const String &p_message, const Array &p_args); + virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info); + + virtual void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer); + + virtual bool is_profiling() const; + virtual void add_profiling_frame_data(const StringName &p_name, const Array &p_data); + + virtual void profiling_start(); + virtual void profiling_end(); + virtual void profiling_set_frame_times(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time); + + virtual void set_skip_breakpoints(bool p_skip_breakpoints); + + ScriptDebuggerRemote(); + ~ScriptDebuggerRemote(); +}; + +#endif // SCRIPT_DEBUGGER_REMOTE_H 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..6861531fbd 100644 --- a/core/type_info.h +++ b/core/type_info.h @@ -151,8 +151,11 @@ MAKE_TYPE_INFO(AABB, Variant::AABB) MAKE_TYPE_INFO(Basis, Variant::BASIS) MAKE_TYPE_INFO(Transform, Variant::TRANSFORM) MAKE_TYPE_INFO(Color, Variant::COLOR) +MAKE_TYPE_INFO(StringName, Variant::STRING_NAME) 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) @@ -163,7 +166,6 @@ MAKE_TYPE_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) MAKE_TYPE_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) MAKE_TYPE_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY) -MAKE_TYPE_INFO(StringName, Variant::STRING) MAKE_TYPE_INFO(IP_Address, Variant::STRING) //objectID diff --git a/core/typedefs.h b/core/typedefs.h index 0bb80cb2dd..5376b0718a 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -335,26 +335,16 @@ struct _GlobalLock { */ #define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr)) -/** Hint for compilers that this fallthrough in a switch is intentional. - * Can be replaced by [[fallthrough]] annotation if we move to C++17. - * Including conditional support for it for people who set -std=c++17 - * themselves. - * Requires a trailing semicolon when used. - */ -#if __cplusplus >= 201703L -#define FALLTHROUGH [[fallthrough]] -#elif defined(__GNUC__) && __GNUC__ >= 7 -#define FALLTHROUGH __attribute__((fallthrough)) -#elif defined(__llvm__) && __cplusplus >= 201103L && defined(__has_feature) -#if __has_feature(cxx_attributes) && defined(__has_warning) -#if __has_warning("-Wimplicit-fallthrough") -#define FALLTHROUGH [[clang::fallthrough]] -#endif -#endif -#endif +// Home-made index sequence trick, so it can be used everywhere without the costly include of std::tuple. +// https://stackoverflow.com/questions/15014096/c-index-of-type-during-variadic-template-expansion -#ifndef FALLTHROUGH -#define FALLTHROUGH -#endif +template <size_t... Is> +struct IndexSequence {}; + +template <size_t N, size_t... Is> +struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {}; + +template <size_t... Is> +struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {}; #endif // TYPEDEFS_H diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 577879d448..02f460c93d 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -105,7 +105,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { action_level++; } -void UndoRedo::add_do_method(Object *p_object, const String &p_method, VARIANT_ARG_DECLARE) { +void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) { VARIANT_ARGPTRS ERR_FAIL_COND(p_object == NULL); @@ -125,7 +125,7 @@ void UndoRedo::add_do_method(Object *p_object, const String &p_method, VARIANT_A actions.write[current_action + 1].do_ops.push_back(do_op); } -void UndoRedo::add_undo_method(Object *p_object, const String &p_method, VARIANT_ARG_DECLARE) { +void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) { VARIANT_ARGPTRS ERR_FAIL_COND(p_object == NULL); @@ -149,7 +149,7 @@ void UndoRedo::add_undo_method(Object *p_object, const String &p_method, VARIANT } actions.write[current_action + 1].undo_ops.push_back(undo_op); } -void UndoRedo::add_do_property(Object *p_object, const String &p_property, const Variant &p_value) { +void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value) { ERR_FAIL_COND(p_object == NULL); ERR_FAIL_COND(action_level <= 0); @@ -164,7 +164,7 @@ void UndoRedo::add_do_property(Object *p_object, const String &p_property, const do_op.args[0] = p_value; actions.write[current_action + 1].do_ops.push_back(do_op); } -void UndoRedo::add_undo_property(Object *p_object, const String &p_property, const Variant &p_value) { +void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value) { ERR_FAIL_COND(p_object == NULL); ERR_FAIL_COND(action_level <= 0); @@ -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,32 +431,32 @@ 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; + if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; - r_error.expected = Variant::STRING; + r_error.expected = Variant::STRING_NAME; 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]; + StringName method = *p_args[1]; Variant v[VARIANT_ARG_MAX]; @@ -469,32 +469,32 @@ 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; + if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; - r_error.expected = Variant::STRING; + r_error.expected = Variant::STRING_NAME; 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]; + StringName method = *p_args[1]; Variant v[VARIANT_ARG_MAX]; @@ -518,7 +518,7 @@ void UndoRedo::_bind_methods() { MethodInfo mi; mi.name = "add_do_method"; mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); - mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_do_method", &UndoRedo::_add_do_method, mi, varray(), false); } @@ -527,7 +527,7 @@ void UndoRedo::_bind_methods() { MethodInfo mi; mi.name = "add_undo_method"; mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); - mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_undo_method", &UndoRedo::_add_undo_method, mi, varray(), false); } diff --git a/core/undo_redo.h b/core/undo_redo.h index bb9a4d1642..3b91e9ce36 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); @@ -65,7 +65,7 @@ private: Type type; Ref<Resource> resref; ObjectID object; - String name; + StringName name; Variant args[VARIANT_ARG_MAX]; }; @@ -103,10 +103,10 @@ protected: public: void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE); - void add_do_method(Object *p_object, const String &p_method, VARIANT_ARG_LIST); - void add_undo_method(Object *p_object, const String &p_method, VARIANT_ARG_LIST); - void add_do_property(Object *p_object, const String &p_property, const Variant &p_value); - void add_undo_property(Object *p_object, const String &p_property, const Variant &p_value); + void add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST); + void add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST); + void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value); + void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value); void add_do_reference(Object *p_object); void add_undo_reference(Object *p_object); diff --git a/core/ustring.cpp b/core/ustring.cpp index c4543b89da..1d4d9c2dfd 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -2169,6 +2169,7 @@ int64_t String::to_int(const CharType *p_str, int p_len) { } else { break; } + [[fallthrough]]; } case READING_INT: { diff --git a/core/variant.cpp b/core/variant.cpp index b849a83cb4..1acb0e7a73 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -72,10 +72,18 @@ String Variant::get_type_name(Variant::Type p_type) { return "Vector2"; } break; + case VECTOR2I: { + + return "Vector2i"; + } break; case RECT2: { return "Rect2"; } break; + case RECT2I: { + + return "Rect2i"; + } break; case TRANSFORM2D: { return "Transform2D"; @@ -84,6 +92,10 @@ String Variant::get_type_name(Variant::Type p_type) { return "Vector3"; } break; + case VECTOR3I: { + + return "Vector3i"; + } break; case PLANE: { return "Plane"; @@ -128,6 +140,19 @@ String Variant::get_type_name(Variant::Type p_type) { return "Object"; } break; + case CALLABLE: { + + return "Callable"; + } break; + case SIGNAL: { + + return "Signal"; + } break; + case STRING_NAME: { + + return "StringName"; + + } break; case NODE_PATH: { return "NodePath"; @@ -245,6 +270,46 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { invalid_types = invalid; } break; + case VECTOR2: { + + static const Type valid[] = { + VECTOR2I, + NIL, + }; + + valid_types = valid; + + } break; + case VECTOR2I: { + + static const Type valid[] = { + VECTOR2, + NIL, + }; + + valid_types = valid; + + } break; + case RECT2: { + + static const Type valid[] = { + RECT2I, + NIL, + }; + + valid_types = valid; + + } break; + case RECT2I: { + + static const Type valid[] = { + RECT2, + NIL, + }; + + valid_types = valid; + + } break; case TRANSFORM2D: { static const Type valid[] = { @@ -254,6 +319,27 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { valid_types = valid; } break; + case VECTOR3: { + + static const Type valid[] = { + VECTOR3I, + NIL, + }; + + valid_types = valid; + + } break; + case VECTOR3I: { + + static const Type valid[] = { + VECTOR3, + NIL, + }; + + valid_types = valid; + + } break; + case QUAT: { static const Type valid[] = { @@ -317,6 +403,15 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { valid_types = valid; } break; + case STRING_NAME: { + + static const Type valid[] = { + STRING, + NIL + }; + + valid_types = valid; + } break; case NODE_PATH: { static const Type valid[] = { @@ -487,11 +582,52 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type static const Type valid[] = { NODE_PATH, + STRING_NAME, NIL }; valid_types = valid; } break; + case VECTOR2: { + + static const Type valid[] = { + VECTOR2I, + NIL, + }; + + valid_types = valid; + + } break; + case VECTOR2I: { + + static const Type valid[] = { + VECTOR2, + NIL, + }; + + valid_types = valid; + + } break; + case RECT2: { + + static const Type valid[] = { + RECT2I, + NIL, + }; + + valid_types = valid; + + } break; + case RECT2I: { + + static const Type valid[] = { + RECT2, + NIL, + }; + + valid_types = valid; + + } break; case TRANSFORM2D: { static const Type valid[] = { @@ -501,6 +637,27 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; + case VECTOR3: { + + static const Type valid[] = { + VECTOR3I, + NIL, + }; + + valid_types = valid; + + } break; + case VECTOR3I: { + + static const Type valid[] = { + VECTOR3, + NIL, + }; + + valid_types = valid; + + } break; + case QUAT: { static const Type valid[] = { @@ -564,6 +721,15 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; + case STRING_NAME: { + + static const Type valid[] = { + STRING, + NIL + }; + + valid_types = valid; + } break; case NODE_PATH: { static const Type valid[] = { @@ -733,11 +899,21 @@ bool Variant::is_zero() const { return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2(); } break; + case VECTOR2I: { + + return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i(); + + } break; case RECT2: { return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2(); } break; + case RECT2I: { + + return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i(); + + } break; case TRANSFORM2D: { return *_data._transform2d == Transform2D(); @@ -748,6 +924,11 @@ bool Variant::is_zero() const { return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3(); } break; + case VECTOR3I: { + + return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i(); + + } break; case PLANE: { return *reinterpret_cast<const Plane *>(_data._mem) == Plane(); @@ -792,6 +973,19 @@ 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 STRING_NAME: { + + return *reinterpret_cast<const StringName *>(_data._mem) != StringName(); + + } break; case NODE_PATH: { return reinterpret_cast<const NodePath *>(_data._mem)->is_empty(); @@ -879,16 +1073,31 @@ bool Variant::is_one() const { return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2(1, 1); } break; + case VECTOR2I: { + + return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i(1, 1); + + } break; case RECT2: { return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2(1, 1, 1, 1); } break; + case RECT2I: { + + return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i(1, 1, 1, 1); + + } break; case VECTOR3: { return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3(1, 1, 1); } break; + case VECTOR3I: { + + return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i(1, 1, 1); + + } break; case PLANE: { return *reinterpret_cast<const Plane *>(_data._mem) == Plane(1, 1, 1, 1); @@ -959,10 +1168,18 @@ void Variant::reference(const Variant &p_variant) { memnew_placement(_data._mem, Vector2(*reinterpret_cast<const Vector2 *>(p_variant._data._mem))); } break; + case VECTOR2I: { + + memnew_placement(_data._mem, Vector2i(*reinterpret_cast<const Vector2i *>(p_variant._data._mem))); + } break; case RECT2: { memnew_placement(_data._mem, Rect2(*reinterpret_cast<const Rect2 *>(p_variant._data._mem))); } break; + case RECT2I: { + + memnew_placement(_data._mem, Rect2i(*reinterpret_cast<const Rect2i *>(p_variant._data._mem))); + } break; case TRANSFORM2D: { _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d)); @@ -971,6 +1188,10 @@ void Variant::reference(const Variant &p_variant) { memnew_placement(_data._mem, Vector3(*reinterpret_cast<const Vector3 *>(p_variant._data._mem))); } break; + case VECTOR3I: { + + memnew_placement(_data._mem, Vector3i(*reinterpret_cast<const Vector3i *>(p_variant._data._mem))); + } break; case PLANE: { memnew_placement(_data._mem, Plane(*reinterpret_cast<const Plane *>(p_variant._data._mem))); @@ -1022,6 +1243,19 @@ 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 STRING_NAME: { + + memnew_placement(_data._mem, StringName(*reinterpret_cast<const StringName *>(p_variant._data._mem))); + + } break; case NODE_PATH: { memnew_placement(_data._mem, NodePath(*reinterpret_cast<const NodePath *>(p_variant._data._mem))); @@ -1086,8 +1320,11 @@ void Variant::zero() { case INT: this->_data._int = 0; break; case REAL: this->_data._real = 0; break; case VECTOR2: *reinterpret_cast<Vector2 *>(this->_data._mem) = Vector2(); break; + case VECTOR2I: *reinterpret_cast<Vector2i *>(this->_data._mem) = Vector2i(); break; case RECT2: *reinterpret_cast<Rect2 *>(this->_data._mem) = Rect2(); break; + case RECT2I: *reinterpret_cast<Rect2i *>(this->_data._mem) = Rect2i(); break; case VECTOR3: *reinterpret_cast<Vector3 *>(this->_data._mem) = Vector3(); break; + case VECTOR3I: *reinterpret_cast<Vector3i *>(this->_data._mem) = Vector3i(); break; case PLANE: *reinterpret_cast<Plane *>(this->_data._mem) = Plane(); break; case QUAT: *reinterpret_cast<Quat *>(this->_data._mem) = Quat(); break; case COLOR: *reinterpret_cast<Color *>(this->_data._mem) = Color(); break; @@ -1128,7 +1365,11 @@ void Variant::clear() { memdelete(_data._transform); } break; - // misc types + // misc types + case STRING_NAME: { + + reinterpret_cast<StringName *>(_data._mem)->~StringName(); + } break; case NODE_PATH: { reinterpret_cast<NodePath *>(_data._mem)->~NodePath(); @@ -1149,6 +1390,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(); @@ -1421,10 +1670,13 @@ Variant::operator double() const { Variant::operator StringName() const { - if (type == NODE_PATH) { - return reinterpret_cast<const NodePath *>(_data._mem)->get_sname(); + if (type == STRING_NAME) { + return *reinterpret_cast<const StringName *>(_data._mem); + } else if (type == STRING) { + return *reinterpret_cast<const String *>(_data._mem); } - return StringName(operator String()); + + return StringName(); } struct _VariantStrPair { @@ -1453,13 +1705,16 @@ String Variant::stringify(List<const void *> &stack) const { case REAL: return rtos(_data._real); case STRING: return *reinterpret_cast<const String *>(_data._mem); case VECTOR2: return "(" + operator Vector2() + ")"; + case VECTOR2I: return "(" + operator Vector2i() + ")"; case RECT2: return "(" + operator Rect2() + ")"; + case RECT2I: return "(" + operator Rect2i() + ")"; case TRANSFORM2D: { Transform2D mat32 = operator Transform2D(); return "(" + Variant(mat32.elements[0]).operator String() + ", " + Variant(mat32.elements[1]).operator String() + ", " + Variant(mat32.elements[2]).operator String() + ")"; } break; case VECTOR3: return "(" + operator Vector3() + ")"; + case VECTOR3I: return "(" + operator Vector3i() + ")"; case PLANE: return operator Plane(); //case QUAT: @@ -1491,6 +1746,7 @@ String Variant::stringify(List<const void *> &stack) const { return mtx + ")"; } break; case TRANSFORM: return operator Transform(); + case STRING_NAME: return operator StringName(); case NODE_PATH: return operator NodePath(); case COLOR: return String::num(operator Color().r) + "," + String::num(operator Color().g) + "," + String::num(operator Color().b) + "," + String::num(operator Color().a); case DICTIONARY: { @@ -1627,6 +1883,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) + "]"; } @@ -1639,28 +1907,78 @@ Variant::operator Vector2() const { if (type == VECTOR2) return *reinterpret_cast<const Vector2 *>(_data._mem); + else if (type == VECTOR2I) + return *reinterpret_cast<const Vector2i *>(_data._mem); else if (type == VECTOR3) return Vector2(reinterpret_cast<const Vector3 *>(_data._mem)->x, reinterpret_cast<const Vector3 *>(_data._mem)->y); + else if (type == VECTOR3I) + return Vector2(reinterpret_cast<const Vector3i *>(_data._mem)->x, reinterpret_cast<const Vector3i *>(_data._mem)->y); else return Vector2(); } + +Variant::operator Vector2i() const { + + if (type == VECTOR2I) + return *reinterpret_cast<const Vector2i *>(_data._mem); + else if (type == VECTOR2) + return *reinterpret_cast<const Vector2 *>(_data._mem); + else if (type == VECTOR3) + return Vector2(reinterpret_cast<const Vector3 *>(_data._mem)->x, reinterpret_cast<const Vector3 *>(_data._mem)->y); + else if (type == VECTOR3I) + return Vector2(reinterpret_cast<const Vector3i *>(_data._mem)->x, reinterpret_cast<const Vector3i *>(_data._mem)->y); + else + return Vector2i(); +} + Variant::operator Rect2() const { if (type == RECT2) return *reinterpret_cast<const Rect2 *>(_data._mem); + else if (type == RECT2I) + return *reinterpret_cast<const Rect2i *>(_data._mem); else return Rect2(); } +Variant::operator Rect2i() const { + + if (type == RECT2I) + return *reinterpret_cast<const Rect2i *>(_data._mem); + else if (type == RECT2) + return *reinterpret_cast<const Rect2 *>(_data._mem); + else + return Rect2i(); +} + Variant::operator Vector3() const { if (type == VECTOR3) return *reinterpret_cast<const Vector3 *>(_data._mem); + else if (type == VECTOR3I) + return *reinterpret_cast<const Vector3i *>(_data._mem); else if (type == VECTOR2) return Vector3(reinterpret_cast<const Vector2 *>(_data._mem)->x, reinterpret_cast<const Vector2 *>(_data._mem)->y, 0.0); + else if (type == VECTOR2I) + return Vector3(reinterpret_cast<const Vector2i *>(_data._mem)->x, reinterpret_cast<const Vector2i *>(_data._mem)->y, 0.0); else return Vector3(); } + +Variant::operator Vector3i() const { + + if (type == VECTOR3I) + return *reinterpret_cast<const Vector3i *>(_data._mem); + else if (type == VECTOR3) + return *reinterpret_cast<const Vector3 *>(_data._mem); + else if (type == VECTOR2) + return Vector3i(reinterpret_cast<const Vector2 *>(_data._mem)->x, reinterpret_cast<const Vector2 *>(_data._mem)->y, 0.0); + else if (type == VECTOR2I) + return Vector3i(reinterpret_cast<const Vector2i *>(_data._mem)->x, reinterpret_cast<const Vector2i *>(_data._mem)->y, 0.0); + else + return Vector3i(); +} + Variant::operator Plane() const { if (type == PLANE) @@ -1776,9 +2094,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 +2154,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) { @@ -2131,8 +2465,8 @@ Variant::Variant(const ObjectID &p_id) { Variant::Variant(const StringName &p_string) { - type = STRING; - memnew_placement(_data._mem, String(p_string.operator String())); + type = STRING_NAME; + memnew_placement(_data._mem, StringName(p_string)); } Variant::Variant(const String &p_string) { @@ -2156,17 +2490,36 @@ Variant::Variant(const Vector3 &p_vector3) { type = VECTOR3; memnew_placement(_data._mem, Vector3(p_vector3)); } +Variant::Variant(const Vector3i &p_vector3i) { + + type = VECTOR3I; + memnew_placement(_data._mem, Vector3i(p_vector3i)); +} + Variant::Variant(const Vector2 &p_vector2) { type = VECTOR2; memnew_placement(_data._mem, Vector2(p_vector2)); } + +Variant::Variant(const Vector2i &p_vector2i) { + + type = VECTOR2I; + memnew_placement(_data._mem, Vector2i(p_vector2i)); +} + Variant::Variant(const Rect2 &p_rect2) { type = RECT2; memnew_placement(_data._mem, Rect2(p_rect2)); } +Variant::Variant(const Rect2i &p_rect2i) { + + type = RECT2I; + memnew_placement(_data._mem, Rect2i(p_rect2i)); +} + Variant::Variant(const Plane &p_plane) { type = PLANE; @@ -2243,6 +2596,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; @@ -2403,10 +2767,18 @@ void Variant::operator=(const Variant &p_variant) { *reinterpret_cast<Vector2 *>(_data._mem) = *reinterpret_cast<const Vector2 *>(p_variant._data._mem); } break; + case VECTOR2I: { + + *reinterpret_cast<Vector2i *>(_data._mem) = *reinterpret_cast<const Vector2i *>(p_variant._data._mem); + } break; case RECT2: { *reinterpret_cast<Rect2 *>(_data._mem) = *reinterpret_cast<const Rect2 *>(p_variant._data._mem); } break; + case RECT2I: { + + *reinterpret_cast<Rect2i *>(_data._mem) = *reinterpret_cast<const Rect2i *>(p_variant._data._mem); + } break; case TRANSFORM2D: { *_data._transform2d = *(p_variant._data._transform2d); @@ -2415,6 +2787,10 @@ void Variant::operator=(const Variant &p_variant) { *reinterpret_cast<Vector3 *>(_data._mem) = *reinterpret_cast<const Vector3 *>(p_variant._data._mem); } break; + case VECTOR3I: { + + *reinterpret_cast<Vector3i *>(_data._mem) = *reinterpret_cast<const Vector3i *>(p_variant._data._mem); + } break; case PLANE: { *reinterpret_cast<Plane *>(_data._mem) = *reinterpret_cast<const Plane *>(p_variant._data._mem); @@ -2469,6 +2845,19 @@ 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 STRING_NAME: { + + *reinterpret_cast<StringName *>(_data._mem) = *reinterpret_cast<const StringName *>(p_variant._data._mem); + } break; case NODE_PATH: { *reinterpret_cast<NodePath *>(_data._mem) = *reinterpret_cast<const NodePath *>(p_variant._data._mem); @@ -2564,6 +2953,11 @@ uint32_t Variant::hash() const { uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Vector2 *>(_data._mem)->x); return hash_djb2_one_float(reinterpret_cast<const Vector2 *>(_data._mem)->y, hash); } break; + case VECTOR2I: { + + uint32_t hash = hash_djb2_one_32(reinterpret_cast<const Vector2i *>(_data._mem)->x); + return hash_djb2_one_32(reinterpret_cast<const Vector2i *>(_data._mem)->y, hash); + } break; case RECT2: { uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->position.x); @@ -2571,6 +2965,13 @@ uint32_t Variant::hash() const { hash = hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->size.x, hash); return hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->size.y, hash); } break; + case RECT2I: { + + uint32_t hash = hash_djb2_one_32(reinterpret_cast<const Rect2i *>(_data._mem)->position.x); + hash = hash_djb2_one_32(reinterpret_cast<const Rect2i *>(_data._mem)->position.y, hash); + hash = hash_djb2_one_32(reinterpret_cast<const Rect2i *>(_data._mem)->size.x, hash); + return hash_djb2_one_32(reinterpret_cast<const Rect2i *>(_data._mem)->size.y, hash); + } break; case TRANSFORM2D: { uint32_t hash = 5831; @@ -2589,6 +2990,12 @@ uint32_t Variant::hash() const { hash = hash_djb2_one_float(reinterpret_cast<const Vector3 *>(_data._mem)->y, hash); return hash_djb2_one_float(reinterpret_cast<const Vector3 *>(_data._mem)->z, hash); } break; + case VECTOR3I: { + + uint32_t hash = hash_djb2_one_32(reinterpret_cast<const Vector3i *>(_data._mem)->x); + hash = hash_djb2_one_32(reinterpret_cast<const Vector3i *>(_data._mem)->y, hash); + return hash_djb2_one_32(reinterpret_cast<const Vector3i *>(_data._mem)->z, hash); + } break; case PLANE: { uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->normal.x); @@ -2667,6 +3074,10 @@ uint32_t Variant::hash() const { return hash_djb2_one_64(make_uint64_t(_get_obj().obj)); } break; + case STRING_NAME: { + + return reinterpret_cast<const StringName *>(_data._mem)->hash(); + } break; case NODE_PATH: { return reinterpret_cast<const NodePath *>(_data._mem)->hash(); @@ -2676,6 +3087,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); @@ -2852,6 +3274,11 @@ bool Variant::hash_compare(const Variant &p_variant) const { return hash_compare_vector2(*l, *r); } break; + case VECTOR2I: { + const Vector2i *l = reinterpret_cast<const Vector2i *>(_data._mem); + const Vector2i *r = reinterpret_cast<const Vector2i *>(p_variant._data._mem); + return *l == *r; + } break; case RECT2: { const Rect2 *l = reinterpret_cast<const Rect2 *>(_data._mem); @@ -2860,6 +3287,12 @@ bool Variant::hash_compare(const Variant &p_variant) const { return (hash_compare_vector2(l->position, r->position)) && (hash_compare_vector2(l->size, r->size)); } break; + case RECT2I: { + const Rect2i *l = reinterpret_cast<const Rect2i *>(_data._mem); + const Rect2i *r = reinterpret_cast<const Rect2i *>(p_variant._data._mem); + + return *l == *r; + } break; case TRANSFORM2D: { Transform2D *l = _data._transform2d; @@ -2879,6 +3312,12 @@ bool Variant::hash_compare(const Variant &p_variant) const { return hash_compare_vector3(*l, *r); } break; + case VECTOR3I: { + const Vector3i *l = reinterpret_cast<const Vector3i *>(_data._mem); + const Vector3i *r = reinterpret_cast<const Vector3i *>(p_variant._data._mem); + + return *l == *r; + } break; case PLANE: { const Plane *l = reinterpret_cast<const Plane *>(_data._mem); @@ -3054,24 +3493,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 +3535,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 +3567,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..b1be95de12 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" @@ -43,9 +44,9 @@ #include "core/math/transform.h" #include "core/math/transform_2d.h" #include "core/math/vector3.h" +#include "core/math/vector3i.h" #include "core/node_path.h" #include "core/object_id.h" - #include "core/rid.h" #include "core/ustring.h" @@ -87,8 +88,11 @@ public: // math types VECTOR2, // 5 + VECTOR2I, RECT2, + RECT2I, VECTOR3, + VECTOR3I, TRANSFORM2D, PLANE, QUAT, // 10 @@ -98,12 +102,14 @@ public: // misc types COLOR, + STRING_NAME, NODE_PATH, // 15 _RID, OBJECT, + CALLABLE, + SIGNAL, DICTIONARY, ARRAY, - // arrays PACKED_BYTE_ARRAY, // 20 PACKED_INT_ARRAY, @@ -185,8 +191,11 @@ public: operator String() const; operator StringName() const; operator Vector2() const; + operator Vector2i() const; operator Rect2() const; + operator Rect2i() const; operator Vector3() const; + operator Vector3i() const; operator Plane() const; operator ::AABB() const; operator Quat() const; @@ -202,6 +211,9 @@ public: operator Node *() const; operator Control *() const; + operator Callable() const; + operator Signal() const; + operator Dictionary() const; operator Array() const; @@ -250,8 +262,11 @@ public: Variant(const char *const p_cstring); Variant(const CharType *p_wstring); Variant(const Vector2 &p_vector2); + Variant(const Vector2i &p_vector2i); Variant(const Rect2 &p_rect2); + Variant(const Rect2i &p_rect2i); Variant(const Vector3 &p_vector3); + Variant(const Vector3i &p_vector3i); Variant(const Plane &p_plane); Variant(const ::AABB &p_aabb); Variant(const Quat &p_quat); @@ -262,6 +277,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 +350,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..0f7c1275ef 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; } @@ -383,6 +383,10 @@ struct _VariantCall { VCALL_LOCALMEM1R(Vector2, clamped); VCALL_LOCALMEM0R(Vector2, sign); + VCALL_LOCALMEM0R(Vector2i, aspect); + VCALL_LOCALMEM0R(Vector2i, sign); + VCALL_LOCALMEM0R(Vector2i, abs); + VCALL_LOCALMEM0R(Rect2, get_area); VCALL_LOCALMEM0R(Rect2, has_no_area); VCALL_LOCALMEM1R(Rect2, has_point); @@ -397,6 +401,19 @@ struct _VariantCall { VCALL_LOCALMEM4R(Rect2, grow_individual); VCALL_LOCALMEM0R(Rect2, abs); + VCALL_LOCALMEM0R(Rect2i, get_area); + VCALL_LOCALMEM0R(Rect2i, has_no_area); + VCALL_LOCALMEM1R(Rect2i, has_point); + VCALL_LOCALMEM1R(Rect2i, intersects); + VCALL_LOCALMEM1R(Rect2i, encloses); + VCALL_LOCALMEM1R(Rect2i, clip); + VCALL_LOCALMEM1R(Rect2i, merge); + VCALL_LOCALMEM1R(Rect2i, expand); + VCALL_LOCALMEM1R(Rect2i, grow); + VCALL_LOCALMEM2R(Rect2i, grow_margin); + VCALL_LOCALMEM4R(Rect2i, grow_individual); + VCALL_LOCALMEM0R(Rect2i, abs); + VCALL_LOCALMEM0R(Vector3, min_axis); VCALL_LOCALMEM0R(Vector3, max_axis); VCALL_LOCALMEM1R(Vector3, distance_to); @@ -431,6 +448,10 @@ struct _VariantCall { VCALL_LOCALMEM1R(Vector3, reflect); VCALL_LOCALMEM0R(Vector3, sign); + VCALL_LOCALMEM0R(Vector3i, min_axis); + VCALL_LOCALMEM0R(Vector3i, max_axis); + VCALL_LOCALMEM0R(Vector3i, sign); + VCALL_LOCALMEM0R(Plane, normalized); VCALL_LOCALMEM0R(Plane, center); VCALL_LOCALMEM0R(Plane, get_any_point); @@ -519,6 +540,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); @@ -892,6 +930,11 @@ struct _VariantCall { r_ret = Vector2(*p_args[0], *p_args[1]); } + static void Vector2i_init1(Variant &r_ret, const Variant **p_args) { + + r_ret = Vector2i(*p_args[0], *p_args[1]); + } + static void Rect2_init1(Variant &r_ret, const Variant **p_args) { r_ret = Rect2(*p_args[0], *p_args[1]); @@ -902,6 +945,16 @@ struct _VariantCall { r_ret = Rect2(*p_args[0], *p_args[1], *p_args[2], *p_args[3]); } + static void Rect2i_init1(Variant &r_ret, const Variant **p_args) { + + r_ret = Rect2i(*p_args[0], *p_args[1]); + } + + static void Rect2i_init2(Variant &r_ret, const Variant **p_args) { + + r_ret = Rect2i(*p_args[0], *p_args[1], *p_args[2], *p_args[3]); + } + static void Transform2D_init2(Variant &r_ret, const Variant **p_args) { Transform2D m(*p_args[0], *p_args[1]); @@ -922,6 +975,11 @@ struct _VariantCall { r_ret = Vector3(*p_args[0], *p_args[1], *p_args[2]); } + static void Vector3i_init1(Variant &r_ret, const Variant **p_args) { + + r_ret = Vector3i(*p_args[0], *p_args[1], *p_args[2]); + } + static void Plane_init1(Variant &r_ret, const Variant **p_args) { r_ret = Plane(*p_args[0], *p_args[1], *p_args[2], *p_args[3]); @@ -1010,6 +1068,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 +1146,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 +1176,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) { @@ -1162,10 +1256,14 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i // misc types case COLOR: return Color(); + case STRING_NAME: + return StringName(); // 15 case NODE_PATH: 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 @@ -1205,8 +1303,13 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i case VECTOR2: { return Vector2(*p_args[0]); } + case VECTOR2I: { + return Vector2i(*p_args[0]); + } case RECT2: return (Rect2(*p_args[0])); + case RECT2I: return (Rect2i(*p_args[0])); case VECTOR3: return (Vector3(*p_args[0])); + case VECTOR3I: return (Vector3i(*p_args[0])); case PLANE: return (Plane(*p_args[0])); case QUAT: return (p_args[0]->operator Quat()); case AABB: @@ -1217,10 +1320,14 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i // misc types case COLOR: return p_args[0]->type == Variant::STRING ? Color::html(*p_args[0]) : Color::hex(*p_args[0]); + case STRING_NAME: + return (StringName(p_args[0]->operator StringName())); // 15 case NODE_PATH: return (NodePath(p_args[0]->operator NodePath())); // 15 case _RID: return (RID(*p_args[0])); case OBJECT: return ((Object *)(p_args[0]->operator Object *())); + case CALLABLE: return ((Callable)(p_args[0]->operator Callable())); + case SIGNAL: return ((Signal)(p_args[0]->operator Signal())); case DICTIONARY: return p_args[0]->operator Dictionary(); case ARRAY: return p_args[0]->operator Array(); // 20 @@ -1249,7 +1356,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 +1368,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 +1480,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) { @@ -1642,6 +1773,10 @@ void register_variant_methods() { ADDFUNC1R(VECTOR2, VECTOR2, Vector2, clamped, REAL, "length", varray()); ADDFUNC0R(VECTOR2, VECTOR2, Vector2, sign, varray()); + ADDFUNC0R(VECTOR2I, REAL, Vector2i, aspect, varray()); + ADDFUNC0R(VECTOR2I, VECTOR2I, Vector2i, sign, varray()); + ADDFUNC0R(VECTOR2I, VECTOR2I, Vector2i, abs, varray()); + ADDFUNC0R(RECT2, REAL, Rect2, get_area, varray()); ADDFUNC0R(RECT2, BOOL, Rect2, has_no_area, varray()); ADDFUNC1R(RECT2, BOOL, Rect2, has_point, VECTOR2, "point", varray()); @@ -1656,6 +1791,19 @@ void register_variant_methods() { ADDFUNC4R(RECT2, RECT2, Rect2, grow_individual, REAL, "left", REAL, "top", REAL, "right", REAL, " bottom", varray()); ADDFUNC0R(RECT2, RECT2, Rect2, abs, varray()); + ADDFUNC0R(RECT2I, INT, Rect2i, get_area, varray()); + ADDFUNC0R(RECT2I, BOOL, Rect2i, has_no_area, varray()); + ADDFUNC1R(RECT2I, BOOL, Rect2i, has_point, VECTOR2I, "point", varray()); + ADDFUNC1R(RECT2I, BOOL, Rect2i, intersects, RECT2I, "b", varray()); + ADDFUNC1R(RECT2I, BOOL, Rect2i, encloses, RECT2I, "b", varray()); + ADDFUNC1R(RECT2I, RECT2I, Rect2i, clip, RECT2I, "b", varray()); + ADDFUNC1R(RECT2I, RECT2I, Rect2i, merge, RECT2I, "b", varray()); + ADDFUNC1R(RECT2I, RECT2I, Rect2i, expand, VECTOR2I, "to", varray()); + ADDFUNC1R(RECT2I, RECT2I, Rect2i, grow, INT, "by", varray()); + ADDFUNC2R(RECT2I, RECT2I, Rect2i, grow_margin, INT, "margin", INT, "by", varray()); + ADDFUNC4R(RECT2I, RECT2I, Rect2i, grow_individual, INT, "left", INT, "top", INT, "right", INT, " bottom", varray()); + ADDFUNC0R(RECT2I, RECT2I, Rect2i, abs, varray()); + ADDFUNC0R(VECTOR3, INT, Vector3, min_axis, varray()); ADDFUNC0R(VECTOR3, INT, Vector3, max_axis, varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray()); @@ -1690,6 +1838,10 @@ void register_variant_methods() { ADDFUNC1R(VECTOR3, VECTOR3, Vector3, reflect, VECTOR3, "n", varray()); ADDFUNC0R(VECTOR3, VECTOR3, Vector3, sign, varray()); + ADDFUNC0R(VECTOR3I, INT, Vector3i, min_axis, varray()); + ADDFUNC0R(VECTOR3I, INT, Vector3i, max_axis, varray()); + ADDFUNC0R(VECTOR3I, VECTOR3I, Vector3i, sign, varray()); + ADDFUNC0R(PLANE, PLANE, Plane, normalized, varray()); ADDFUNC0R(PLANE, VECTOR3, Plane, center, varray()); ADDFUNC0R(PLANE, VECTOR3, Plane, get_any_point, varray()); @@ -1756,6 +1908,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_NAME, 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_NAME, 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()); @@ -1944,14 +2115,19 @@ void register_variant_methods() { /* REGISTER CONSTRUCTORS */ _VariantCall::add_constructor(_VariantCall::Vector2_init1, Variant::VECTOR2, "x", Variant::REAL, "y", Variant::REAL); + _VariantCall::add_constructor(_VariantCall::Vector2i_init1, Variant::VECTOR2I, "x", Variant::INT, "y", Variant::INT); _VariantCall::add_constructor(_VariantCall::Rect2_init1, Variant::RECT2, "position", Variant::VECTOR2, "size", Variant::VECTOR2); _VariantCall::add_constructor(_VariantCall::Rect2_init2, Variant::RECT2, "x", Variant::REAL, "y", Variant::REAL, "width", Variant::REAL, "height", Variant::REAL); + _VariantCall::add_constructor(_VariantCall::Rect2i_init1, Variant::RECT2I, "position", Variant::VECTOR2, "size", Variant::VECTOR2); + _VariantCall::add_constructor(_VariantCall::Rect2i_init2, Variant::RECT2I, "x", Variant::INT, "y", Variant::INT, "width", Variant::INT, "height", Variant::INT); + _VariantCall::add_constructor(_VariantCall::Transform2D_init2, Variant::TRANSFORM2D, "rotation", Variant::REAL, "position", Variant::VECTOR2); _VariantCall::add_constructor(_VariantCall::Transform2D_init3, Variant::TRANSFORM2D, "x_axis", Variant::VECTOR2, "y_axis", Variant::VECTOR2, "origin", Variant::VECTOR2); _VariantCall::add_constructor(_VariantCall::Vector3_init1, Variant::VECTOR3, "x", Variant::REAL, "y", Variant::REAL, "z", Variant::REAL); + _VariantCall::add_constructor(_VariantCall::Vector3i_init1, Variant::VECTOR3I, "x", Variant::INT, "y", Variant::INT, "z", Variant::INT); _VariantCall::add_constructor(_VariantCall::Plane_init1, Variant::PLANE, "a", Variant::REAL, "b", Variant::REAL, "c", Variant::REAL, "d", Variant::REAL); _VariantCall::add_constructor(_VariantCall::Plane_init2, Variant::PLANE, "v1", Variant::VECTOR3, "v2", Variant::VECTOR3, "v3", Variant::VECTOR3); @@ -1972,6 +2148,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_NAME); + _VariantCall::add_constructor(_VariantCall::Signal_init2, Variant::SIGNAL, "object", Variant::OBJECT, "signal_name", Variant::STRING_NAME); + /* REGISTER CONSTANTS */ _populate_named_colors(); @@ -1993,9 +2172,25 @@ void register_variant_methods() { _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1)); _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1)); + _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3::AXIS_X); + _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3::AXIS_Y); + _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3::AXIS_Z); + + _VariantCall::add_variant_constant(Variant::VECTOR3I, "ZERO", Vector3i(0, 0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3I, "ONE", Vector3i(1, 1, 1)); + _VariantCall::add_variant_constant(Variant::VECTOR3I, "LEFT", Vector3i(-1, 0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3I, "RIGHT", Vector3i(1, 0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3I, "UP", Vector3i(0, 1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3I, "DOWN", Vector3i(0, -1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3I, "FORWARD", Vector3i(0, 0, -1)); + _VariantCall::add_variant_constant(Variant::VECTOR3I, "BACK", Vector3i(0, 0, 1)); + _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X); _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y); + _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2::AXIS_X); + _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2::AXIS_Y); + _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(Math_INF, Math_INF)); @@ -2004,6 +2199,13 @@ void register_variant_methods() { _VariantCall::add_variant_constant(Variant::VECTOR2, "UP", Vector2(0, -1)); _VariantCall::add_variant_constant(Variant::VECTOR2, "DOWN", Vector2(0, 1)); + _VariantCall::add_variant_constant(Variant::VECTOR2I, "ZERO", Vector2i(0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR2I, "ONE", Vector2i(1, 1)); + _VariantCall::add_variant_constant(Variant::VECTOR2I, "LEFT", Vector2i(-1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR2I, "RIGHT", Vector2i(1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1)); + _VariantCall::add_variant_constant(Variant::VECTOR2I, "DOWN", Vector2i(0, 1)); + _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D()); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0)); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0)); diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 566c87dac1..6af4b3887c 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -44,8 +44,11 @@ CASE_TYPE(PREFIX, OP, REAL) \ CASE_TYPE(PREFIX, OP, STRING) \ CASE_TYPE(PREFIX, OP, VECTOR2) \ + CASE_TYPE(PREFIX, OP, VECTOR2I) \ CASE_TYPE(PREFIX, OP, RECT2) \ + CASE_TYPE(PREFIX, OP, RECT2I) \ CASE_TYPE(PREFIX, OP, VECTOR3) \ + CASE_TYPE(PREFIX, OP, VECTOR3I) \ CASE_TYPE(PREFIX, OP, TRANSFORM2D) \ CASE_TYPE(PREFIX, OP, PLANE) \ CASE_TYPE(PREFIX, OP, QUAT) \ @@ -53,9 +56,12 @@ CASE_TYPE(PREFIX, OP, BASIS) \ CASE_TYPE(PREFIX, OP, TRANSFORM) \ CASE_TYPE(PREFIX, OP, COLOR) \ + CASE_TYPE(PREFIX, OP, STRING_NAME) \ 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) \ @@ -77,8 +83,11 @@ TYPE(PREFIX, OP, REAL), \ TYPE(PREFIX, OP, STRING), \ TYPE(PREFIX, OP, VECTOR2), \ + TYPE(PREFIX, OP, VECTOR2I), \ TYPE(PREFIX, OP, RECT2), \ + TYPE(PREFIX, OP, RECT2I), \ TYPE(PREFIX, OP, VECTOR3), \ + TYPE(PREFIX, OP, VECTOR3I), \ TYPE(PREFIX, OP, TRANSFORM2D), \ TYPE(PREFIX, OP, PLANE), \ TYPE(PREFIX, OP, QUAT), \ @@ -86,9 +95,12 @@ TYPE(PREFIX, OP, BASIS), \ TYPE(PREFIX, OP, TRANSFORM), \ TYPE(PREFIX, OP, COLOR), \ + TYPE(PREFIX, OP, STRING_NAME), \ 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 +113,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]; @@ -222,33 +234,47 @@ bool Variant::booleanize() const { _RETURN(p_a._data.m_type); \ }; -#define DEFAULT_OP_NUM_VEC(m_prefix, m_op_name, m_name, m_op, m_type) \ - CASE_TYPE(m_prefix, m_op_name, m_name) { \ - if (p_b.type == INT) _RETURN(p_a._data.m_type m_op p_b._data._int); \ - if (p_b.type == REAL) _RETURN(p_a._data.m_type m_op p_b._data._real); \ - if (p_b.type == VECTOR2) _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2 *>(p_b._data._mem)); \ - if (p_b.type == VECTOR3) _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3 *>(p_b._data._mem)); \ - \ - _RETURN_FAIL \ +#define DEFAULT_OP_NUM_VEC(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_b.type == INT) _RETURN(p_a._data.m_type m_op p_b._data._int); \ + if (p_b.type == REAL) _RETURN(p_a._data.m_type m_op p_b._data._real); \ + if (p_b.type == VECTOR2) _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2 *>(p_b._data._mem)); \ + if (p_b.type == VECTOR3) _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3 *>(p_b._data._mem)); \ + if (p_b.type == VECTOR2I) _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2 *>(p_b._data._mem)); \ + if (p_b.type == VECTOR3I) _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3 *>(p_b._data._mem)); \ + \ + _RETURN_FAIL \ }; -#define DEFAULT_OP_STR_REV(m_prefix, m_op_name, m_name, m_op, m_type) \ - CASE_TYPE(m_prefix, m_op_name, m_name) { \ - if (p_b.type == STRING) _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const String *>(p_a._data._mem)); \ - if (p_b.type == NODE_PATH) _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const NodePath *>(p_a._data._mem)); \ - \ - _RETURN_FAIL \ +#define DEFAULT_OP_STR_REV(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_b.type == STRING) _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const String *>(p_a._data._mem)); \ + if (p_b.type == STRING_NAME) _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const StringName *>(p_a._data._mem)); \ + if (p_b.type == NODE_PATH) _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const NodePath *>(p_a._data._mem)); \ + \ + _RETURN_FAIL \ }; -#define DEFAULT_OP_STR(m_prefix, m_op_name, m_name, m_op, m_type) \ - CASE_TYPE(m_prefix, m_op_name, m_name) { \ - if (p_b.type == STRING) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \ - if (p_b.type == NODE_PATH) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \ - \ - _RETURN_FAIL \ +#define DEFAULT_OP_STR(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_b.type == STRING) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \ + if (p_b.type == STRING_NAME) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const StringName *>(p_b._data._mem)); \ + if (p_b.type == NODE_PATH) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \ + \ + _RETURN_FAIL \ + }; + +#define DEFAULT_OP_STR_NULL(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_b.type == STRING) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \ + if (p_b.type == STRING_NAME) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const StringName *>(p_b._data._mem)); \ + if (p_b.type == NODE_PATH) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \ + if (p_b.type == NIL) _RETURN(!(p_b.type m_op NIL)); \ + \ + _RETURN_FAIL \ }; -#define DEFAULT_OP_STR_NULL(m_prefix, m_op_name, m_name, m_op, m_type) \ +#define DEFAULT_OP_STR_NULL_NP(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ if (p_b.type == STRING) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \ if (p_b.type == NODE_PATH) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \ @@ -257,6 +283,15 @@ bool Variant::booleanize() const { _RETURN_FAIL \ }; +#define DEFAULT_OP_STR_NULL_SN(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_b.type == STRING) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \ + if (p_b.type == STRING_NAME) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const StringName *>(p_b._data._mem)); \ + if (p_b.type == NIL) _RETURN(!(p_b.type m_op NIL)); \ + \ + _RETURN_FAIL \ + }; + #define DEFAULT_OP_LOCALMEM_REV(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ if (p_b.type == m_name) \ @@ -423,6 +458,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) @@ -461,16 +499,20 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_NULL(math, OP_EQUAL, REAL, ==, _real); DEFAULT_OP_STR_NULL(math, OP_EQUAL, STRING, ==, String); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR2, ==, Vector2); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR2I, ==, Vector2i); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, RECT2, ==, Rect2); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, RECT2I, ==, Rect2i); DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, TRANSFORM2D, ==, _transform2d); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR3, ==, Vector3); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR3I, ==, Vector3i); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, PLANE, ==, Plane); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, QUAT, ==, Quat); DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, AABB, ==, _aabb); DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, BASIS, ==, _basis); DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, TRANSFORM, ==, _transform); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, COLOR, ==, Color); - DEFAULT_OP_STR_NULL(math, OP_EQUAL, NODE_PATH, ==, NodePath); + DEFAULT_OP_STR_NULL_SN(math, OP_EQUAL, STRING_NAME, ==, StringName); + DEFAULT_OP_STR_NULL_NP(math, OP_EQUAL, NODE_PATH, ==, NodePath); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, _RID, ==, RID); DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_BYTE_ARRAY, uint8_t); @@ -511,6 +553,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) @@ -551,16 +596,20 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_NULL(math, OP_NOT_EQUAL, REAL, !=, _real); DEFAULT_OP_STR_NULL(math, OP_NOT_EQUAL, STRING, !=, String); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR2, !=, Vector2); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR2I, !=, Vector2i); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, RECT2, !=, Rect2); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, RECT2I, !=, Rect2i); DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, TRANSFORM2D, !=, _transform2d); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR3, !=, Vector3); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR3I, !=, Vector3i); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, PLANE, !=, Plane); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, QUAT, !=, Quat); DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, AABB, !=, _aabb); DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, BASIS, !=, _basis); DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, TRANSFORM, !=, _transform); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, COLOR, !=, Color); - DEFAULT_OP_STR_NULL(math, OP_NOT_EQUAL, NODE_PATH, !=, NodePath); + DEFAULT_OP_STR_NULL_SN(math, OP_NOT_EQUAL, STRING_NAME, !=, StringName); + DEFAULT_OP_STR_NULL_NP(math, OP_NOT_EQUAL, NODE_PATH, !=, NodePath); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, _RID, !=, RID); DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_BYTE_ARRAY, uint8_t); @@ -592,6 +641,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; @@ -615,7 +667,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_LESS, REAL, <, _real); DEFAULT_OP_STR(math, OP_LESS, STRING, <, String); DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR2, <, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR2I, <, Vector2i); DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR3, <, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR3I, <, Vector3i); DEFAULT_OP_LOCALMEM(math, OP_LESS, _RID, <, RID); DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_BYTE_ARRAY, uint8_t); DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_INT_ARRAY, int); @@ -627,6 +681,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_LESS, NIL) CASE_TYPE(math, OP_LESS, RECT2) + CASE_TYPE(math, OP_LESS, RECT2I) CASE_TYPE(math, OP_LESS, TRANSFORM2D) CASE_TYPE(math, OP_LESS, PLANE) CASE_TYPE(math, OP_LESS, QUAT) @@ -634,6 +689,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_LESS, BASIS) CASE_TYPE(math, OP_LESS, TRANSFORM) CASE_TYPE(math, OP_LESS, COLOR) + CASE_TYPE(math, OP_LESS, STRING_NAME) CASE_TYPE(math, OP_LESS, NODE_PATH) CASE_TYPE(math, OP_LESS, DICTIONARY) _RETURN_FAIL; @@ -650,12 +706,15 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_LESS_EQUAL, REAL, <=, _real); DEFAULT_OP_STR(math, OP_LESS_EQUAL, STRING, <=, String); DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR2, <=, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR2I, <=, Vector2i); DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR3, <=, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR3I, <=, Vector3i); DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, _RID, <=, RID); CASE_TYPE(math, OP_LESS_EQUAL, NIL) CASE_TYPE(math, OP_LESS_EQUAL, BOOL) CASE_TYPE(math, OP_LESS_EQUAL, RECT2) + CASE_TYPE(math, OP_LESS_EQUAL, RECT2I) CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM2D) CASE_TYPE(math, OP_LESS_EQUAL, PLANE) CASE_TYPE(math, OP_LESS_EQUAL, QUAT) @@ -663,7 +722,11 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_LESS_EQUAL, BASIS) CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM) CASE_TYPE(math, OP_LESS_EQUAL, COLOR) + CASE_TYPE(math, OP_LESS_EQUAL, STRING_NAME) 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); @@ -719,7 +782,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_GREATER, REAL, >, _real); DEFAULT_OP_STR_REV(math, OP_GREATER, STRING, <, String); DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR2, <, Vector2); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR2I, <, Vector2i); DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR3, <, Vector3); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR3I, <, Vector3i); DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, _RID, <, RID); DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_BYTE_ARRAY, uint8_t); DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_INT_ARRAY, int); @@ -731,6 +796,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_GREATER, NIL) CASE_TYPE(math, OP_GREATER, RECT2) + CASE_TYPE(math, OP_GREATER, RECT2I) CASE_TYPE(math, OP_GREATER, TRANSFORM2D) CASE_TYPE(math, OP_GREATER, PLANE) CASE_TYPE(math, OP_GREATER, QUAT) @@ -738,8 +804,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_GREATER, BASIS) CASE_TYPE(math, OP_GREATER, TRANSFORM) CASE_TYPE(math, OP_GREATER, COLOR) + CASE_TYPE(math, OP_GREATER, STRING_NAME) 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; } @@ -754,12 +824,15 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_GREATER_EQUAL, REAL, >=, _real); DEFAULT_OP_STR_REV(math, OP_GREATER_EQUAL, STRING, <=, String); DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR2, <=, Vector2); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR2I, <=, Vector2i); DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR3, <=, Vector3); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR3I, <=, Vector3i); DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, _RID, <=, RID); CASE_TYPE(math, OP_GREATER_EQUAL, NIL) CASE_TYPE(math, OP_GREATER_EQUAL, BOOL) CASE_TYPE(math, OP_GREATER_EQUAL, RECT2) + CASE_TYPE(math, OP_GREATER_EQUAL, RECT2I) CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM2D) CASE_TYPE(math, OP_GREATER_EQUAL, PLANE) CASE_TYPE(math, OP_GREATER_EQUAL, QUAT) @@ -767,7 +840,11 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_GREATER_EQUAL, BASIS) CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM) CASE_TYPE(math, OP_GREATER_EQUAL, COLOR) + CASE_TYPE(math, OP_GREATER_EQUAL, STRING_NAME) 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); @@ -802,7 +879,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_ADD, REAL, +, _real); DEFAULT_OP_STR(math, OP_ADD, STRING, +, String); DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR2, +, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR2I, +, Vector2i); DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR3, +, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR3I, +, Vector3i); DEFAULT_OP_LOCALMEM(math, OP_ADD, QUAT, +, Quat); DEFAULT_OP_LOCALMEM(math, OP_ADD, COLOR, +, Color); @@ -817,14 +896,19 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_ADD, NIL) CASE_TYPE(math, OP_ADD, BOOL) CASE_TYPE(math, OP_ADD, RECT2) + CASE_TYPE(math, OP_ADD, RECT2I) CASE_TYPE(math, OP_ADD, TRANSFORM2D) CASE_TYPE(math, OP_ADD, PLANE) CASE_TYPE(math, OP_ADD, AABB) CASE_TYPE(math, OP_ADD, BASIS) CASE_TYPE(math, OP_ADD, TRANSFORM) + CASE_TYPE(math, OP_ADD, STRING_NAME) 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; } @@ -833,7 +917,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_SUBTRACT, INT, -, _int); DEFAULT_OP_NUM(math, OP_SUBTRACT, REAL, -, _real); DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR2, -, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR2I, -, Vector2i); DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR3, -, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR3I, -, Vector3i); DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, QUAT, -, Quat); DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, COLOR, -, Color); @@ -841,14 +927,19 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_SUBTRACT, BOOL) CASE_TYPE(math, OP_SUBTRACT, STRING) CASE_TYPE(math, OP_SUBTRACT, RECT2) + CASE_TYPE(math, OP_SUBTRACT, RECT2I) CASE_TYPE(math, OP_SUBTRACT, TRANSFORM2D) CASE_TYPE(math, OP_SUBTRACT, PLANE) CASE_TYPE(math, OP_SUBTRACT, AABB) CASE_TYPE(math, OP_SUBTRACT, BASIS) CASE_TYPE(math, OP_SUBTRACT, TRANSFORM) + CASE_TYPE(math, OP_SUBTRACT, STRING_NAME) 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); @@ -916,18 +1007,25 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, INT, *, _int); DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, REAL, *, _real); DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR2, *, Vector2); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR2I, *, Vector2i); DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3, *, Vector3); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3I, *, Vector3i); DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, COLOR, *, Color); CASE_TYPE(math, OP_MULTIPLY, NIL) CASE_TYPE(math, OP_MULTIPLY, BOOL) CASE_TYPE(math, OP_MULTIPLY, STRING) CASE_TYPE(math, OP_MULTIPLY, RECT2) + CASE_TYPE(math, OP_MULTIPLY, RECT2I) CASE_TYPE(math, OP_MULTIPLY, PLANE) CASE_TYPE(math, OP_MULTIPLY, AABB) + CASE_TYPE(math, OP_MULTIPLY, STRING_NAME) 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); @@ -956,21 +1054,28 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_DIV(math, OP_DIVIDE, INT, _int); DEFAULT_OP_NUM_DIV(math, OP_DIVIDE, REAL, _real); DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR2, /, Vector2); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR2I, /, Vector2i); DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR3, /, Vector3); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR3I, /, Vector3i); DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, COLOR, /, Color); CASE_TYPE(math, OP_DIVIDE, NIL) CASE_TYPE(math, OP_DIVIDE, BOOL) CASE_TYPE(math, OP_DIVIDE, STRING) CASE_TYPE(math, OP_DIVIDE, RECT2) + CASE_TYPE(math, OP_DIVIDE, RECT2I) CASE_TYPE(math, OP_DIVIDE, TRANSFORM2D) CASE_TYPE(math, OP_DIVIDE, PLANE) CASE_TYPE(math, OP_DIVIDE, AABB) CASE_TYPE(math, OP_DIVIDE, BASIS) CASE_TYPE(math, OP_DIVIDE, TRANSFORM) + CASE_TYPE(math, OP_DIVIDE, STRING_NAME) 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); @@ -987,22 +1092,29 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_POS(math, OP_POSITIVE, INT, _int); DEFAULT_OP_NUM_POS(math, OP_POSITIVE, REAL, _real); DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR3, Vector3); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR3I, Vector3i); DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, PLANE, Plane); DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, QUAT, Quat); DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR2, Vector2); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR2I, Vector2i); CASE_TYPE(math, OP_POSITIVE, NIL) CASE_TYPE(math, OP_POSITIVE, BOOL) CASE_TYPE(math, OP_POSITIVE, STRING) CASE_TYPE(math, OP_POSITIVE, RECT2) + CASE_TYPE(math, OP_POSITIVE, RECT2I) CASE_TYPE(math, OP_POSITIVE, TRANSFORM2D) CASE_TYPE(math, OP_POSITIVE, AABB) CASE_TYPE(math, OP_POSITIVE, BASIS) CASE_TYPE(math, OP_POSITIVE, TRANSFORM) CASE_TYPE(math, OP_POSITIVE, COLOR) + CASE_TYPE(math, OP_POSITIVE, STRING_NAME) 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) @@ -1020,7 +1132,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_NEG(math, OP_NEGATE, REAL, _real); DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR2, Vector2); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR2I, Vector2i); DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR3, Vector3); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR3I, Vector3i); DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, PLANE, Plane); DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, QUAT, Quat); DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, COLOR, Color); @@ -1029,13 +1143,18 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_NEGATE, BOOL) CASE_TYPE(math, OP_NEGATE, STRING) CASE_TYPE(math, OP_NEGATE, RECT2) + CASE_TYPE(math, OP_NEGATE, RECT2I) CASE_TYPE(math, OP_NEGATE, TRANSFORM2D) CASE_TYPE(math, OP_NEGATE, AABB) CASE_TYPE(math, OP_NEGATE, BASIS) CASE_TYPE(math, OP_NEGATE, TRANSFORM) + CASE_TYPE(math, OP_NEGATE, STRING_NAME) 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) @@ -1084,8 +1203,11 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_MODULE, BOOL) CASE_TYPE(math, OP_MODULE, REAL) CASE_TYPE(math, OP_MODULE, VECTOR2) + CASE_TYPE(math, OP_MODULE, VECTOR2I) CASE_TYPE(math, OP_MODULE, RECT2) + CASE_TYPE(math, OP_MODULE, RECT2I) CASE_TYPE(math, OP_MODULE, VECTOR3) + CASE_TYPE(math, OP_MODULE, VECTOR3I) CASE_TYPE(math, OP_MODULE, TRANSFORM2D) CASE_TYPE(math, OP_MODULE, PLANE) CASE_TYPE(math, OP_MODULE, QUAT) @@ -1093,9 +1215,13 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_MODULE, BASIS) CASE_TYPE(math, OP_MODULE, TRANSFORM) CASE_TYPE(math, OP_MODULE, COLOR) + CASE_TYPE(math, OP_MODULE, STRING_NAME) 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) @@ -1249,6 +1375,28 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool } } break; + case VECTOR2I: { + if (p_value.type == Variant::INT) { + Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } + } + + } break; case RECT2: { if (p_value.type == Variant::VECTOR2) { @@ -1266,6 +1414,23 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool } } } break; + case RECT2I: { + + if (p_value.type == Variant::VECTOR2I) { + Rect2i *v = reinterpret_cast<Rect2i *>(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast<const Vector2i *>(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast<const Vector2i *>(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast<const Vector2i *>(p_value._data._mem) - v->position; + valid = true; + } + } + } break; case TRANSFORM2D: { if (p_value.type == Variant::VECTOR2) { @@ -1312,6 +1477,35 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool } } break; + case VECTOR3I: { + + if (p_value.type == Variant::INT) { + Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } + } + + } break; case PLANE: { if (p_value.type == Variant::INT) { @@ -1548,6 +1742,15 @@ Variant Variant::get_named(const StringName &p_index, bool *r_valid) const { } } break; + case VECTOR2I: { + const Vector2i *v = reinterpret_cast<const Vector2i *>(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } + + } break; case RECT2: { const Rect2 *v = reinterpret_cast<const Rect2 *>(_data._mem); @@ -1560,6 +1763,18 @@ Variant Variant::get_named(const StringName &p_index, bool *r_valid) const { return v->size + v->position; } } break; + case RECT2I: { + + const Rect2i *v = reinterpret_cast<const Rect2i *>(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + return v->size + v->position; + } + } break; case TRANSFORM2D: { const Transform2D *v = _data._transform2d; @@ -1584,6 +1799,18 @@ Variant Variant::get_named(const StringName &p_index, bool *r_valid) const { } } break; + case VECTOR3I: { + + const Vector3i *v = reinterpret_cast<const Vector3i *>(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } + + } break; case PLANE: { const Plane *v = reinterpret_cast<const Plane *>(_data._mem); @@ -1814,6 +2041,41 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) } } break; // 5 + case VECTOR2I: { + + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) + return; + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + // scalar index + int idx = p_index; + + if (idx < 0) + idx += 2; + if (idx >= 0 && idx < 2) { + + Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast<const String *>(p_index._data._mem); + Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } + } + + } break; // 5 case RECT2: { if (p_value.type != Variant::VECTOR2) @@ -1839,6 +2101,31 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) } } } break; + case RECT2I: { + + if (p_value.type != Variant::VECTOR2I) + return; + + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast<const String *>(p_index._data._mem); + Rect2i *v = reinterpret_cast<Rect2i *>(_data._mem); + if (*str == "position") { + valid = true; + v->position = p_value; + return; + } else if (*str == "size") { + valid = true; + v->size = p_value; + return; + } else if (*str == "end") { + valid = true; + v->size = Vector2i(p_value) - v->position; + return; + } + } + } break; case TRANSFORM2D: { if (p_value.type != Variant::VECTOR2) @@ -1916,6 +2203,44 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) } } break; + case VECTOR3I: { + + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) + return; + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) + idx += 3; + if (idx >= 0 && idx < 3) { + + Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + + //scalar name + const String *str = reinterpret_cast<const String *>(p_index._data._mem); + Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } + } + + } break; case PLANE: { if (p_index.get_type() == Variant::STRING) { @@ -2161,6 +2486,8 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) } } break; + case STRING_NAME: { + } break; // 15 case NODE_PATH: { } break; // 15 case _RID: { @@ -2180,7 +2507,7 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) } #endif - if (p_index.get_type() != Variant::STRING) { + if (p_index.get_type() != Variant::STRING_NAME && p_index.get_type() != Variant::STRING) { obj->setvar(p_index, p_value, r_valid); return; } @@ -2275,6 +2602,34 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { } } break; // 5 + case VECTOR2I: { + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + // scalar index + int idx = p_index; + if (idx < 0) + idx += 2; + if (idx >= 0 && idx < 2) { + + const Vector2i *v = reinterpret_cast<const Vector2i *>(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast<const String *>(p_index._data._mem); + const Vector2i *v = reinterpret_cast<const Vector2i *>(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } + } + + } break; // 5 case RECT2: { if (p_index.get_type() == Variant::STRING) { @@ -2294,6 +2649,25 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { } } } break; + case RECT2I: { + + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast<const String *>(p_index._data._mem); + const Rect2i *v = reinterpret_cast<const Rect2i *>(_data._mem); + if (*str == "position") { + valid = true; + return v->position; + } else if (*str == "size") { + valid = true; + return v->size; + } else if (*str == "end") { + valid = true; + return v->size + v->position; + } + } + } break; case VECTOR3: { if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { @@ -2325,6 +2699,37 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { } } break; + case VECTOR3I: { + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) + idx += 3; + if (idx >= 0 && idx < 3) { + + const Vector3i *v = reinterpret_cast<const Vector3i *>(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + + //scalar name + const String *str = reinterpret_cast<const String *>(p_index._data._mem); + const Vector3i *v = reinterpret_cast<const Vector3i *>(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } + } + + } break; case TRANSFORM2D: { if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { @@ -2535,6 +2940,8 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { } } break; + case STRING_NAME: { + } break; // 15 case NODE_PATH: { } break; // 15 case _RID: { @@ -2799,6 +3206,12 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::REAL, "y")); } break; // 5 + case VECTOR2I: { + + p_list->push_back(PropertyInfo(Variant::INT, "x")); + p_list->push_back(PropertyInfo(Variant::INT, "y")); + + } break; // 5 case RECT2: { p_list->push_back(PropertyInfo(Variant::VECTOR2, "position")); @@ -2806,6 +3219,13 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::VECTOR2, "end")); } break; + case RECT2I: { + + p_list->push_back(PropertyInfo(Variant::VECTOR2I, "position")); + p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size")); + p_list->push_back(PropertyInfo(Variant::VECTOR2I, "end")); + + } break; case VECTOR3: { p_list->push_back(PropertyInfo(Variant::REAL, "x")); @@ -2813,6 +3233,13 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::REAL, "z")); } break; + case VECTOR3I: { + + p_list->push_back(PropertyInfo(Variant::INT, "x")); + p_list->push_back(PropertyInfo(Variant::INT, "y")); + p_list->push_back(PropertyInfo(Variant::INT, "z")); + + } break; case TRANSFORM2D: { p_list->push_back(PropertyInfo(Variant::VECTOR2, "x")); @@ -2869,6 +3296,8 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, "a8")); } break; + case STRING_NAME: { + } break; // 15 case NODE_PATH: { } break; // 15 case _RID: { @@ -2968,15 +3397,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 +3567,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 +3726,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(); } @@ -3477,16 +3906,50 @@ void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) + *reinterpret_cast<const Vector2 *>(b._data._mem) * c; } return; + case VECTOR2I: { + int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x; + int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x; + int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y; + int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y; + r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5)); + } + return; case RECT2: { const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem); const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem); r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c); } return; + case RECT2I: { + const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem); + const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem); + + int32_t vax = ra->position.x; + int32_t vay = ra->position.y; + int32_t vbx = ra->size.x; + int32_t vby = ra->size.y; + int32_t vcx = rb->position.x; + int32_t vcy = rb->position.y; + int32_t vdx = rb->size.x; + int32_t vdy = rb->size.y; + + r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5)); + } + return; case VECTOR3: { r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) + *reinterpret_cast<const Vector3 *>(b._data._mem) * c; } return; + case VECTOR3I: { + int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x; + int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x; + int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y; + int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y; + int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z; + int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z; + r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5)); + } + return; case AABB: { const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem); const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem); @@ -3603,14 +4066,51 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & r_dst = reinterpret_cast<const Vector2 *>(a._data._mem)->linear_interpolate(*reinterpret_cast<const Vector2 *>(b._data._mem), c); } return; + case VECTOR2I: { + int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x; + int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x; + int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y; + int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y; + r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5)); + } + return; + case RECT2: { r_dst = Rect2(reinterpret_cast<const Rect2 *>(a._data._mem)->position.linear_interpolate(reinterpret_cast<const Rect2 *>(b._data._mem)->position, c), reinterpret_cast<const Rect2 *>(a._data._mem)->size.linear_interpolate(reinterpret_cast<const Rect2 *>(b._data._mem)->size, c)); } return; + case RECT2I: { + const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem); + const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem); + + int32_t vax = ra->position.x; + int32_t vay = ra->position.y; + int32_t vbx = ra->size.x; + int32_t vby = ra->size.y; + int32_t vcx = rb->position.x; + int32_t vcy = rb->position.y; + int32_t vdx = rb->size.x; + int32_t vdy = rb->size.y; + + r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5)); + } + return; + case VECTOR3: { r_dst = reinterpret_cast<const Vector3 *>(a._data._mem)->linear_interpolate(*reinterpret_cast<const Vector3 *>(b._data._mem), c); } return; + case VECTOR3I: { + int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x; + int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x; + int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y; + int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y; + int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z; + int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z; + r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5)); + } + return; + case TRANSFORM2D: { r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c); } @@ -3639,6 +4139,10 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & r_dst = reinterpret_cast<const Color *>(a._data._mem)->linear_interpolate(*reinterpret_cast<const Color *>(b._data._mem), c); } return; + case STRING_NAME: { + r_dst = a; + } + return; case NODE_PATH: { r_dst = a; } diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index f036e00ed5..44bf90674b 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -81,6 +81,7 @@ const char *VariantParser::tk_name[TK_MAX] = { "')'", "identifier", "string", + "string_name", "number", "color", "':'", @@ -93,6 +94,8 @@ const char *VariantParser::tk_name[TK_MAX] = { Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, String &r_err_str) { + bool string_name = false; + while (true) { CharType cchar; @@ -204,6 +207,17 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri r_token.type = TK_COLOR; return OK; }; + case '@': { + cchar = p_stream->get_char(); + if (cchar != '"') { + r_err_str = "Expected '\"' after '@'"; + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } + + string_name = true; + [[fallthrough]]; + } case '"': { String str; @@ -285,8 +299,14 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri if (p_stream->is_utf8()) { str.parse_utf8(str.ascii(true).get_data()); } - r_token.type = TK_STRING; - r_token.value = str; + if (string_name) { + r_token.type = TK_STRING_NAME; + r_token.value = StringName(str); + string_name = false; //reset + } else { + r_token.type = TK_STRING; + r_token.value = str; + } return OK; } break; @@ -525,6 +545,19 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, value = Vector2(args[0], args[1]); return OK; + } else if (id == "Vector2i") { + + Vector<int32_t> args; + Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str); + if (err) + return err; + + if (args.size() != 2) { + r_err_str = "Expected 2 arguments for constructor"; + } + + value = Vector2i(args[0], args[1]); + return OK; } else if (id == "Rect2") { Vector<float> args; @@ -538,6 +571,19 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, value = Rect2(args[0], args[1], args[2], args[3]); return OK; + } else if (id == "Rect2i") { + + Vector<int32_t> args; + Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str); + if (err) + return err; + + if (args.size() != 4) { + r_err_str = "Expected 4 arguments for constructor"; + } + + value = Rect2i(args[0], args[1], args[2], args[3]); + return OK; } else if (id == "Vector3") { Vector<float> args; @@ -551,6 +597,19 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, value = Vector3(args[0], args[1], args[2]); return OK; + } else if (id == "Vector3i") { + + Vector<int32_t> args; + Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str); + if (err) + return err; + + if (args.size() != 3) { + r_err_str = "Expected 3 arguments for constructor"; + } + + value = Vector3i(args[0], args[1], args[2]); + return OK; } else if (id == "Transform2D" || id == "Matrix32") { //compatibility Vector<float> args; @@ -1411,17 +1470,33 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str Vector2 v = p_variant; p_store_string_func(p_store_string_ud, "Vector2( " + rtosfix(v.x) + ", " + rtosfix(v.y) + " )"); } break; + case Variant::VECTOR2I: { + + Vector2i v = p_variant; + p_store_string_func(p_store_string_ud, "Vector2i( " + itos(v.x) + ", " + itos(v.y) + " )"); + } break; case Variant::RECT2: { Rect2 aabb = p_variant; p_store_string_func(p_store_string_ud, "Rect2( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + " )"); } break; + case Variant::RECT2I: { + + Rect2i aabb = p_variant; + p_store_string_func(p_store_string_ud, "Rect2i( " + itos(aabb.position.x) + ", " + itos(aabb.position.y) + ", " + itos(aabb.size.x) + ", " + itos(aabb.size.y) + " )"); + + } break; case Variant::VECTOR3: { Vector3 v = p_variant; p_store_string_func(p_store_string_ud, "Vector3( " + rtosfix(v.x) + ", " + rtosfix(v.y) + ", " + rtosfix(v.z) + " )"); } break; + case Variant::VECTOR3I: { + + Vector3i v = p_variant; + p_store_string_func(p_store_string_ud, "Vector3i( " + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + " )"); + } break; case Variant::PLANE: { Plane p = p_variant; @@ -1498,6 +1573,14 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, "Color( " + rtosfix(c.r) + ", " + rtosfix(c.g) + ", " + rtosfix(c.b) + ", " + rtosfix(c.a) + " )"); } break; + case Variant::STRING_NAME: { + + String str = p_variant; + + str = "@\"" + str.c_escape() + "\""; + p_store_string_func(p_store_string_ud, str); + + } break; case Variant::NODE_PATH: { String str = p_variant; diff --git a/core/variant_parser.h b/core/variant_parser.h index 89db3ada0d..ad0a4d6682 100644 --- a/core/variant_parser.h +++ b/core/variant_parser.h @@ -92,6 +92,7 @@ public: TK_PARENTHESIS_CLOSE, TK_IDENTIFIER, TK_STRING, + TK_STRING_NAME, TK_NUMBER, TK_COLOR, TK_COLON, |