diff options
Diffstat (limited to 'core/variant')
29 files changed, 1216 insertions, 649 deletions
diff --git a/core/variant/array.cpp b/core/variant/array.cpp index 8373cbd4e8..afc4acadf9 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,6 +34,7 @@ #include "core/object/class_db.h" #include "core/object/script_language.h" #include "core/templates/hashfuncs.h" +#include "core/templates/search_array.h" #include "core/templates/vector.h" #include "core/variant/callable.h" #include "core/variant/variant.h" @@ -96,11 +97,38 @@ void Array::clear() { } bool Array::operator==(const Array &p_array) const { - return _p == p_array._p; + return recursive_equal(p_array, 0); } bool Array::operator!=(const Array &p_array) const { - return !operator==(p_array); + return !recursive_equal(p_array, 0); +} + +bool Array::recursive_equal(const Array &p_array, int recursion_count) const { + // Cheap checks + if (_p == p_array._p) { + return true; + } + const Vector<Variant> &a1 = _p->array; + const Vector<Variant> &a2 = p_array._p->array; + const int size = a1.size(); + if (size != a2.size()) { + return false; + } + + // Heavy O(n) check + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return true; + } + recursion_count++; + for (int i = 0; i < size; i++) { + if (!a1[i].hash_compare(a2[i], recursion_count)) { + return false; + } + } + + return true; } bool Array::operator<(const Array &p_array) const { @@ -131,10 +159,20 @@ bool Array::operator>=(const Array &p_array) const { } uint32_t Array::hash() const { - uint32_t h = hash_djb2_one_32(0); + return recursive_hash(0); +} + +uint32_t Array::recursive_hash(int recursion_count) const { + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return 0; + } + uint32_t h = hash_djb2_one_32(Variant::ARRAY); + + recursion_count++; for (int i = 0; i < _p->array.size(); i++) { - h = hash_djb2_one_32(_p->array[i].hash(), h); + h = hash_djb2_one_32(_p->array[i].recursive_hash(recursion_count), h); } return h; } @@ -284,8 +322,8 @@ bool Array::has(const Variant &p_value) const { return _p->array.find(p_value, 0) != -1; } -void Array::remove(int p_pos) { - _p->array.remove(p_pos); +void Array::remove_at(int p_pos) { + _p->array.remove_at(p_pos); } void Array::set(int p_idx, const Variant &p_value) { @@ -299,66 +337,62 @@ const Variant &Array::get(int p_idx) const { } Array Array::duplicate(bool p_deep) const { + return recursive_duplicate(p_deep, 0); +} + +Array Array::recursive_duplicate(bool p_deep, int recursion_count) const { Array new_arr; + + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return new_arr; + } + int element_count = size(); new_arr.resize(element_count); new_arr._p->typed = _p->typed; - for (int i = 0; i < element_count; i++) { - new_arr[i] = p_deep ? get(i).duplicate(p_deep) : get(i); + if (p_deep) { + recursion_count++; + for (int i = 0; i < element_count; i++) { + new_arr[i] = get(i).recursive_duplicate(true, recursion_count); + } + } else { + for (int i = 0; i < element_count; i++) { + new_arr[i] = get(i); + } } return new_arr; } -int Array::_clamp_slice_index(int p_index) const { - int arr_size = size(); - int fixed_index = CLAMP(p_index, -arr_size, arr_size - 1); - if (fixed_index < 0) { - fixed_index = arr_size + fixed_index; - } - return fixed_index; -} - -Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const { // like python, but inclusive on upper bound +Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const { + Array result; - Array new_arr; + ERR_FAIL_COND_V_MSG(p_step == 0, result, "Slice step cannot be zero."); - ERR_FAIL_COND_V_MSG(p_step == 0, new_arr, "Array slice step size cannot be zero."); + const int s = size(); - if (is_empty()) { // Don't try to slice empty arrays. - return new_arr; + int begin = CLAMP(p_begin, -s, s); + if (begin < 0) { + begin += s; } - if (p_step > 0) { - if (p_begin >= size() || p_end < -size()) { - return new_arr; - } - } else { // p_step < 0 - if (p_begin < -size() || p_end >= size()) { - return new_arr; - } + int end = CLAMP(p_end, -s, s); + if (end < 0) { + end += s; } - int begin = _clamp_slice_index(p_begin); - int end = _clamp_slice_index(p_end); + ERR_FAIL_COND_V_MSG(p_step > 0 && begin > end, result, "Slice is positive, but bounds is decreasing."); + ERR_FAIL_COND_V_MSG(p_step < 0 && begin < end, result, "Slice is negative, but bounds is increasing."); - int new_arr_size = MAX(((end - begin + p_step) / p_step), 0); - new_arr.resize(new_arr_size); + int result_size = (end - begin) / p_step; + result.resize(result_size); - if (p_step > 0) { - int dest_idx = 0; - for (int idx = begin; idx <= end; idx += p_step) { - ERR_FAIL_COND_V_MSG(dest_idx < 0 || dest_idx >= new_arr_size, Array(), "Bug in Array slice()"); - new_arr[dest_idx++] = p_deep ? get(idx).duplicate(p_deep) : get(idx); - } - } else { // p_step < 0 - int dest_idx = 0; - for (int idx = begin; idx >= end; idx += p_step) { - ERR_FAIL_COND_V_MSG(dest_idx < 0 || dest_idx >= new_arr_size, Array(), "Bug in Array slice()"); - new_arr[dest_idx++] = p_deep ? get(idx).duplicate(p_deep) : get(idx); - } + for (int src_idx = begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) { + result[dest_idx] = p_deep ? get(src_idx).duplicate(true) : get(src_idx); + src_idx += p_step; } - return new_arr; + return result; } Array Array::filter(const Callable &p_callable) const { @@ -450,24 +484,8 @@ void Array::sort() { _p->array.sort_custom<_ArrayVariantSort>(); } -struct _ArrayVariantSortCustom { - Callable func; - - _FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const { - const Variant *args[2] = { &p_l, &p_r }; - Callable::CallError err; - Variant res; - func.call(args, 2, res, err); - ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, false, - "Error calling sorting method: " + Variant::get_callable_error_text(func, args, 1, err)); - return res; - } -}; - -void Array::sort_custom(Callable p_callable) { - SortArray<Variant, _ArrayVariantSortCustom, true> avs; - avs.compare.func = p_callable; - avs.sort(_p->array.ptrw(), _p->array.size()); +void Array::sort_custom(const Callable &p_callable) { + _p->array.sort_custom<CallableComparator, true>(p_callable); } void Array::shuffle() { @@ -484,44 +502,16 @@ void Array::shuffle() { } } -template <typename Less> -_FORCE_INLINE_ int bisect(const Vector<Variant> &p_array, const Variant &p_value, bool p_before, const Less &p_less) { - int lo = 0; - int hi = p_array.size(); - if (p_before) { - while (lo < hi) { - const int mid = (lo + hi) / 2; - if (p_less(p_array.get(mid), p_value)) { - lo = mid + 1; - } else { - hi = mid; - } - } - } else { - while (lo < hi) { - const int mid = (lo + hi) / 2; - if (p_less(p_value, p_array.get(mid))) { - hi = mid; - } else { - lo = mid + 1; - } - } - } - return lo; -} - int Array::bsearch(const Variant &p_value, bool p_before) { ERR_FAIL_COND_V(!_p->typed.validate(p_value, "binary search"), -1); - return bisect(_p->array, p_value, p_before, _ArrayVariantSort()); + SearchArray<Variant, _ArrayVariantSort> avs; + return avs.bisect(_p->array.ptrw(), _p->array.size(), p_value, p_before); } -int Array::bsearch_custom(const Variant &p_value, Callable p_callable, bool p_before) { +int Array::bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before) { ERR_FAIL_COND_V(!_p->typed.validate(p_value, "custom binary search"), -1); - _ArrayVariantSortCustom less; - less.func = p_callable; - - return bisect(_p->array, p_value, p_before, less); + return _p->array.bsearch_custom<CallableComparator>(p_value, p_before, p_callable); } void Array::reverse() { @@ -546,7 +536,7 @@ Variant Array::pop_back() { Variant Array::pop_front() { if (!_p->array.is_empty()) { const Variant ret = _p->array.get(0); - _p->array.remove(0); + _p->array.remove_at(0); return ret; } return Variant(); @@ -573,7 +563,7 @@ Variant Array::pop_at(int p_pos) { _p->array.size())); const Variant ret = _p->array.get(p_pos); - _p->array.remove(p_pos); + _p->array.remove_at(p_pos); return ret; } @@ -622,7 +612,7 @@ Variant Array::max() const { } const void *Array::id() const { - return _p->array.ptr(); + return _p; } Array::Array(const Array &p_from, uint32_t p_type, const StringName &p_class_name, const Variant &p_script) { diff --git a/core/variant/array.h b/core/variant/array.h index 4a1b25c4a9..ab5f7cd50f 100644 --- a/core/variant/array.h +++ b/core/variant/array.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,6 +33,8 @@ #include "core/typedefs.h" +#include <climits> + class Variant; class ArrayPrivate; class Object; @@ -44,8 +46,6 @@ class Array { void _ref(const Array &p_from) const; void _unref() const; - inline int _clamp_slice_index(int p_index) const; - protected: Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script); bool _assign(const Array &p_array); @@ -63,8 +63,10 @@ public: bool operator==(const Array &p_array) const; bool operator!=(const Array &p_array) const; + bool recursive_equal(const Array &p_array, int recursion_count) const; uint32_t hash() const; + uint32_t recursive_hash(int recursion_count) const; void operator=(const Array &p_array); void push_back(const Variant &p_value); @@ -73,17 +75,17 @@ public: Error resize(int p_new_size); Error insert(int p_pos, const Variant &p_value); - void remove(int p_pos); + void remove_at(int p_pos); void fill(const Variant &p_value); Variant front() const; Variant back() const; void sort(); - void sort_custom(Callable p_callable); + void sort_custom(const Callable &p_callable); void shuffle(); int bsearch(const Variant &p_value, bool p_before = true); - int bsearch_custom(const Variant &p_value, Callable p_callable, bool p_before = true); + int bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before = true); void reverse(); int find(const Variant &p_value, int p_from = 0) const; @@ -100,8 +102,9 @@ public: Variant pop_at(int p_pos); Array duplicate(bool p_deep = false) const; + Array recursive_duplicate(bool p_deep, int recursion_count) const; - Array slice(int p_begin, int p_end, int p_step = 1, bool p_deep = false) const; + Array slice(int p_begin, int p_end = INT_MAX, int p_step = 1, bool p_deep = false) const; Array filter(const Callable &p_callable) const; Array map(const Callable &p_callable) const; Variant reduce(const Callable &p_callable, const Variant &p_accum) const; diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index 3b2c837096..22a13b0fab 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -44,24 +44,42 @@ #include <stdio.h> +// Variant cannot define an implicit cast operator for every Object subclass, so the +// casting is done here, to allow binding methods with parameters more specific than Object * + template <class T> struct VariantCaster { static _FORCE_INLINE_ T cast(const Variant &p_variant) { - return p_variant; + using TStripped = std::remove_pointer_t<T>; + if constexpr (std::is_base_of<Object, TStripped>::value) { + return Object::cast_to<TStripped>(p_variant); + } else { + return p_variant; + } } }; template <class T> struct VariantCaster<T &> { static _FORCE_INLINE_ T cast(const Variant &p_variant) { - return p_variant; + using TStripped = std::remove_pointer_t<T>; + if constexpr (std::is_base_of<Object, TStripped>::value) { + return Object::cast_to<TStripped>(p_variant); + } else { + return p_variant; + } } }; template <class T> struct VariantCaster<const T &> { static _FORCE_INLINE_ T cast(const Variant &p_variant) { - return p_variant; + using TStripped = std::remove_pointer_t<T>; + if constexpr (std::is_base_of<Object, TStripped>::value) { + return Object::cast_to<TStripped>(p_variant); + } else { + return p_variant; + } } }; @@ -80,14 +98,22 @@ struct VariantCaster<const T &> { } \ typedef int64_t EncodeT; \ _FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \ - *(int64_t *)p_ptr = p_val; \ + *(int64_t *)p_ptr = (int64_t)p_val; \ } \ + }; \ + template <> \ + struct ZeroInitializer<m_enum> { \ + static void initialize(m_enum &value) { value = (m_enum)0; } \ }; // Object enum casts must go here VARIANT_ENUM_CAST(Object::ConnectFlags); +VARIANT_ENUM_CAST(Vector2::Axis); +VARIANT_ENUM_CAST(Vector2i::Axis); VARIANT_ENUM_CAST(Vector3::Axis); +VARIANT_ENUM_CAST(Vector3i::Axis); +VARIANT_ENUM_CAST(Basis::EulerOrder); VARIANT_ENUM_CAST(Error); VARIANT_ENUM_CAST(Side); @@ -102,9 +128,9 @@ VARIANT_ENUM_CAST(KeyModifierMask); VARIANT_ENUM_CAST(MIDIMessage); VARIANT_ENUM_CAST(MouseButton); VARIANT_ENUM_CAST(Orientation); -VARIANT_ENUM_CAST(HAlign); -VARIANT_ENUM_CAST(VAlign); -VARIANT_ENUM_CAST(InlineAlign); +VARIANT_ENUM_CAST(HorizontalAlignment); +VARIANT_ENUM_CAST(VerticalAlignment); +VARIANT_ENUM_CAST(InlineAlignment); VARIANT_ENUM_CAST(PropertyHint); VARIANT_ENUM_CAST(PropertyUsageFlags); VARIANT_ENUM_CAST(Variant::Type); @@ -131,7 +157,13 @@ struct PtrToArg<char32_t> { template <typename T> struct VariantObjectClassChecker { static _FORCE_INLINE_ bool check(const Variant &p_variant) { - return true; + using TStripped = std::remove_pointer_t<T>; + if constexpr (std::is_base_of<Object, TStripped>::value) { + Object *obj = p_variant; + return Object::cast_to<TStripped>(p_variant) || !obj; + } else { + return true; + } } }; @@ -147,24 +179,6 @@ struct VariantObjectClassChecker<const Ref<T> &> { } }; -template <> -struct VariantObjectClassChecker<Node *> { - static _FORCE_INLINE_ bool check(const Variant &p_variant) { - Object *obj = p_variant; - Node *node = p_variant; - return node || !obj; - } -}; - -template <> -struct VariantObjectClassChecker<Control *> { - static _FORCE_INLINE_ bool check(const Variant &p_variant) { - Object *obj = p_variant; - Control *control = p_variant; - return control || !obj; - } -}; - #ifdef DEBUG_METHODS_ENABLED template <class T> @@ -172,7 +186,7 @@ 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) || - !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) { + !VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = p_arg_idx; r_error.expected = argtype; @@ -187,7 +201,7 @@ 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) || - !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) { + !VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = p_arg_idx; r_error.expected = argtype; @@ -202,7 +216,7 @@ 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) || - !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) { + !VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = p_arg_idx; r_error.expected = argtype; @@ -563,13 +577,11 @@ void call_with_validated_variant_args_static_method_ret(R (*p_method)(P...), con // GCC raises "parameter 'p_args' set but not used" when P = {}, // it's not clever enough to treat other P values as making this branch valid. -#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__) +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #endif -#ifdef DEBUG_METHODS_ENABLED - template <class Q> void call_get_argument_type_helper(int p_arg, int &index, Variant::Type &type) { if (p_arg == index) { @@ -608,6 +620,7 @@ void call_get_argument_type_info(int p_arg, PropertyInfo &info) { (void)index; // Suppress GCC warning. } +#ifdef DEBUG_METHODS_ENABLED template <class Q> void call_get_argument_metadata_helper(int p_arg, int &index, GodotTypeInfo::Metadata &md) { if (p_arg == index) { @@ -629,13 +642,6 @@ GodotTypeInfo::Metadata call_get_argument_metadata(int p_arg) { return md; } -#else - -template <class... P> -Variant::Type call_get_argument_type(int p_arg) { - return Variant::NIL; -} - #endif // DEBUG_METHODS_ENABLED ////////////////////// @@ -915,7 +921,7 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const Variant **p_ call_with_variant_args_static(p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{}); } -#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__) +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index f487e718f4..516b8f2d51 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -37,7 +37,7 @@ #include "core/object/script_language.h" void Callable::call_deferred(const Variant **p_arguments, int p_argcount) const { - MessageQueue::get_singleton()->push_callable(*this, p_arguments, p_argcount); + MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount); } void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const { @@ -59,7 +59,7 @@ void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_retu return; } #endif - r_return_value = obj->call(method, p_arguments, p_argcount, r_call_error); + r_return_value = obj->callp(method, p_arguments, p_argcount, r_call_error); } } @@ -114,8 +114,9 @@ ObjectID Callable::get_object_id() const { } StringName Callable::get_method() const { - ERR_FAIL_COND_V_MSG(is_custom(), StringName(), - vformat("Can't get method on CallableCustom \"%s\".", operator String())); + if (is_custom()) { + return get_custom()->get_method(); + } return method; } @@ -310,6 +311,10 @@ Callable::~Callable() { } } +StringName CallableCustom::get_method() const { + ERR_FAIL_V_MSG(StringName(), vformat("Can't get method on CallableCustom \"%s\".", get_as_text())); +} + void CallableCustom::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const { r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_call_error.argument = 0; @@ -374,14 +379,14 @@ Error Signal::emit(const Variant **p_arguments, int p_argcount) const { return ERR_INVALID_DATA; } - return obj->emit_signal(name, p_arguments, p_argcount); + return obj->emit_signalp(name, p_arguments, p_argcount); } -Error Signal::connect(const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) { +Error Signal::connect(const Callable &p_callable, 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); + return object->connect(name, p_callable, varray(), p_flags); } void Signal::disconnect(const Callable &p_callable) { @@ -424,3 +429,13 @@ Signal::Signal(ObjectID p_object, const StringName &p_name) { object = p_object; name = p_name; } + +bool CallableComparator::operator()(const Variant &p_l, const Variant &p_r) const { + const Variant *args[2] = { &p_l, &p_r }; + Callable::CallError err; + Variant res; + func.call(args, 2, res, err); + ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, false, + "Error calling compare method: " + Variant::get_callable_error_text(func, args, 1, err)); + return res; +} diff --git a/core/variant/callable.h b/core/variant/callable.h index 52094af3aa..6a760958d6 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -125,6 +125,7 @@ public: virtual String get_as_text() const = 0; virtual CompareEqualFunc get_compare_equal_func() const = 0; virtual CompareLessFunc get_compare_less_func() const = 0; + virtual StringName get_method() const; 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; virtual void rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const; @@ -159,7 +160,7 @@ public: 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); + Error connect(const Callable &p_callable, uint32_t p_flags = 0); void disconnect(const Callable &p_callable); bool is_connected(const Callable &p_callable) const; @@ -169,4 +170,10 @@ public: Signal() {} }; +struct CallableComparator { + const Callable &func; + + bool operator()(const Variant &p_l, const Variant &p_r) const; +}; + #endif // CALLABLE_H diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp index 56eda6e703..1a400b4360 100644 --- a/core/variant/callable_bind.cpp +++ b/core/variant/callable_bind.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -40,8 +40,8 @@ String CallableCustomBind::get_as_text() const { } bool CallableCustomBind::_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) { - const CallableCustomBind *a = (const CallableCustomBind *)p_a; - const CallableCustomBind *b = (const CallableCustomBind *)p_b; + const CallableCustomBind *a = static_cast<const CallableCustomBind *>(p_a); + const CallableCustomBind *b = static_cast<const CallableCustomBind *>(p_b); if (!(a->callable != b->callable)) { return false; @@ -55,8 +55,8 @@ bool CallableCustomBind::_equal_func(const CallableCustom *p_a, const CallableCu } bool CallableCustomBind::_less_func(const CallableCustom *p_a, const CallableCustom *p_b) { - const CallableCustomBind *a = (const CallableCustomBind *)p_a; - const CallableCustomBind *b = (const CallableCustomBind *)p_b; + const CallableCustomBind *a = static_cast<const CallableCustomBind *>(p_a); + const CallableCustomBind *b = static_cast<const CallableCustomBind *>(p_b); if (a->callable < b->callable) { return true; @@ -70,12 +70,19 @@ bool CallableCustomBind::_less_func(const CallableCustom *p_a, const CallableCus CallableCustom::CompareEqualFunc CallableCustomBind::get_compare_equal_func() const { return _equal_func; } + CallableCustom::CompareLessFunc CallableCustomBind::get_compare_less_func() const { return _less_func; } + +StringName CallableCustomBind::get_method() const { + return callable.get_method(); +} + ObjectID CallableCustomBind::get_object() const { return callable.get_object_id(); } + const Callable *CallableCustomBind::get_base_comparator() const { return &callable; } @@ -110,8 +117,8 @@ String CallableCustomUnbind::get_as_text() const { } bool CallableCustomUnbind::_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) { - const CallableCustomUnbind *a = (const CallableCustomUnbind *)p_a; - const CallableCustomUnbind *b = (const CallableCustomUnbind *)p_b; + const CallableCustomUnbind *a = static_cast<const CallableCustomUnbind *>(p_a); + const CallableCustomUnbind *b = static_cast<const CallableCustomUnbind *>(p_b); if (!(a->callable != b->callable)) { return false; @@ -125,8 +132,8 @@ bool CallableCustomUnbind::_equal_func(const CallableCustom *p_a, const Callable } bool CallableCustomUnbind::_less_func(const CallableCustom *p_a, const CallableCustom *p_b) { - const CallableCustomUnbind *a = (const CallableCustomUnbind *)p_a; - const CallableCustomUnbind *b = (const CallableCustomUnbind *)p_b; + const CallableCustomUnbind *a = static_cast<const CallableCustomUnbind *>(p_a); + const CallableCustomUnbind *b = static_cast<const CallableCustomUnbind *>(p_b); if (a->callable < b->callable) { return true; @@ -140,12 +147,19 @@ bool CallableCustomUnbind::_less_func(const CallableCustom *p_a, const CallableC CallableCustom::CompareEqualFunc CallableCustomUnbind::get_compare_equal_func() const { return _equal_func; } + CallableCustom::CompareLessFunc CallableCustomUnbind::get_compare_less_func() const { return _less_func; } + +StringName CallableCustomUnbind::get_method() const { + return callable.get_method(); +} + ObjectID CallableCustomUnbind::get_object() const { return callable.get_object_id(); } + const Callable *CallableCustomUnbind::get_base_comparator() const { return &callable; } diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h index feb40d1de9..a5c830e109 100644 --- a/core/variant/callable_bind.h +++ b/core/variant/callable_bind.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -43,13 +43,17 @@ class CallableCustomBind : public CallableCustom { public: //for every type that inherits, these must always be the same for this type - virtual uint32_t hash() const; - virtual String get_as_text() const; - virtual CompareEqualFunc get_compare_equal_func() const; - virtual CompareLessFunc get_compare_less_func() const; - virtual ObjectID get_object() const; //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; - virtual const Callable *get_base_comparator() const; + virtual uint32_t hash() const override; + virtual String get_as_text() const override; + virtual CompareEqualFunc get_compare_equal_func() const override; + virtual CompareLessFunc get_compare_less_func() const override; + virtual StringName get_method() const override; + virtual ObjectID get_object() const override; //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 override; + virtual const Callable *get_base_comparator() const override; + + Callable get_callable() { return callable; } + Vector<Variant> get_binds() { return binds; } CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds); virtual ~CallableCustomBind(); @@ -64,13 +68,17 @@ class CallableCustomUnbind : public CallableCustom { public: //for every type that inherits, these must always be the same for this type - virtual uint32_t hash() const; - virtual String get_as_text() const; - virtual CompareEqualFunc get_compare_equal_func() const; - virtual CompareLessFunc get_compare_less_func() const; - virtual ObjectID get_object() const; //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; - virtual const Callable *get_base_comparator() const; + virtual uint32_t hash() const override; + virtual String get_as_text() const override; + virtual CompareEqualFunc get_compare_equal_func() const override; + virtual CompareLessFunc get_compare_less_func() const override; + virtual StringName get_method() const override; + virtual ObjectID get_object() const override; //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 override; + virtual const Callable *get_base_comparator() const override; + + Callable get_callable() { return callable; } + int get_unbinds() { return argcount; } CallableCustomUnbind(const Callable &p_callable, int p_argcount); virtual ~CallableCustomUnbind(); diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h index f13a37cddd..6171c8c88f 100644 --- a/core/variant/container_type_validate.h +++ b/core/variant/container_type_validate.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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/variant/dictionary.cpp b/core/variant/dictionary.cpp index 07b3a9a675..0f2f8fc8ed 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -188,11 +188,35 @@ bool Dictionary::erase(const Variant &p_key) { } bool Dictionary::operator==(const Dictionary &p_dictionary) const { - return _p == p_dictionary._p; + return recursive_equal(p_dictionary, 0); } bool Dictionary::operator!=(const Dictionary &p_dictionary) const { - return _p != p_dictionary._p; + return !recursive_equal(p_dictionary, 0); +} + +bool Dictionary::recursive_equal(const Dictionary &p_dictionary, int recursion_count) const { + // Cheap checks + if (_p == p_dictionary._p) { + return true; + } + if (_p->variant_map.size() != p_dictionary._p->variant_map.size()) { + return false; + } + + // Heavy O(n) check + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return true; + } + recursion_count++; + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement this_E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->front(); this_E; this_E = this_E.next()) { + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement other_E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&p_dictionary._p->variant_map)->find(this_E.key()); + if (!other_E || !this_E.value().hash_compare(other_E.value(), recursion_count)) { + return false; + } + } + return true; } void Dictionary::_ref(const Dictionary &p_from) const { @@ -225,11 +249,21 @@ void Dictionary::_unref() const { } uint32_t Dictionary::hash() const { + return recursive_hash(0); +} + +uint32_t Dictionary::recursive_hash(int recursion_count) const { + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return 0; + } + uint32_t h = hash_djb2_one_32(Variant::DICTIONARY); + recursion_count++; for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { - h = hash_djb2_one_32(E.key().hash(), h); - h = hash_djb2_one_32(E.value().hash(), h); + h = hash_djb2_one_32(E.key().recursive_hash(recursion_count), h); + h = hash_djb2_one_32(E.value().recursive_hash(recursion_count), h); } return h; @@ -286,10 +320,26 @@ const Variant *Dictionary::next(const Variant *p_key) const { } Dictionary Dictionary::duplicate(bool p_deep) const { + return recursive_duplicate(p_deep, 0); +} + +Dictionary Dictionary::recursive_duplicate(bool p_deep, int recursion_count) const { Dictionary n; - for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { - n[E.key()] = p_deep ? E.value().duplicate(true) : E.value(); + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return n; + } + + if (p_deep) { + recursion_count++; + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { + n[E.key().recursive_duplicate(true, recursion_count)] = E.value().recursive_duplicate(true, recursion_count); + } + } else { + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { + n[E.key()] = E.value(); + } } return n; @@ -300,7 +350,7 @@ void Dictionary::operator=(const Dictionary &p_dictionary) { } const void *Dictionary::id() const { - return _p->variant_map.id(); + return _p; } Dictionary::Dictionary(const Dictionary &p_from) { diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h index 4067ff9fd9..16cf0c2bf8 100644 --- a/core/variant/dictionary.h +++ b/core/variant/dictionary.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -70,8 +70,10 @@ public: bool operator==(const Dictionary &p_dictionary) const; bool operator!=(const Dictionary &p_dictionary) const; + bool recursive_equal(const Dictionary &p_dictionary, int recursion_count) const; uint32_t hash() const; + uint32_t recursive_hash(int recursion_count) const; void operator=(const Dictionary &p_dictionary); const Variant *next(const Variant *p_key = nullptr) const; @@ -80,6 +82,7 @@ public: Array values() const; Dictionary duplicate(bool p_deep = false) const; + Dictionary recursive_duplicate(bool p_deep, int recursion_count) const; const void *id() const; diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h index 98304621f2..d0acf60c22 100644 --- a/core/variant/method_ptrcall.h +++ b/core/variant/method_ptrcall.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,6 @@ #ifndef METHOD_PTRCALL_H #define METHOD_PTRCALL_H -#include "core/math/transform_2d.h" #include "core/object/object_id.h" #include "core/typedefs.h" #include "core/variant/variant.h" diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h index b4ec0df7d6..ed68e0f6c9 100644 --- a/core/variant/native_ptr.h +++ b/core/variant/native_ptr.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -53,22 +53,36 @@ struct GDNativePtr { operator Variant() const { return uint64_t(data); } }; -#define GDVIRTUAL_NATIVE_PTR(m_type) \ - template <> \ - struct GDNativeConstPtr<m_type> { \ - const m_type *data = nullptr; \ - GDNativeConstPtr(const m_type *p_assign) { data = p_assign; } \ - static const char *get_name() { return "const " #m_type; } \ - operator const m_type *() const { return data; } \ - operator Variant() const { return uint64_t(data); } \ - }; \ - template <> \ - struct GDNativePtr<m_type> { \ - m_type *data = nullptr; \ - GDNativePtr(m_type *p_assign) { data = p_assign; } \ - static const char *get_name() { return #m_type; } \ - operator m_type *() const { return data; } \ - operator Variant() const { return uint64_t(data); } \ +#define GDVIRTUAL_NATIVE_PTR(m_type) \ + template <> \ + struct GDNativeConstPtr<const m_type> { \ + const m_type *data = nullptr; \ + GDNativeConstPtr() {} \ + GDNativeConstPtr(const m_type *p_assign) { data = p_assign; } \ + static const char *get_name() { return "const " #m_type; } \ + operator const m_type *() const { return data; } \ + operator Variant() const { return uint64_t(data); } \ + }; \ + template <> \ + struct VariantCaster<GDNativeConstPtr<const m_type>> { \ + static _FORCE_INLINE_ GDNativeConstPtr<const m_type> cast(const Variant &p_variant) { \ + return GDNativeConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \ + } \ + }; \ + template <> \ + struct GDNativePtr<m_type> { \ + m_type *data = nullptr; \ + GDNativePtr() {} \ + GDNativePtr(m_type *p_assign) { data = p_assign; } \ + static const char *get_name() { return #m_type; } \ + operator m_type *() const { return data; } \ + operator Variant() const { return uint64_t(data); } \ + }; \ + template <> \ + struct VariantCaster<GDNativePtr<m_type>> { \ + static _FORCE_INLINE_ GDNativePtr<m_type> cast(const Variant &p_variant) { \ + return GDNativePtr<m_type>((m_type *)p_variant.operator uint64_t()); \ + } \ }; template <class T> @@ -110,6 +124,7 @@ struct PtrToArg<GDNativePtr<T>> { } }; +GDVIRTUAL_NATIVE_PTR(void) GDVIRTUAL_NATIVE_PTR(AudioFrame) GDVIRTUAL_NATIVE_PTR(bool) GDVIRTUAL_NATIVE_PTR(char) @@ -117,6 +132,7 @@ GDVIRTUAL_NATIVE_PTR(char16_t) GDVIRTUAL_NATIVE_PTR(char32_t) GDVIRTUAL_NATIVE_PTR(wchar_t) GDVIRTUAL_NATIVE_PTR(uint8_t) +GDVIRTUAL_NATIVE_PTR(uint8_t *) GDVIRTUAL_NATIVE_PTR(int8_t) GDVIRTUAL_NATIVE_PTR(uint16_t) GDVIRTUAL_NATIVE_PTR(int16_t) diff --git a/core/variant/type_info.h b/core/variant/type_info.h index b70d29bbac..bacd0d19ce 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -60,7 +60,7 @@ struct TypeInherits { static char (&test(...))[2]; static bool const value = sizeof(test(get_d())) == sizeof(char) && - !TypesAreSame<B volatile const, void volatile const>::value; + !TypesAreSame<B volatile const, void volatile const>::value; }; namespace GodotTypeInfo { @@ -245,8 +245,9 @@ namespace godot { namespace details { inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) { Vector<String> parts = p_qualified_name.split("::", false); - if (parts.size() <= 2) + if (parts.size() <= 2) { return String(".").join(parts); + } // Contains namespace. We only want the class and enum names. return parts[parts.size() - 2] + "." + parts[parts.size() - 1]; } @@ -280,4 +281,38 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) { #define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info()) +template <typename T> +struct ZeroInitializer { + static void initialize(T &value) {} //no initialization by default +}; + +template <> +struct ZeroInitializer<bool> { + static void initialize(bool &value) { value = false; } +}; + +template <typename T> +struct ZeroInitializer<T *> { + static void initialize(T *&value) { value = nullptr; } +}; + +#define ZERO_INITIALIZER_NUMBER(m_type) \ + template <> \ + struct ZeroInitializer<m_type> { \ + static void initialize(m_type &value) { value = 0; } \ + }; + +ZERO_INITIALIZER_NUMBER(uint8_t) +ZERO_INITIALIZER_NUMBER(int8_t) +ZERO_INITIALIZER_NUMBER(uint16_t) +ZERO_INITIALIZER_NUMBER(int16_t) +ZERO_INITIALIZER_NUMBER(uint32_t) +ZERO_INITIALIZER_NUMBER(int32_t) +ZERO_INITIALIZER_NUMBER(uint64_t) +ZERO_INITIALIZER_NUMBER(int64_t) +ZERO_INITIALIZER_NUMBER(char16_t) +ZERO_INITIALIZER_NUMBER(char32_t) +ZERO_INITIALIZER_NUMBER(float) +ZERO_INITIALIZER_NUMBER(double) + #endif // TYPE_INFO_H diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h index 2e96f4e445..aadd6fee89 100644 --- a/core/variant/typed_array.h +++ b/core/variant/typed_array.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,8 +31,10 @@ #ifndef TYPED_ARRAY_H #define TYPED_ARRAY_H +#include "core/object/object.h" #include "core/variant/array.h" #include "core/variant/method_ptrcall.h" +#include "core/variant/type_info.h" #include "core/variant/variant.h" template <class T> diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 0dbeb6e4cb..da5d73d519 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -38,8 +38,6 @@ #include "core/math/math_funcs.h" #include "core/string/print_string.h" #include "core/variant/variant_parser.h" -#include "scene/gui/control.h" -#include "scene/main/node.h" String Variant::get_type_name(Variant::Type p_type) { switch (p_type) { @@ -186,7 +184,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { if (p_type_from == p_type_to) { return true; } - if (p_type_to == NIL && p_type_from != NIL) { //nil can convert to anything + if (p_type_to == NIL) { //nil can convert to anything return true; } @@ -313,7 +311,6 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { case BASIS: { static const Type valid[] = { QUATERNION, - VECTOR3, NIL }; @@ -493,7 +490,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type if (p_type_from == p_type_to) { return true; } - if (p_type_to == NIL && p_type_from != NIL) { //nil can convert to anything + if (p_type_to == NIL) { //nil can convert to anything return true; } @@ -620,7 +617,6 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type case BASIS: { static const Type valid[] = { QUATERNION, - VECTOR3, NIL }; @@ -786,16 +782,11 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } bool Variant::operator==(const Variant &p_variant) const { - if (type != p_variant.type) { //evaluation of operator== needs to be more strict - return false; - } - bool v; - Variant r; - evaluate(OP_EQUAL, *this, p_variant, r, v); - return r; + return hash_compare(p_variant); } bool Variant::operator!=(const Variant &p_variant) const { + // Don't use `!hash_compare(p_variant)` given it makes use of OP_EQUAL if (type != p_variant.type) { //evaluation of operator== needs to be more strict return true; } @@ -1032,6 +1023,13 @@ bool Variant::is_null() const { } } +bool Variant::initialize_ref(Object *p_object) { + RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_object)); + if (!ref_counted->init_ref()) { + return false; + } + return true; +} void Variant::reference(const Variant &p_variant) { switch (type) { case NIL: @@ -1619,12 +1617,23 @@ struct _VariantStrPair { }; Variant::operator String() const { - List<const void *> stack; + return stringify(0); +} - return stringify(stack); +template <class T> +String stringify_vector(const T &vec, int recursion_count) { + String str("["); + for (int i = 0; i < vec.size(); i++) { + if (i > 0) { + str += ", "; + } + str = str + Variant(vec[i]).stringify(recursion_count); + } + str += "]"; + return str; } -String Variant::stringify(List<const void *> &stack) const { +String Variant::stringify(int recursion_count) const { switch (type) { case NIL: return "null"; @@ -1668,29 +1677,26 @@ String Variant::stringify(List<const void *> &stack) const { return operator Color(); case DICTIONARY: { const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem); - if (stack.find(d.id())) { + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); return "{...}"; } - stack.push_back(d.id()); - - //const String *K=nullptr; String str("{"); List<Variant> keys; d.get_key_list(&keys); Vector<_VariantStrPair> pairs; - for (const Variant &E : keys) { + recursion_count++; + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { _VariantStrPair sp; - sp.key = E.stringify(stack); - sp.value = d[E].stringify(stack); + sp.key = E->get().stringify(recursion_count); + sp.value = d[E->get()].stringify(recursion_count); pairs.push_back(sp); } - pairs.sort(); - for (int i = 0; i < pairs.size(); i++) { if (i > 0) { str += ", "; @@ -1699,111 +1705,43 @@ String Variant::stringify(List<const void *> &stack) const { } str += "}"; - stack.erase(d.id()); return str; } break; case PACKED_VECTOR2_ARRAY: { - Vector<Vector2> vec = operator Vector<Vector2>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + Variant(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<Vector2>(), recursion_count); } break; case PACKED_VECTOR3_ARRAY: { - Vector<Vector3> vec = operator Vector<Vector3>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + Variant(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<Vector3>(), recursion_count); + } break; + case PACKED_COLOR_ARRAY: { + return stringify_vector(operator Vector<Color>(), recursion_count); } break; case PACKED_STRING_ARRAY: { - Vector<String> vec = operator Vector<String>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + vec[i]; - } - str += "]"; - return str; + return stringify_vector(operator Vector<String>(), recursion_count); + } break; + case PACKED_BYTE_ARRAY: { + return stringify_vector(operator Vector<uint8_t>(), recursion_count); } break; case PACKED_INT32_ARRAY: { - Vector<int32_t> vec = operator Vector<int32_t>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + itos(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<int32_t>(), recursion_count); } break; case PACKED_INT64_ARRAY: { - Vector<int64_t> vec = operator Vector<int64_t>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + itos(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<int64_t>(), recursion_count); } break; case PACKED_FLOAT32_ARRAY: { - Vector<float> vec = operator Vector<float>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + rtos(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<float>(), recursion_count); } break; case PACKED_FLOAT64_ARRAY: { - Vector<double> vec = operator Vector<double>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + rtos(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<double>(), recursion_count); } break; case ARRAY: { Array arr = operator Array(); - if (stack.find(arr.id())) { + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); return "[...]"; } - stack.push_back(arr.id()); - - String str("["); - for (int i = 0; i < arr.size(); i++) { - if (i) { - str += ", "; - } - - str += arr[i].stringify(stack); - } - str += "]"; - stack.erase(arr.id()); + String str = stringify_vector(arr, recursion_count); return str; } break; @@ -1941,8 +1879,6 @@ Variant::operator Basis() const { return *_data._basis; } else if (type == QUATERNION) { return *reinterpret_cast<const Quaternion *>(_data._mem); - } else if (type == VECTOR3) { - return Basis(*reinterpret_cast<const Vector3 *>(_data._mem)); } else if (type == TRANSFORM3D) { // unexposed in Variant::can_convert? return _data._transform3d->basis; } else { @@ -2036,7 +1972,7 @@ Variant::operator ::RID() const { } #endif Callable::CallError ce; - Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce); + Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce); if (ce.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::RID) { return ret; } @@ -2073,22 +2009,6 @@ Object *Variant::get_validated_object() const { } } -Variant::operator Node *() const { - if (type == OBJECT) { - return Object::cast_to<Node>(_get_obj().obj); - } else { - return nullptr; - } -} - -Variant::operator Control *() const { - if (type == OBJECT) { - return Object::cast_to<Control>(_get_obj().obj); - } else { - return nullptr; - } -} - Variant::operator Dictionary() const { if (type == DICTIONARY) { return *reinterpret_cast<const Dictionary *>(_data._mem); @@ -2824,6 +2744,10 @@ Variant::Variant(const Variant &p_variant) { } uint32_t Variant::hash() const { + return recursive_hash(0); +} + +uint32_t Variant::recursive_hash(int recursion_count) const { switch (type) { case NIL: { return 0; @@ -2951,7 +2875,7 @@ uint32_t Variant::hash() const { return reinterpret_cast<const NodePath *>(_data._mem)->hash(); } break; case DICTIONARY: { - return reinterpret_cast<const Dictionary *>(_data._mem)->hash(); + return reinterpret_cast<const Dictionary *>(_data._mem)->recursive_hash(recursion_count); } break; case CALLABLE: { @@ -2965,7 +2889,7 @@ uint32_t Variant::hash() const { } break; case ARRAY: { const Array &arr = *reinterpret_cast<const Array *>(_data._mem); - return arr.hash(); + return arr.recursive_hash(recursion_count); } break; case PACKED_BYTE_ARRAY: { @@ -3139,16 +3063,24 @@ uint32_t Variant::hash() const { \ return true -bool Variant::hash_compare(const Variant &p_variant) const { +bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const { if (type != p_variant.type) { return false; } switch (type) { + case INT: { + return _data._int == p_variant._data._int; + } break; + case FLOAT: { return hash_compare_scalar(_data._float, p_variant._data._float); } break; + case STRING: { + return *reinterpret_cast<const String *>(_data._mem) == *reinterpret_cast<const String *>(p_variant._data._mem); + } break; + case VECTOR2: { const Vector2 *l = reinterpret_cast<const Vector2 *>(_data._mem); const Vector2 *r = reinterpret_cast<const Vector2 *>(p_variant._data._mem); @@ -3166,7 +3098,7 @@ bool Variant::hash_compare(const Variant &p_variant) const { const Rect2 *r = reinterpret_cast<const Rect2 *>(p_variant._data._mem); return (hash_compare_vector2(l->position, r->position)) && - (hash_compare_vector2(l->size, r->size)); + (hash_compare_vector2(l->size, r->size)); } break; case RECT2I: { const Rect2i *l = reinterpret_cast<const Rect2i *>(_data._mem); @@ -3206,7 +3138,7 @@ bool Variant::hash_compare(const Variant &p_variant) const { const Plane *r = reinterpret_cast<const Plane *>(p_variant._data._mem); return (hash_compare_vector3(l->normal, r->normal)) && - (hash_compare_scalar(l->d, r->d)); + (hash_compare_scalar(l->d, r->d)); } break; case AABB: { @@ -3262,14 +3194,19 @@ bool Variant::hash_compare(const Variant &p_variant) const { const Array &l = *(reinterpret_cast<const Array *>(_data._mem)); const Array &r = *(reinterpret_cast<const Array *>(p_variant._data._mem)); - if (l.size() != r.size()) { + if (!l.recursive_equal(r, recursion_count + 1)) { return false; } - for (int i = 0; i < l.size(); ++i) { - if (!l[i].hash_compare(r[i])) { - return false; - } + return true; + } break; + + case DICTIONARY: { + const Dictionary &l = *(reinterpret_cast<const Dictionary *>(_data._mem)); + const Dictionary &r = *(reinterpret_cast<const Dictionary *>(p_variant._data._mem)); + + if (!l.recursive_equal(r, recursion_count + 1)) { + return false; } return true; @@ -3306,7 +3243,7 @@ bool Variant::hash_compare(const Variant &p_variant) const { return false; } -bool Variant::is_ref() const { +bool Variant::is_ref_counted() const { return type == OBJECT && _get_obj().id.is_ref_counted(); } @@ -3372,21 +3309,7 @@ bool Variant::is_shared() const { return false; } -Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - Callable::CallError error; - - Variant ret; - call(p_method, argptr, argc, ret, error); - +void Variant::_variant_call_error(const String &p_method, Callable::CallError &error) { switch (error.error) { case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { String err = "Invalid type for argument #" + itos(error.argument) + ", expected '" + Variant::get_type_name(Variant::Type(error.expected)) + "'."; @@ -3404,8 +3327,6 @@ Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) { default: { } } - - return ret; } void Variant::construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct, void *p_construct_ud) { @@ -3466,7 +3387,7 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method, } String class_name = p_base->get_class(); - Ref<Script> script = p_base->get_script(); + Ref<Resource> script = p_base->get_script(); if (script.is_valid() && script->get_path().is_resource_file()) { class_name += "(" + script->get_path().get_file() + ")"; } diff --git a/core/variant/variant.h b/core/variant/variant.h index 9ec131a1b8..475bf7158d 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,6 +31,7 @@ #ifndef VARIANT_H #define VARIANT_H +#include "core/input/input_enums.h" #include "core/io/ip_address.h" #include "core/math/aabb.h" #include "core/math/basis.h" @@ -38,11 +39,16 @@ #include "core/math/face3.h" #include "core/math/plane.h" #include "core/math/quaternion.h" +#include "core/math/rect2.h" +#include "core/math/rect2i.h" #include "core/math/transform_2d.h" #include "core/math/transform_3d.h" +#include "core/math/vector2.h" +#include "core/math/vector2i.h" #include "core/math/vector3.h" #include "core/math/vector3i.h" #include "core/object/object_id.h" +#include "core/os/keyboard.h" #include "core/string/node_path.h" #include "core/string/ustring.h" #include "core/templates/rid.h" @@ -51,8 +57,6 @@ #include "core/variant/dictionary.h" class Object; -class Node; // helper -class Control; // helper struct PropertyInfo; struct MethodInfo; @@ -212,6 +216,7 @@ private: } _data alignas(8); void reference(const Variant &p_variant); + static bool initialize_ref(Object *p_object); void _clear_internal(); @@ -277,6 +282,14 @@ private: static void _register_variant_utility_functions(); static void _unregister_variant_utility_functions(); + void _variant_call_error(const String &p_method, Callable::CallError &error); + + // Avoid accidental conversion. If you reached this point, it's because you most likely forgot to dereference + // a Variant pointer (so add * like this: *variant_pointer). + + Variant(const Variant *) {} + Variant(const Variant **) {} + public: _FORCE_INLINE_ Type get_type() const { return type; @@ -285,7 +298,7 @@ public: static bool can_convert(Type p_type_from, Type p_type_to); static bool can_convert_strict(Type p_type_from, Type p_type_to); - bool is_ref() const; + bool is_ref_counted() const; _FORCE_INLINE_ bool is_num() const { return type == INT || type == FLOAT; } @@ -337,8 +350,6 @@ public: operator ::RID() const; operator Object *() const; - operator Node *() const; - operator Control *() const; operator Callable() const; operator Signal() const; @@ -430,6 +441,21 @@ public: Variant(const IPAddress &p_address); +#define VARIANT_ENUM_CLASS_CONSTRUCTOR(m_enum) \ + Variant(const m_enum &p_value) { \ + type = INT; \ + _data._int = (int64_t)p_value; \ + } + + // Only enum classes that need to be bound need this to be defined. + VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyAxis) + VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyButton) + VARIANT_ENUM_CLASS_CONSTRUCTOR(Key) + VARIANT_ENUM_CLASS_CONSTRUCTOR(MIDIMessage) + VARIANT_ENUM_CLASS_CONSTRUCTOR(MouseButton) + +#undef VARIANT_ENUM_CLASS_CONSTRUCTOR + // If this changes the table in variant_op must be updated enum Operator { //comparison @@ -481,9 +507,11 @@ public: static PTROperatorEvaluator get_ptr_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b); void zero(); - Variant duplicate(bool deep = false) const; + Variant duplicate(bool p_deep = false) const; + Variant recursive_duplicate(bool p_deep, int recursion_count) const; 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); + static void sub(const Variant &a, const Variant &b, Variant &r_dst); /* Built-In Methods */ @@ -508,8 +536,23 @@ public: static int get_builtin_method_count(Variant::Type p_type); static uint32_t get_builtin_method_hash(Variant::Type p_type, const StringName &p_method); - void call(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_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant()); + void callp(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error); + + template <typename... VarArgs> + Variant call(const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + Callable::CallError cerr; + Variant ret; + callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), ret, cerr); + if (cerr.error != Callable::CallError::CALL_OK) { + _variant_call_error(p_method, cerr); + } + return ret; + } static void call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error); @@ -641,6 +684,7 @@ public: static UtilityFunctionType get_utility_function_type(const StringName &p_name); + static MethodInfo get_utility_function_info(const StringName &p_name); static int get_utility_function_argument_count(const StringName &p_name); static Variant::Type get_utility_function_argument_type(const StringName &p_name, int p_arg); static String get_utility_function_argument_name(const StringName &p_name, int p_arg); @@ -658,10 +702,11 @@ public: bool operator!=(const Variant &p_variant) const; bool operator<(const Variant &p_variant) const; uint32_t hash() const; + uint32_t recursive_hash(int recursion_count) const; - bool hash_compare(const Variant &p_variant) const; + bool hash_compare(const Variant &p_variant, int recursion_count = 0) const; bool booleanize() const; - String stringify(List<const void *> &stack) const; + String stringify(int recursion_count = 0) const; String to_json_string() const; void static_assign(const Variant &p_variant); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 49a0b455df..9dae0720d9 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -752,8 +752,9 @@ struct _VariantCall { static PackedInt32Array func_PackedByteArray_decode_s32_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); - const uint8_t *r = p_instance->ptr(); PackedInt32Array dest; + ERR_FAIL_COND_V_MSG(size < sizeof(int32_t), dest, "Size didn't match array of size int32_t, maybe you are trying to convert to the wrong type?"); + const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(int32_t)); memcpy(dest.ptrw(), r, size); return dest; @@ -761,8 +762,9 @@ struct _VariantCall { static PackedInt64Array func_PackedByteArray_decode_s64_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); - const uint8_t *r = p_instance->ptr(); PackedInt64Array dest; + ERR_FAIL_COND_V_MSG(size < sizeof(int64_t), dest, "Size didn't match array of size int64_t, maybe you are trying to convert to the wrong type?"); + const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(int64_t)); memcpy(dest.ptrw(), r, size); return dest; @@ -770,8 +772,9 @@ struct _VariantCall { static PackedFloat32Array func_PackedByteArray_decode_float_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); - const uint8_t *r = p_instance->ptr(); PackedFloat32Array dest; + ERR_FAIL_COND_V_MSG(size < sizeof(float), dest, "Size didn't match array of size float, maybe you are trying to convert to the wrong type?"); + const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(float)); memcpy(dest.ptrw(), r, size); return dest; @@ -779,8 +782,9 @@ struct _VariantCall { static PackedFloat64Array func_PackedByteArray_decode_double_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); - const uint8_t *r = p_instance->ptr(); PackedFloat64Array dest; + ERR_FAIL_COND_V_MSG(size < sizeof(double), dest, "Size didn't match array of size double, maybe you are trying to convert to the wrong type?"); + const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(double)); memcpy(dest.ptrw(), r, size); return dest; @@ -999,7 +1003,7 @@ static void register_builtin_method(const Vector<String> &p_argnames, const Vect builtin_method_names[T::get_base_type()].push_back(name); } -void Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) { +void Variant::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) { if (type == Variant::OBJECT) { //call object Object *obj = _get_obj().obj; @@ -1014,7 +1018,7 @@ void Variant::call(const StringName &p_method, const Variant **p_args, int p_arg } #endif - r_ret = _get_obj().obj->call(p_method, p_args, p_argcount, r_error); + r_ret = _get_obj().obj->callp(p_method, p_args, p_argcount, r_error); //else if (type==Variant::METHOD) { } else { @@ -1235,23 +1239,23 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const { void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants) { ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX); - _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type]; + const _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type]; #ifdef DEBUG_ENABLED - for (List<StringName>::Element *E = cd.value_ordered.front(); E; E = E->next()) { + for (const List<StringName>::Element *E = cd.value_ordered.front(); E; E = E->next()) { p_constants->push_back(E->get()); #else - for (Map<StringName, int>::Element *E = cd.value.front(); E; E = E->next()) { - p_constants->push_back(E->key()); + for (const KeyValue<StringName, int> &E : cd.value) { + p_constants->push_back(E.key); #endif } #ifdef DEBUG_ENABLED - for (List<StringName>::Element *E = cd.variant_value_ordered.front(); E; E = E->next()) { + for (const List<StringName>::Element *E = cd.variant_value_ordered.front(); E; E = E->next()) { p_constants->push_back(E->get()); #else - for (Map<StringName, Variant>::Element *E = cd.variant_value.front(); E; E = E->next()) { - p_constants->push_back(E->key()); + for (const KeyValue<StringName, Variant> &E : cd.variant_value) { + p_constants->push_back(E.key); #endif } } @@ -1366,6 +1370,9 @@ static void _register_variant_builtin_methods() { bind_method(String, naturalnocasecmp_to, sarray("to"), varray()); bind_method(String, length, sarray(), varray()); bind_method(String, substr, sarray("from", "len"), varray(-1)); + bind_method(String, get_slice, sarray("delimiter", "slice"), varray()); + bind_method(String, get_slicec, sarray("delimiter", "slice"), varray()); + bind_method(String, get_slice_count, sarray("delimiter"), varray()); bind_methodv(String, find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0)); bind_method(String, count, sarray("what", "from", "to"), varray(0, 0)); bind_method(String, countn, sarray("what", "from", "to"), varray(0, 0)); @@ -1377,7 +1384,7 @@ static void _register_variant_builtin_methods() { bind_methodv(String, begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray()); bind_method(String, ends_with, sarray("text"), varray()); bind_method(String, is_subsequence_of, sarray("text"), varray()); - bind_method(String, is_subsequence_ofi, sarray("text"), varray()); + bind_method(String, is_subsequence_ofn, sarray("text"), varray()); bind_method(String, bigrams, sarray(), varray()); bind_method(String, similarity, sarray("text"), varray()); @@ -1406,9 +1413,8 @@ static void _register_variant_builtin_methods() { bind_method(String, get_basename, sarray(), varray()); bind_method(String, plus_file, sarray("file"), varray()); bind_method(String, unicode_at, sarray("at"), varray()); + bind_method(String, indent, sarray("prefix"), varray()); bind_method(String, dedent, sarray(), varray()); - // FIXME: String needs to be immutable when binding - //bind_method(String, erase, sarray("position", "chars"), varray()); bind_method(String, hash, sarray(), varray()); bind_method(String, md5_text, sarray(), varray()); bind_method(String, sha1_text, sarray(), varray()); @@ -1417,8 +1423,7 @@ static void _register_variant_builtin_methods() { bind_method(String, sha1_buffer, sarray(), varray()); bind_method(String, sha256_buffer, sarray(), varray()); bind_method(String, is_empty, sarray(), varray()); - // FIXME: Static function, not sure how to bind - //bind_method(String, humanize_size, sarray("size"), varray()); + bind_methodv(String, contains, static_cast<bool (String::*)(const String &) const>(&String::contains), sarray("what"), varray()); bind_method(String, is_absolute_path, sarray(), varray()); bind_method(String, is_relative_path, sarray(), varray()); @@ -1462,6 +1467,8 @@ static void _register_variant_builtin_methods() { bind_static_method(String, num_scientific, sarray("number"), varray()); bind_static_method(String, num, sarray("number", "decimals"), varray(-1)); + bind_static_method(String, num_int64, sarray("number", "base", "capitalize_hex"), varray(10, false)); + bind_static_method(String, num_uint64, sarray("number", "base", "capitalize_hex"), varray(10, false)); bind_static_method(String, chr, sarray("char"), varray()); bind_static_method(String, humanize_size, sarray("size"), varray()); @@ -1470,7 +1477,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector2, angle, sarray(), varray()); bind_method(Vector2, angle_to, sarray("to"), varray()); bind_method(Vector2, angle_to_point, sarray("to"), varray()); - bind_method(Vector2, direction_to, sarray("b"), varray()); + bind_method(Vector2, direction_to, sarray("to"), varray()); bind_method(Vector2, distance_to, sarray("to"), varray()); bind_method(Vector2, distance_squared_to, sarray("to"), varray()); bind_method(Vector2, length, sarray(), varray()); @@ -1485,6 +1492,8 @@ static void _register_variant_builtin_methods() { bind_method(Vector2, lerp, sarray("to", "weight"), varray()); bind_method(Vector2, slerp, sarray("to", "weight"), varray()); bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray()); + bind_method(Vector2, max_axis_index, sarray(), varray()); + bind_method(Vector2, min_axis_index, sarray(), varray()); bind_method(Vector2, move_toward, sarray("to", "delta"), varray()); bind_method(Vector2, rotated, sarray("phi"), varray()); bind_method(Vector2, orthogonal, sarray(), varray()); @@ -1507,12 +1516,17 @@ static void _register_variant_builtin_methods() { /* Vector2i */ bind_method(Vector2i, aspect, sarray(), varray()); + bind_method(Vector2i, max_axis_index, sarray(), varray()); + bind_method(Vector2i, min_axis_index, sarray(), varray()); + bind_method(Vector2i, length, sarray(), varray()); + bind_method(Vector2i, length_squared, sarray(), varray()); bind_method(Vector2i, sign, sarray(), varray()); bind_method(Vector2i, abs, sarray(), varray()); bind_method(Vector2i, clamp, sarray("min", "max"), varray()); /* Rect2 */ + bind_method(Rect2, get_center, sarray(), varray()); bind_method(Rect2, get_area, sarray(), varray()); bind_method(Rect2, has_no_area, sarray(), varray()); bind_method(Rect2, has_point, sarray("point"), varray()); @@ -1529,6 +1543,7 @@ static void _register_variant_builtin_methods() { /* Rect2i */ + bind_method(Rect2i, get_center, sarray(), varray()); bind_method(Rect2i, get_area, sarray(), varray()); bind_method(Rect2i, has_no_area, sarray(), varray()); bind_method(Rect2i, has_point, sarray("point"), varray()); @@ -1544,13 +1559,13 @@ static void _register_variant_builtin_methods() { /* Vector3 */ - bind_method(Vector3, min_axis, sarray(), varray()); - bind_method(Vector3, max_axis, sarray(), varray()); + bind_method(Vector3, min_axis_index, sarray(), varray()); + bind_method(Vector3, max_axis_index, sarray(), varray()); bind_method(Vector3, angle_to, sarray("to"), varray()); bind_method(Vector3, signed_angle_to, sarray("to", "axis"), varray()); - bind_method(Vector3, direction_to, sarray("b"), varray()); - bind_method(Vector3, distance_to, sarray("b"), varray()); - bind_method(Vector3, distance_squared_to, sarray("b"), varray()); + bind_method(Vector3, direction_to, sarray("to"), varray()); + bind_method(Vector3, distance_to, sarray("to"), varray()); + bind_method(Vector3, distance_squared_to, sarray("to"), varray()); bind_method(Vector3, length, sarray(), varray()); bind_method(Vector3, length_squared, sarray(), varray()); bind_method(Vector3, limit_length, sarray("length"), varray(1.0)); @@ -1579,11 +1594,15 @@ static void _register_variant_builtin_methods() { bind_method(Vector3, bounce, sarray("n"), varray()); bind_method(Vector3, reflect, sarray("n"), varray()); bind_method(Vector3, sign, sarray(), varray()); + bind_method(Vector3, octahedron_encode, sarray(), varray()); + bind_static_method(Vector3, octahedron_decode, sarray("uv"), varray()); /* Vector3i */ - bind_method(Vector3i, min_axis, sarray(), varray()); - bind_method(Vector3i, max_axis, sarray(), varray()); + bind_method(Vector3i, min_axis_index, sarray(), varray()); + bind_method(Vector3i, max_axis_index, sarray(), varray()); + bind_method(Vector3i, length, sarray(), varray()); + bind_method(Vector3i, length_squared, sarray(), varray()); bind_method(Vector3i, sign, sarray(), varray()); bind_method(Vector3i, abs, sarray(), varray()); bind_method(Vector3i, clamp, sarray("min", "max"), varray()); @@ -1609,12 +1628,16 @@ static void _register_variant_builtin_methods() { bind_method(Quaternion, is_normalized, sarray(), varray()); bind_method(Quaternion, is_equal_approx, sarray("to"), varray()); bind_method(Quaternion, inverse, sarray(), varray()); + bind_method(Quaternion, log, sarray(), varray()); + bind_method(Quaternion, exp, sarray(), varray()); bind_method(Quaternion, angle_to, sarray("to"), varray()); bind_method(Quaternion, dot, sarray("with"), varray()); bind_method(Quaternion, slerp, sarray("to", "weight"), varray()); bind_method(Quaternion, slerpni, sarray("to", "weight"), varray()); bind_method(Quaternion, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray()); bind_method(Quaternion, get_euler, sarray(), varray()); + bind_method(Quaternion, get_axis, sarray(), varray()); + bind_method(Quaternion, get_angle, sarray(), varray()); /* Color */ @@ -1624,17 +1647,18 @@ static void _register_variant_builtin_methods() { bind_method(Color, to_argb64, sarray(), varray()); bind_method(Color, to_abgr64, sarray(), varray()); bind_method(Color, to_rgba64, sarray(), varray()); + bind_method(Color, to_html, sarray("with_alpha"), varray(true)); bind_method(Color, clamp, sarray("min", "max"), varray(Color(0, 0, 0, 0), Color(1, 1, 1, 1))); bind_method(Color, inverted, sarray(), varray()); bind_method(Color, lerp, sarray("to", "weight"), varray()); bind_method(Color, lightened, sarray("amount"), varray()); bind_method(Color, darkened, sarray("amount"), varray()); - bind_method(Color, to_html, sarray("with_alpha"), varray(true)); bind_method(Color, blend, sarray("over"), varray()); + bind_method(Color, get_luminance, sarray(), varray()); + bind_method(Color, srgb_to_linear, sarray(), varray()); + bind_method(Color, linear_to_srgb, sarray(), varray()); - // FIXME: Color is immutable, need to probably find a way to do this via constructor - //ADDFUNC4R(COLOR, COLOR, Color, from_hsv, FLOAT, "h", FLOAT, "s", FLOAT, "v", FLOAT, "a", varray(1.0)); bind_method(Color, is_equal_approx, sarray("to"), varray()); bind_static_method(Color, hex, sarray("hex"), varray()); @@ -1646,10 +1670,12 @@ static void _register_variant_builtin_methods() { bind_static_method(Color, get_named_color_name, sarray("idx"), varray()); bind_static_method(Color, get_named_color, sarray("idx"), varray()); bind_static_method(Color, from_string, sarray("str", "default"), varray()); + bind_static_method(Color, from_hsv, sarray("h", "s", "v", "alpha"), varray(1.0)); bind_static_method(Color, from_rgbe9995, sarray("rgbe"), varray()); /* RID */ + bind_method(RID, is_valid, sarray(), varray()); bind_method(RID, get_id, sarray(), varray()); /* NodePath */ @@ -1688,7 +1714,7 @@ static void _register_variant_builtin_methods() { bind_method(Signal, get_object_id, sarray(), varray()); bind_method(Signal, get_name, sarray(), varray()); - bind_method(Signal, connect, sarray("callable", "binds", "flags"), varray(Array(), 0)); + bind_method(Signal, connect, sarray("callable", "flags"), varray(0)); bind_method(Signal, disconnect, sarray("callable"), varray()); bind_method(Signal, is_connected, sarray("callable"), varray()); bind_method(Signal, get_connections, sarray(), varray()); @@ -1702,6 +1728,7 @@ static void _register_variant_builtin_methods() { bind_method(Transform2D, get_rotation, sarray(), varray()); bind_method(Transform2D, get_origin, sarray(), varray()); bind_method(Transform2D, get_scale, sarray(), varray()); + bind_method(Transform2D, get_skew, sarray(), varray()); bind_method(Transform2D, orthonormalized, sarray(), varray()); bind_method(Transform2D, rotated, sarray("phi"), varray()); bind_method(Transform2D, scaled, sarray("scale"), varray()); @@ -1711,6 +1738,8 @@ static void _register_variant_builtin_methods() { bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray()); bind_method(Transform2D, is_equal_approx, sarray("xform"), varray()); bind_method(Transform2D, set_rotation, sarray("rotation"), varray()); + bind_method(Transform2D, set_scale, sarray("scale"), varray()); + bind_method(Transform2D, set_skew, sarray("skew"), varray()); bind_method(Transform2D, looking_at, sarray("target"), varray(Vector2())); /* Basis */ @@ -1722,7 +1751,7 @@ static void _register_variant_builtin_methods() { bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "phi"), varray()); bind_method(Basis, scaled, sarray("scale"), varray()); bind_method(Basis, get_scale, sarray(), varray()); - bind_method(Basis, get_euler, sarray(), varray()); + bind_method(Basis, get_euler, sarray("order"), varray(Basis::EULER_ORDER_YXZ)); bind_method(Basis, tdotx, sarray("with"), varray()); bind_method(Basis, tdoty, sarray("with"), varray()); bind_method(Basis, tdotz, sarray("with"), varray()); @@ -1732,12 +1761,14 @@ static void _register_variant_builtin_methods() { bind_method(Basis, get_rotation_quaternion, sarray(), varray()); bind_static_method(Basis, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); bind_static_method(Basis, from_scale, sarray("scale"), varray()); + bind_static_method(Basis, from_euler, sarray("euler", "order"), varray(Basis::EULER_ORDER_YXZ)); /* AABB */ bind_method(AABB, abs, sarray(), varray()); - bind_method(AABB, get_area, sarray(), varray()); - bind_method(AABB, has_no_area, sarray(), varray()); + bind_method(AABB, get_center, sarray(), varray()); + bind_method(AABB, get_volume, sarray(), varray()); + bind_method(AABB, has_no_volume, sarray(), varray()); bind_method(AABB, has_no_surface, sarray(), varray()); bind_method(AABB, has_point, sarray("point"), varray()); bind_method(AABB, is_equal_approx, sarray("aabb"), varray()); @@ -1768,6 +1799,7 @@ static void _register_variant_builtin_methods() { bind_method(Transform3D, scaled, sarray("scale"), varray()); bind_method(Transform3D, translated, sarray("offset"), varray()); bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); + bind_method(Transform3D, sphere_interpolate_with, sarray("xform", "weight"), varray()); bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray()); bind_method(Transform3D, is_equal_approx, sarray("xform"), varray()); @@ -1797,7 +1829,7 @@ static void _register_variant_builtin_methods() { bind_method(Array, append_array, sarray("array"), varray()); bind_method(Array, resize, sarray("size"), varray()); bind_method(Array, insert, sarray("position", "value"), varray()); - bind_method(Array, remove, sarray("position"), varray()); + bind_method(Array, remove_at, sarray("position"), varray()); bind_method(Array, fill, sarray("value"), varray()); bind_method(Array, erase, sarray("value"), varray()); bind_method(Array, front, sarray(), varray()); @@ -1817,7 +1849,7 @@ static void _register_variant_builtin_methods() { bind_method(Array, bsearch_custom, sarray("value", "func", "before"), varray(true)); bind_method(Array, reverse, sarray(), varray()); bind_method(Array, duplicate, sarray("deep"), varray(false)); - bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(1, false)); + bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(INT_MAX, 1, false)); bind_method(Array, filter, sarray("method"), varray()); bind_method(Array, map, sarray("method"), varray()); bind_method(Array, reduce, sarray("method", "accum"), varray(Variant())); @@ -1831,14 +1863,15 @@ static void _register_variant_builtin_methods() { bind_method(PackedByteArray, push_back, sarray("value"), varray()); bind_method(PackedByteArray, append, sarray("value"), varray()); bind_method(PackedByteArray, append_array, sarray("array"), varray()); - bind_method(PackedByteArray, remove, sarray("index"), varray()); + bind_method(PackedByteArray, remove_at, sarray("index"), varray()); bind_method(PackedByteArray, insert, sarray("at_index", "value"), varray()); bind_method(PackedByteArray, fill, sarray("value"), varray()); bind_method(PackedByteArray, resize, sarray("new_size"), varray()); bind_method(PackedByteArray, has, sarray("value"), varray()); bind_method(PackedByteArray, reverse, sarray(), varray()); - bind_method(PackedByteArray, subarray, sarray("from", "to"), varray()); + bind_method(PackedByteArray, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(PackedByteArray, sort, sarray(), varray()); + bind_method(PackedByteArray, bsearch, sarray("value", "before"), varray(true)); bind_method(PackedByteArray, duplicate, sarray(), varray()); bind_function(PackedByteArray, get_string_from_ascii, _VariantCall::func_PackedByteArray_get_string_from_ascii, sarray(), varray()); @@ -1891,15 +1924,16 @@ static void _register_variant_builtin_methods() { bind_method(PackedInt32Array, push_back, sarray("value"), varray()); bind_method(PackedInt32Array, append, sarray("value"), varray()); bind_method(PackedInt32Array, append_array, sarray("array"), varray()); - bind_method(PackedInt32Array, remove, sarray("index"), varray()); + bind_method(PackedInt32Array, remove_at, sarray("index"), varray()); bind_method(PackedInt32Array, insert, sarray("at_index", "value"), varray()); bind_method(PackedInt32Array, fill, sarray("value"), varray()); bind_method(PackedInt32Array, resize, sarray("new_size"), varray()); bind_method(PackedInt32Array, has, sarray("value"), varray()); bind_method(PackedInt32Array, reverse, sarray(), varray()); - bind_method(PackedInt32Array, subarray, sarray("from", "to"), varray()); + bind_method(PackedInt32Array, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(PackedInt32Array, to_byte_array, sarray(), varray()); bind_method(PackedInt32Array, sort, sarray(), varray()); + bind_method(PackedInt32Array, bsearch, sarray("value", "before"), varray(true)); bind_method(PackedInt32Array, duplicate, sarray(), varray()); /* Int64 Array */ @@ -1910,15 +1944,16 @@ static void _register_variant_builtin_methods() { bind_method(PackedInt64Array, push_back, sarray("value"), varray()); bind_method(PackedInt64Array, append, sarray("value"), varray()); bind_method(PackedInt64Array, append_array, sarray("array"), varray()); - bind_method(PackedInt64Array, remove, sarray("index"), varray()); + bind_method(PackedInt64Array, remove_at, sarray("index"), varray()); bind_method(PackedInt64Array, insert, sarray("at_index", "value"), varray()); bind_method(PackedInt64Array, fill, sarray("value"), varray()); bind_method(PackedInt64Array, resize, sarray("new_size"), varray()); bind_method(PackedInt64Array, has, sarray("value"), varray()); bind_method(PackedInt64Array, reverse, sarray(), varray()); - bind_method(PackedInt64Array, subarray, sarray("from", "to"), varray()); + bind_method(PackedInt64Array, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(PackedInt64Array, to_byte_array, sarray(), varray()); bind_method(PackedInt64Array, sort, sarray(), varray()); + bind_method(PackedInt64Array, bsearch, sarray("value", "before"), varray(true)); bind_method(PackedInt64Array, duplicate, sarray(), varray()); /* Float32 Array */ @@ -1929,15 +1964,16 @@ static void _register_variant_builtin_methods() { bind_method(PackedFloat32Array, push_back, sarray("value"), varray()); bind_method(PackedFloat32Array, append, sarray("value"), varray()); bind_method(PackedFloat32Array, append_array, sarray("array"), varray()); - bind_method(PackedFloat32Array, remove, sarray("index"), varray()); + bind_method(PackedFloat32Array, remove_at, sarray("index"), varray()); bind_method(PackedFloat32Array, insert, sarray("at_index", "value"), varray()); bind_method(PackedFloat32Array, fill, sarray("value"), varray()); bind_method(PackedFloat32Array, resize, sarray("new_size"), varray()); bind_method(PackedFloat32Array, has, sarray("value"), varray()); bind_method(PackedFloat32Array, reverse, sarray(), varray()); - bind_method(PackedFloat32Array, subarray, sarray("from", "to"), varray()); + bind_method(PackedFloat32Array, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(PackedFloat32Array, to_byte_array, sarray(), varray()); bind_method(PackedFloat32Array, sort, sarray(), varray()); + bind_method(PackedFloat32Array, bsearch, sarray("value", "before"), varray(true)); bind_method(PackedFloat32Array, duplicate, sarray(), varray()); /* Float64 Array */ @@ -1948,15 +1984,16 @@ static void _register_variant_builtin_methods() { bind_method(PackedFloat64Array, push_back, sarray("value"), varray()); bind_method(PackedFloat64Array, append, sarray("value"), varray()); bind_method(PackedFloat64Array, append_array, sarray("array"), varray()); - bind_method(PackedFloat64Array, remove, sarray("index"), varray()); + bind_method(PackedFloat64Array, remove_at, sarray("index"), varray()); bind_method(PackedFloat64Array, insert, sarray("at_index", "value"), varray()); bind_method(PackedFloat64Array, fill, sarray("value"), varray()); bind_method(PackedFloat64Array, resize, sarray("new_size"), varray()); bind_method(PackedFloat64Array, has, sarray("value"), varray()); bind_method(PackedFloat64Array, reverse, sarray(), varray()); - bind_method(PackedFloat64Array, subarray, sarray("from", "to"), varray()); + bind_method(PackedFloat64Array, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(PackedFloat64Array, to_byte_array, sarray(), varray()); bind_method(PackedFloat64Array, sort, sarray(), varray()); + bind_method(PackedFloat64Array, bsearch, sarray("value", "before"), varray(true)); bind_method(PackedFloat64Array, duplicate, sarray(), varray()); /* String Array */ @@ -1967,15 +2004,16 @@ static void _register_variant_builtin_methods() { bind_method(PackedStringArray, push_back, sarray("value"), varray()); bind_method(PackedStringArray, append, sarray("value"), varray()); bind_method(PackedStringArray, append_array, sarray("array"), varray()); - bind_method(PackedStringArray, remove, sarray("index"), varray()); + bind_method(PackedStringArray, remove_at, sarray("index"), varray()); bind_method(PackedStringArray, insert, sarray("at_index", "value"), varray()); bind_method(PackedStringArray, fill, sarray("value"), varray()); bind_method(PackedStringArray, resize, sarray("new_size"), varray()); bind_method(PackedStringArray, has, sarray("value"), varray()); bind_method(PackedStringArray, reverse, sarray(), varray()); - bind_method(PackedStringArray, subarray, sarray("from", "to"), varray()); + bind_method(PackedStringArray, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(PackedStringArray, to_byte_array, sarray(), varray()); bind_method(PackedStringArray, sort, sarray(), varray()); + bind_method(PackedStringArray, bsearch, sarray("value", "before"), varray(true)); bind_method(PackedStringArray, duplicate, sarray(), varray()); /* Vector2 Array */ @@ -1986,15 +2024,16 @@ static void _register_variant_builtin_methods() { bind_method(PackedVector2Array, push_back, sarray("value"), varray()); bind_method(PackedVector2Array, append, sarray("value"), varray()); bind_method(PackedVector2Array, append_array, sarray("array"), varray()); - bind_method(PackedVector2Array, remove, sarray("index"), varray()); + bind_method(PackedVector2Array, remove_at, sarray("index"), varray()); bind_method(PackedVector2Array, insert, sarray("at_index", "value"), varray()); bind_method(PackedVector2Array, fill, sarray("value"), varray()); bind_method(PackedVector2Array, resize, sarray("new_size"), varray()); bind_method(PackedVector2Array, has, sarray("value"), varray()); bind_method(PackedVector2Array, reverse, sarray(), varray()); - bind_method(PackedVector2Array, subarray, sarray("from", "to"), varray()); + bind_method(PackedVector2Array, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(PackedVector2Array, to_byte_array, sarray(), varray()); bind_method(PackedVector2Array, sort, sarray(), varray()); + bind_method(PackedVector2Array, bsearch, sarray("value", "before"), varray(true)); bind_method(PackedVector2Array, duplicate, sarray(), varray()); /* Vector3 Array */ @@ -2005,15 +2044,16 @@ static void _register_variant_builtin_methods() { bind_method(PackedVector3Array, push_back, sarray("value"), varray()); bind_method(PackedVector3Array, append, sarray("value"), varray()); bind_method(PackedVector3Array, append_array, sarray("array"), varray()); - bind_method(PackedVector3Array, remove, sarray("index"), varray()); + bind_method(PackedVector3Array, remove_at, sarray("index"), varray()); bind_method(PackedVector3Array, insert, sarray("at_index", "value"), varray()); bind_method(PackedVector3Array, fill, sarray("value"), varray()); bind_method(PackedVector3Array, resize, sarray("new_size"), varray()); bind_method(PackedVector3Array, has, sarray("value"), varray()); bind_method(PackedVector3Array, reverse, sarray(), varray()); - bind_method(PackedVector3Array, subarray, sarray("from", "to"), varray()); + bind_method(PackedVector3Array, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(PackedVector3Array, to_byte_array, sarray(), varray()); bind_method(PackedVector3Array, sort, sarray(), varray()); + bind_method(PackedVector3Array, bsearch, sarray("value", "before"), varray(true)); bind_method(PackedVector3Array, duplicate, sarray(), varray()); /* Color Array */ @@ -2024,15 +2064,16 @@ static void _register_variant_builtin_methods() { bind_method(PackedColorArray, push_back, sarray("value"), varray()); bind_method(PackedColorArray, append, sarray("value"), varray()); bind_method(PackedColorArray, append_array, sarray("array"), varray()); - bind_method(PackedColorArray, remove, sarray("index"), varray()); + bind_method(PackedColorArray, remove_at, sarray("index"), varray()); bind_method(PackedColorArray, insert, sarray("at_index", "value"), varray()); bind_method(PackedColorArray, fill, sarray("value"), varray()); bind_method(PackedColorArray, resize, sarray("new_size"), varray()); bind_method(PackedColorArray, has, sarray("value"), varray()); bind_method(PackedColorArray, reverse, sarray(), varray()); - bind_method(PackedColorArray, subarray, sarray("from", "to"), varray()); + bind_method(PackedColorArray, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(PackedColorArray, to_byte_array, sarray(), varray()); bind_method(PackedColorArray, sort, sarray(), varray()); + bind_method(PackedColorArray, bsearch, sarray("value", "before"), varray(true)); bind_method(PackedColorArray, duplicate, sarray(), varray()); /* Register constants */ @@ -2090,6 +2131,13 @@ static void _register_variant_builtin_methods() { _VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1)); _VariantCall::add_variant_constant(Variant::VECTOR2I, "DOWN", Vector2i(0, 1)); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XYZ", Basis::EULER_ORDER_XYZ); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XZY", Basis::EULER_ORDER_XZY); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YXZ", Basis::EULER_ORDER_YXZ); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YZX", Basis::EULER_ORDER_YZX); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX); + _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/variant_construct.cpp b/core/variant/variant_construct.cpp index a1a2bec369..351f4ae253 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -114,22 +114,24 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Transform2D>>(sarray()); add_constructor<VariantConstructor<Transform2D, Transform2D>>(sarray("from")); add_constructor<VariantConstructor<Transform2D, float, Vector2>>(sarray("rotation", "position")); + add_constructor<VariantConstructor<Transform2D, float, Size2, float, Vector2>>(sarray("rotation", "scale", "skew", "position")); add_constructor<VariantConstructor<Transform2D, Vector2, Vector2, Vector2>>(sarray("x_axis", "y_axis", "origin")); add_constructor<VariantConstructNoArgs<Plane>>(sarray()); add_constructor<VariantConstructor<Plane, Plane>>(sarray("from")); + add_constructor<VariantConstructor<Plane, Vector3>>(sarray("normal")); add_constructor<VariantConstructor<Plane, Vector3, double>>(sarray("normal", "d")); - add_constructor<VariantConstructor<Plane, Vector3, Vector3>>(sarray("point", "normal")); + add_constructor<VariantConstructor<Plane, Vector3, Vector3>>(sarray("normal", "point")); add_constructor<VariantConstructor<Plane, Vector3, Vector3, Vector3>>(sarray("point1", "point2", "point3")); add_constructor<VariantConstructor<Plane, double, double, double, double>>(sarray("a", "b", "c", "d")); add_constructor<VariantConstructNoArgs<Quaternion>>(sarray()); add_constructor<VariantConstructor<Quaternion, Quaternion>>(sarray("from")); add_constructor<VariantConstructor<Quaternion, Basis>>(sarray("from")); - add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler")); add_constructor<VariantConstructor<Quaternion, Vector3, double>>(sarray("axis", "angle")); add_constructor<VariantConstructor<Quaternion, Vector3, Vector3>>(sarray("arc_from", "arc_to")); add_constructor<VariantConstructor<Quaternion, double, double, double, double>>(sarray("x", "y", "z", "w")); + add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler_yxz")); add_constructor<VariantConstructNoArgs<::AABB>>(sarray()); add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from")); @@ -138,7 +140,6 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Basis>>(sarray()); add_constructor<VariantConstructor<Basis, Basis>>(sarray("from")); add_constructor<VariantConstructor<Basis, Quaternion>>(sarray("from")); - add_constructor<VariantConstructor<Basis, Vector3>>(sarray("euler")); add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "phi")); add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis")); diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h index b03f4a8d3b..ce2e9af04f 100644 --- a/core/variant/variant_construct.h +++ b/core/variant/variant_construct.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -543,14 +543,12 @@ public: class VariantConstructNoArgsObject { public: static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantInternal::clear(&r_ret); - VariantInternal::object_assign_null(&r_ret); + r_ret = (Object *)nullptr; // Must construct a TYPE_OBJECT containing nullptr. r_error.error = Callable::CallError::CALL_OK; } static inline void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - VariantInternal::object_assign_null(r_ret); + *r_ret = (Object *)nullptr; // Must construct a TYPE_OBJECT containing nullptr. } static void ptr_construct(void *base, const void **p_args) { PtrConstruct<Object *>::construct(nullptr, base); diff --git a/core/variant/variant_destruct.cpp b/core/variant/variant_destruct.cpp index 366b71df3a..ab8303f3ae 100644 --- a/core/variant/variant_destruct.cpp +++ b/core/variant/variant_destruct.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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/variant/variant_destruct.h b/core/variant/variant_destruct.h index 7356e42201..5e3478635d 100644 --- a/core/variant/variant_destruct.h +++ b/core/variant/variant_destruct.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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/variant/variant_internal.h b/core/variant/variant_internal.h index 40c8a1bfde..3696ffae60 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -111,6 +111,10 @@ public: } } + _FORCE_INLINE_ static bool initialize_ref(Object *object) { + return Variant::initialize_ref(object); + } + // Atomic types. _FORCE_INLINE_ static bool *get_bool(Variant *v) { return &v->_data._bool; } _FORCE_INLINE_ static const bool *get_bool(const Variant *v) { return &v->_data._bool; } @@ -753,8 +757,20 @@ VARIANT_ACCESSOR_NUMBER(uint32_t) VARIANT_ACCESSOR_NUMBER(int64_t) VARIANT_ACCESSOR_NUMBER(uint64_t) VARIANT_ACCESSOR_NUMBER(char32_t) + +// Bind enums to allow using them as return types. VARIANT_ACCESSOR_NUMBER(Error) VARIANT_ACCESSOR_NUMBER(Side) +VARIANT_ACCESSOR_NUMBER(Vector2::Axis) +VARIANT_ACCESSOR_NUMBER(Vector2i::Axis) +VARIANT_ACCESSOR_NUMBER(Vector3::Axis) +VARIANT_ACCESSOR_NUMBER(Vector3i::Axis) + +template <> +struct VariantInternalAccessor<Basis::EulerOrder> { + static _FORCE_INLINE_ Basis::EulerOrder get(const Variant *v) { return Basis::EulerOrder(*VariantInternal::get_int(v)); } + static _FORCE_INLINE_ void set(Variant *v, Basis::EulerOrder p_value) { *VariantInternal::get_int(v) = p_value; } +}; template <> struct VariantInternalAccessor<ObjectID> { @@ -1014,6 +1030,10 @@ INITIALIZER_INT(int64_t) INITIALIZER_INT(char32_t) INITIALIZER_INT(Error) INITIALIZER_INT(ObjectID) +INITIALIZER_INT(Vector2::Axis) +INITIALIZER_INT(Vector2i::Axis) +INITIALIZER_INT(Vector3::Axis) +INITIALIZER_INT(Vector3i::Axis) template <> struct VariantInitializer<double> { @@ -1301,12 +1321,12 @@ struct VariantZeroAssigner<Signal> { template <> struct VariantZeroAssigner<Dictionary> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_dictionary(v) = Dictionary(); } }; template <> struct VariantZeroAssigner<Array> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_array(v) = Array(); } }; template <> @@ -1414,10 +1434,15 @@ struct VariantTypeConstructor<Object *> { _FORCE_INLINE_ static void variant_from_type(void *p_variant, void *p_value) { Variant *variant = reinterpret_cast<Variant *>(p_variant); VariantInitializer<Object *>::init(variant); - Object *value = *(reinterpret_cast<Object **>(p_value)); - if (value) { - VariantInternalAccessor<Object *>::set(variant, value); - VariantInternalAccessor<ObjectID>::set(variant, value->get_instance_id()); + Object *object = *(reinterpret_cast<Object **>(p_value)); + if (object) { + if (object->is_ref_counted()) { + if (!VariantInternal::initialize_ref(object)) { + return; + } + } + VariantInternalAccessor<Object *>::set(variant, object); + VariantInternalAccessor<ObjectID>::set(variant, object->get_instance_id()); } } diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index b94588f480..35e0319aa3 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -45,6 +45,126 @@ void register_op(Variant::Operator p_op, Variant::Type p_type_a, Variant::Type p ptr_operator_evaluator_table[p_op][p_type_a][p_type_b] = T::ptr_evaluate; } +// Special cases that can't be done otherwise because of the forced casting to float. + +template <> +class OperatorEvaluatorMul<Vector2, Vector2i, double> { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector2i &a = *VariantGetInternalPtr<Vector2i>::get_ptr(&p_left); + const double &b = *VariantGetInternalPtr<double>::get_ptr(&p_right); + *r_ret = Vector2(a.x, a.y) * b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<Vector2>::get_ptr(r_ret) = Vector2(VariantGetInternalPtr<Vector2i>::get_ptr(left)->x, VariantGetInternalPtr<Vector2i>::get_ptr(left)->y) * *VariantGetInternalPtr<double>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<Vector2>::encode(Vector2(PtrToArg<Vector2i>::convert(left).x, PtrToArg<Vector2i>::convert(left).y) * PtrToArg<double>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<Vector2>::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorMul<Vector2, double, Vector2i> { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector2i &a = *VariantGetInternalPtr<Vector2i>::get_ptr(&p_right); + const double &b = *VariantGetInternalPtr<double>::get_ptr(&p_left); + *r_ret = Vector2(a.x, a.y) * b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<Vector2>::get_ptr(r_ret) = Vector2(VariantGetInternalPtr<Vector2i>::get_ptr(right)->x, VariantGetInternalPtr<Vector2i>::get_ptr(right)->y) * *VariantGetInternalPtr<double>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<Vector2>::encode(Vector2(PtrToArg<Vector2i>::convert(right).x, PtrToArg<Vector2i>::convert(right).y) * PtrToArg<double>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<Vector2>::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorDivNZ<Vector2, Vector2i, double> { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector2i &a = *VariantGetInternalPtr<Vector2i>::get_ptr(&p_left); + const double &b = *VariantGetInternalPtr<double>::get_ptr(&p_right); + if (unlikely(b == 0)) { + r_valid = false; + *r_ret = "Division by zero error"; + return; + } + *r_ret = Vector2(a.x, a.y) / b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<Vector2>::get_ptr(r_ret) = Vector2(VariantGetInternalPtr<Vector2i>::get_ptr(left)->x, VariantGetInternalPtr<Vector2i>::get_ptr(left)->y) / *VariantGetInternalPtr<double>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<Vector2>::encode(Vector2(PtrToArg<Vector2i>::convert(left).x, PtrToArg<Vector2i>::convert(left).y) / PtrToArg<double>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<Vector2>::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorMul<Vector3, Vector3i, double> { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector3i &a = *VariantGetInternalPtr<Vector3i>::get_ptr(&p_left); + const double &b = *VariantGetInternalPtr<double>::get_ptr(&p_right); + *r_ret = Vector3(a.x, a.y, a.z) * b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<Vector3>::get_ptr(r_ret) = Vector3(VariantGetInternalPtr<Vector3i>::get_ptr(left)->x, VariantGetInternalPtr<Vector3i>::get_ptr(left)->y, VariantGetInternalPtr<Vector3i>::get_ptr(left)->z) * *VariantGetInternalPtr<double>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<Vector3>::encode(Vector3(PtrToArg<Vector3i>::convert(left).x, PtrToArg<Vector3i>::convert(left).y, PtrToArg<Vector3i>::convert(left).z) * PtrToArg<double>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<Vector3>::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorMul<Vector3, double, Vector3i> { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector3i &a = *VariantGetInternalPtr<Vector3i>::get_ptr(&p_right); + const double &b = *VariantGetInternalPtr<double>::get_ptr(&p_left); + *r_ret = Vector3(a.x, a.y, a.z) * b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<Vector3>::get_ptr(r_ret) = Vector3(VariantGetInternalPtr<Vector3i>::get_ptr(right)->x, VariantGetInternalPtr<Vector3i>::get_ptr(right)->y, VariantGetInternalPtr<Vector3i>::get_ptr(right)->z) * *VariantGetInternalPtr<double>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<Vector3>::encode(Vector3(PtrToArg<Vector3i>::convert(right).x, PtrToArg<Vector3i>::convert(right).y, PtrToArg<Vector3i>::convert(right).z) * PtrToArg<double>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<Vector3>::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorDivNZ<Vector3, Vector3i, double> { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector3i &a = *VariantGetInternalPtr<Vector3i>::get_ptr(&p_left); + const double &b = *VariantGetInternalPtr<double>::get_ptr(&p_right); + if (unlikely(b == 0)) { + r_valid = false; + *r_ret = "Division by zero error"; + return; + } + *r_ret = Vector3(a.x, a.y, a.z) / b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<Vector3>::get_ptr(r_ret) = Vector3(VariantGetInternalPtr<Vector3i>::get_ptr(left)->x, VariantGetInternalPtr<Vector3i>::get_ptr(left)->y, VariantGetInternalPtr<Vector3i>::get_ptr(left)->z) / *VariantGetInternalPtr<double>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<Vector3>::encode(Vector3(PtrToArg<Vector3i>::convert(left).x, PtrToArg<Vector3i>::convert(left).y, PtrToArg<Vector3i>::convert(left).z) / PtrToArg<double>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<Vector3>::VARIANT_TYPE; } +}; + void Variant::_register_variant_operators() { memset(operator_return_type_table, 0, sizeof(operator_return_type_table)); memset(operator_evaluator_table, 0, sizeof(operator_evaluator_table)); @@ -56,6 +176,8 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorAdd<double, double, int64_t>>(Variant::OP_ADD, Variant::FLOAT, Variant::INT); register_op<OperatorEvaluatorAdd<double, double, double>>(Variant::OP_ADD, Variant::FLOAT, Variant::FLOAT); register_op<OperatorEvaluatorAdd<String, String, String>>(Variant::OP_ADD, Variant::STRING, Variant::STRING); + register_op<OperatorEvaluatorAdd<String, char32_t, String>>(Variant::OP_ADD, Variant::INT, Variant::STRING); + register_op<OperatorEvaluatorAdd<String, String, char32_t>>(Variant::OP_ADD, Variant::STRING, Variant::INT); register_op<OperatorEvaluatorAdd<Vector2, Vector2, Vector2>>(Variant::OP_ADD, Variant::VECTOR2, Variant::VECTOR2); register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3); @@ -94,9 +216,9 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorMul<double, double, double>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::FLOAT); register_op<OperatorEvaluatorMul<double, double, int64_t>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::INT); register_op<OperatorEvaluatorMul<Vector2, double, Vector2>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR2); - register_op<OperatorEvaluatorMul<Vector2i, double, Vector2i>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR2I); + register_op<OperatorEvaluatorMul<Vector2, double, Vector2i>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR2I); register_op<OperatorEvaluatorMul<Vector3, double, Vector3>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR3); - register_op<OperatorEvaluatorMul<Vector3i, double, Vector3i>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR3I); + register_op<OperatorEvaluatorMul<Vector3, double, Vector3i>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR3I); register_op<OperatorEvaluatorMul<Vector2, Vector2, Vector2>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::VECTOR2); register_op<OperatorEvaluatorMul<Vector2, Vector2, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::INT); @@ -104,7 +226,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorMul<Vector2i, Vector2i, Vector2i>>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorMul<Vector2i, Vector2i, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::INT); - register_op<OperatorEvaluatorMul<Vector2i, Vector2i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::FLOAT); + register_op<OperatorEvaluatorMul<Vector2, Vector2i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::FLOAT); register_op<OperatorEvaluatorMul<Vector3, Vector3, Vector3>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::VECTOR3); register_op<OperatorEvaluatorMul<Vector3, Vector3, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::INT); @@ -112,7 +234,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorMul<Vector3i, Vector3i, Vector3i>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::VECTOR3I); register_op<OperatorEvaluatorMul<Vector3i, Vector3i, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::INT); - register_op<OperatorEvaluatorMul<Vector3i, Vector3i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::FLOAT); + register_op<OperatorEvaluatorMul<Vector3, Vector3i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::FLOAT); register_op<OperatorEvaluatorMul<Quaternion, Quaternion, Quaternion>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorMul<Quaternion, Quaternion, int64_t>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT); @@ -172,7 +294,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorDiv<Vector2, Vector2, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT); register_op<OperatorEvaluatorDivNZ<Vector2i, Vector2i, Vector2i>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::VECTOR2I); - register_op<OperatorEvaluatorDivNZ<Vector2i, Vector2i, double>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::FLOAT); + register_op<OperatorEvaluatorDivNZ<Vector2, Vector2i, double>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::FLOAT); register_op<OperatorEvaluatorDivNZ<Vector2i, Vector2i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::INT); register_op<OperatorEvaluatorDiv<Vector2, Vector2, Vector2>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2); @@ -184,7 +306,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorDiv<Vector3, Vector3, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::INT); register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, Vector3i>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::VECTOR3I); - register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, double>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::FLOAT); + register_op<OperatorEvaluatorDivNZ<Vector3, Vector3i, double>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::FLOAT); register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::INT); register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, double>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::FLOAT); @@ -502,6 +624,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorLess<double, int64_t>>(Variant::OP_LESS, Variant::FLOAT, Variant::INT); register_op<OperatorEvaluatorLess<double, double>>(Variant::OP_LESS, Variant::FLOAT, Variant::FLOAT); register_op<OperatorEvaluatorLess<String, String>>(Variant::OP_LESS, Variant::STRING, Variant::STRING); + register_op<OperatorEvaluatorLess<StringName, StringName>>(Variant::OP_LESS, Variant::STRING_NAME, Variant::STRING_NAME); register_op<OperatorEvaluatorLess<Vector2, Vector2>>(Variant::OP_LESS, Variant::VECTOR2, Variant::VECTOR2); register_op<OperatorEvaluatorLess<Vector2i, Vector2i>>(Variant::OP_LESS, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorLess<Vector3, Vector3>>(Variant::OP_LESS, Variant::VECTOR3, Variant::VECTOR3); @@ -514,6 +637,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorLessEqual<double, int64_t>>(Variant::OP_LESS_EQUAL, Variant::FLOAT, Variant::INT); register_op<OperatorEvaluatorLessEqual<double, double>>(Variant::OP_LESS_EQUAL, Variant::FLOAT, Variant::FLOAT); register_op<OperatorEvaluatorLessEqual<String, String>>(Variant::OP_LESS_EQUAL, Variant::STRING, Variant::STRING); + register_op<OperatorEvaluatorLessEqual<StringName, StringName>>(Variant::OP_LESS_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME); register_op<OperatorEvaluatorLessEqual<Vector2, Vector2>>(Variant::OP_LESS_EQUAL, Variant::VECTOR2, Variant::VECTOR2); register_op<OperatorEvaluatorLessEqual<Vector2i, Vector2i>>(Variant::OP_LESS_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorLessEqual<Vector3, Vector3>>(Variant::OP_LESS_EQUAL, Variant::VECTOR3, Variant::VECTOR3); @@ -527,6 +651,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorGreater<double, int64_t>>(Variant::OP_GREATER, Variant::FLOAT, Variant::INT); register_op<OperatorEvaluatorGreater<double, double>>(Variant::OP_GREATER, Variant::FLOAT, Variant::FLOAT); register_op<OperatorEvaluatorGreater<String, String>>(Variant::OP_GREATER, Variant::STRING, Variant::STRING); + register_op<OperatorEvaluatorGreater<StringName, StringName>>(Variant::OP_GREATER, Variant::STRING_NAME, Variant::STRING_NAME); register_op<OperatorEvaluatorGreater<Vector2, Vector2>>(Variant::OP_GREATER, Variant::VECTOR2, Variant::VECTOR2); register_op<OperatorEvaluatorGreater<Vector2i, Vector2i>>(Variant::OP_GREATER, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorGreater<Vector3, Vector3>>(Variant::OP_GREATER, Variant::VECTOR3, Variant::VECTOR3); @@ -539,6 +664,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorGreaterEqual<double, int64_t>>(Variant::OP_GREATER_EQUAL, Variant::FLOAT, Variant::INT); register_op<OperatorEvaluatorGreaterEqual<double, double>>(Variant::OP_GREATER_EQUAL, Variant::FLOAT, Variant::FLOAT); register_op<OperatorEvaluatorGreaterEqual<String, String>>(Variant::OP_GREATER_EQUAL, Variant::STRING, Variant::STRING); + register_op<OperatorEvaluatorGreaterEqual<StringName, StringName>>(Variant::OP_GREATER_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME); register_op<OperatorEvaluatorGreaterEqual<Vector2, Vector2>>(Variant::OP_GREATER_EQUAL, Variant::VECTOR2, Variant::VECTOR2); register_op<OperatorEvaluatorGreaterEqual<Vector2i, Vector2i>>(Variant::OP_GREATER_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorGreaterEqual<Vector3, Vector3>>(Variant::OP_GREATER_EQUAL, Variant::VECTOR3, Variant::VECTOR3); @@ -641,7 +767,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNotFloat>(Variant::OP_NOT, Variant::FLOAT, Variant::NIL); register_op<OperatorEvaluatorNotObject>(Variant::OP_NOT, Variant::OBJECT, Variant::NIL); - register_op<OperatorEvaluatorInStringFind>(Variant::OP_IN, Variant::STRING, Variant::STRING); + register_op<OperatorEvaluatorInStringFind<String>>(Variant::OP_IN, Variant::STRING, Variant::STRING); + register_op<OperatorEvaluatorInStringFind<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::STRING); + register_op<OperatorEvaluatorInStringNameFind<String>>(Variant::OP_IN, Variant::STRING, Variant::STRING_NAME); + register_op<OperatorEvaluatorInStringNameFind<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::STRING_NAME); register_op<OperatorEvaluatorInDictionaryHasNil>(Variant::OP_IN, Variant::NIL, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<bool>>(Variant::OP_IN, Variant::BOOL, Variant::DICTIONARY); diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h index 3c9f849a4f..f72a92d31a 100644 --- a/core/variant/variant_op.h +++ b/core/variant/variant_op.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -775,6 +775,7 @@ public: r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *r_ret = Array(); _add_arrays(*VariantGetInternalPtr<Array>::get_ptr(r_ret), *VariantGetInternalPtr<Array>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right)); } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -1213,22 +1214,44 @@ public: //// +template <class Left> class OperatorEvaluatorInStringFind { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &str_a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(&p_left); const String &str_b = *VariantGetInternalPtr<String>::get_ptr(&p_right); *r_ret = str_b.find(str_a) != -1; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const String &str_a = *VariantGetInternalPtr<String>::get_ptr(left); + const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(left); const String &str_b = *VariantGetInternalPtr<String>::get_ptr(right); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<String>::convert(right).find(PtrToArg<String>::convert(left)) != -1, r_ret); + PtrToArg<bool>::encode(PtrToArg<String>::convert(right).find(PtrToArg<Left>::convert(left)) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class Left> +class OperatorEvaluatorInStringNameFind { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(&p_left); + const String str_b = VariantGetInternalPtr<StringName>::get_ptr(&p_right)->operator String(); + + *r_ret = str_b.find(str_a) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(left); + const String str_b = VariantGetInternalPtr<StringName>::get_ptr(right)->operator String(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<StringName>::convert(right).operator String().find(PtrToArg<Left>::convert(left)) != -1, r_ret); } static Variant::Type get_return_type() { return Variant::BOOL; } }; diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index a214a238a6..5fc6df8f39 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -90,6 +90,17 @@ const char *VariantParser::tk_name[TK_MAX] = { "ERROR" }; +static double stor_fix(const String &p_str) { + if (p_str == "inf") { + return INFINITY; + } else if (p_str == "inf_neg") { + return -INFINITY; + } else if (p_str == "nan") { + return NAN; + } + return -1; +} + Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, String &r_err_str) { bool string_name = false; @@ -177,7 +188,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri if (p_stream->is_eof()) { r_token.type = TK_EOF; return OK; - } else if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) { + } else if (is_hex_digit(ch)) { color_str += ch; } else { @@ -206,6 +217,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri } case '"': { String str; + char32_t prev = 0; while (true) { char32_t ch = p_stream->get_char(); @@ -241,22 +253,25 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri case 'r': res = 13; break; + case 'U': case 'u': { - //hex number - for (int j = 0; j < 4; j++) { + // Hexadecimal sequence. + int hex_len = (next == 'U') ? 6 : 4; + for (int j = 0; j < hex_len; j++) { char32_t c = p_stream->get_char(); + if (c == 0) { r_err_str = "Unterminated String"; r_token.type = TK_ERROR; return ERR_PARSE_ERROR; } - if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) { + if (!is_hex_digit(c)) { r_err_str = "Malformed hex constant in string"; r_token.type = TK_ERROR; return ERR_PARSE_ERROR; } char32_t v; - if (c >= '0' && c <= '9') { + if (is_digit(c)) { v = c - '0'; } else if (c >= 'a' && c <= 'f') { v = c - 'a'; @@ -279,15 +294,49 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri } break; } + // Parse UTF-16 pair. + if ((res & 0xfffffc00) == 0xd800) { + if (prev == 0) { + prev = res; + continue; + } else { + r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate"; + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } + } else if ((res & 0xfffffc00) == 0xdc00) { + if (prev == 0) { + r_err_str = "Invalid UTF-16 sequence in string, unpaired trail surrogate"; + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } else { + res = (prev << 10UL) + res - ((0xd800 << 10UL) + 0xdc00 - 0x10000); + prev = 0; + } + } + if (prev != 0) { + r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate"; + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } str += res; - } else { + if (prev != 0) { + r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate"; + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } if (ch == '\n') { line++; } str += ch; } } + if (prev != 0) { + r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate"; + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } if (p_stream->is_utf8()) { str.parse_utf8(str.ascii(true).get_data()); @@ -295,7 +344,6 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri 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; @@ -332,7 +380,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri while (true) { switch (reading) { case READING_INT: { - if (c >= '0' && c <= '9') { + if (is_digit(c)) { //pass } else if (c == '.') { reading = READING_DEC; @@ -346,7 +394,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri } break; case READING_DEC: { - if (c >= '0' && c <= '9') { + if (is_digit(c)) { } else if (c == 'e') { reading = READING_EXP; } else { @@ -355,7 +403,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri } break; case READING_EXP: { - if (c >= '0' && c <= '9') { + if (is_digit(c)) { exp_beg = true; } else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) { @@ -384,11 +432,11 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri r_token.value = num.as_int(); } return OK; - } else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') { + } else if (is_ascii_char(cchar) || is_underscore(cchar)) { StringBuffer<> id; bool first = true; - while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) { + while (is_ascii_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) { id += cchar; cchar = p_stream->get_char(); first = false; @@ -469,8 +517,19 @@ Error VariantParser::_parse_construct(Stream *p_stream, Vector<T> &r_construct, if (first && token.type == TK_PARENTHESIS_CLOSE) { break; } else if (token.type != TK_NUMBER) { - r_err_str = "Expected float in constructor"; - return ERR_PARSE_ERROR; + bool valid = false; + if (token.type == TK_IDENTIFIER) { + double real = stor_fix(token.value); + if (real != -1) { + token.type = TK_NUMBER; + token.value = real; + valid = true; + } + } + if (!valid) { + r_err_str = "Expected float in constructor"; + return ERR_PARSE_ERROR; + } } r_construct.push_back(token.value); @@ -507,6 +566,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, value = Variant(); } else if (id == "inf") { value = INFINITY; + } else if (id == "inf_neg") { + value = -INFINITY; } else if (id == "nan") { value = NAN; } else if (id == "Vector2") { @@ -1401,17 +1462,25 @@ Error VariantParser::parse(Stream *p_stream, Variant &r_ret, String &r_err_str, ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// -static String rtosfix(double p_value) { +static String rtos_fix(double p_value) { if (p_value == 0.0) { return "0"; //avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist. + } else if (isnan(p_value)) { + return "nan"; + } else if (isinf(p_value)) { + if (p_value > 0) { + return "inf"; + } else { + return "inf_neg"; + } } else { return rtoss(p_value); } } -Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud) { +Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int recursion_count) { switch (p_variant.get_type()) { case Variant::NIL: { p_store_string_func(p_store_string_ud, "null"); @@ -1423,9 +1492,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, itos(p_variant.operator int64_t())); } break; case Variant::FLOAT: { - String s = rtosfix(p_variant.operator double()); - if (s != "inf" && s != "nan") { - if (s.find(".") == -1 && s.find("e") == -1) { + String s = rtos_fix(p_variant.operator double()); + if (s != "inf" && s != "inf_neg" && s != "nan") { + if (!s.contains(".") && !s.contains("e")) { s += ".0"; } } @@ -1439,7 +1508,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::VECTOR2: { Vector2 v = p_variant; - p_store_string_func(p_store_string_ud, "Vector2(" + rtosfix(v.x) + ", " + rtosfix(v.y) + ")"); + p_store_string_func(p_store_string_ud, "Vector2(" + rtos_fix(v.x) + ", " + rtos_fix(v.y) + ")"); } break; case Variant::VECTOR2I: { Vector2i v = p_variant; @@ -1447,7 +1516,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } 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) + ")"); + p_store_string_func(p_store_string_ud, "Rect2(" + rtos_fix(aabb.position.x) + ", " + rtos_fix(aabb.position.y) + ", " + rtos_fix(aabb.size.x) + ", " + rtos_fix(aabb.size.y) + ")"); } break; case Variant::RECT2I: { @@ -1457,7 +1526,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } 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) + ")"); + p_store_string_func(p_store_string_ud, "Vector3(" + rtos_fix(v.x) + ", " + rtos_fix(v.y) + ", " + rtos_fix(v.z) + ")"); } break; case Variant::VECTOR3I: { Vector3i v = p_variant; @@ -1465,17 +1534,17 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::PLANE: { Plane p = p_variant; - p_store_string_func(p_store_string_ud, "Plane(" + rtosfix(p.normal.x) + ", " + rtosfix(p.normal.y) + ", " + rtosfix(p.normal.z) + ", " + rtosfix(p.d) + ")"); + p_store_string_func(p_store_string_ud, "Plane(" + rtos_fix(p.normal.x) + ", " + rtos_fix(p.normal.y) + ", " + rtos_fix(p.normal.z) + ", " + rtos_fix(p.d) + ")"); } break; case Variant::AABB: { AABB aabb = p_variant; - p_store_string_func(p_store_string_ud, "AABB(" + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.position.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + ")"); + p_store_string_func(p_store_string_ud, "AABB(" + rtos_fix(aabb.position.x) + ", " + rtos_fix(aabb.position.y) + ", " + rtos_fix(aabb.position.z) + ", " + rtos_fix(aabb.size.x) + ", " + rtos_fix(aabb.size.y) + ", " + rtos_fix(aabb.size.z) + ")"); } break; case Variant::QUATERNION: { Quaternion quaternion = p_variant; - p_store_string_func(p_store_string_ud, "Quaternion(" + rtosfix(quaternion.x) + ", " + rtosfix(quaternion.y) + ", " + rtosfix(quaternion.z) + ", " + rtosfix(quaternion.w) + ")"); + p_store_string_func(p_store_string_ud, "Quaternion(" + rtos_fix(quaternion.x) + ", " + rtos_fix(quaternion.y) + ", " + rtos_fix(quaternion.z) + ", " + rtos_fix(quaternion.w) + ")"); } break; case Variant::TRANSFORM2D: { @@ -1486,7 +1555,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i != 0 || j != 0) { s += ", "; } - s += rtosfix(m3.elements[i][j]); + s += rtos_fix(m3.elements[i][j]); } } @@ -1501,7 +1570,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i != 0 || j != 0) { s += ", "; } - s += rtosfix(m3.elements[i][j]); + s += rtos_fix(m3.elements[i][j]); } } @@ -1517,11 +1586,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i != 0 || j != 0) { s += ", "; } - s += rtosfix(m3.elements[i][j]); + s += rtos_fix(m3.elements[i][j]); } } - s = s + ", " + rtosfix(t.origin.x) + ", " + rtosfix(t.origin.y) + ", " + rtosfix(t.origin.z); + s = s + ", " + rtos_fix(t.origin.x) + ", " + rtos_fix(t.origin.y) + ", " + rtos_fix(t.origin.z); p_store_string_func(p_store_string_ud, s + ")"); } break; @@ -1529,7 +1598,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str // misc types case Variant::COLOR: { Color c = p_variant; - p_store_string_func(p_store_string_ud, "Color(" + rtosfix(c.r) + ", " + rtosfix(c.g) + ", " + rtosfix(c.b) + ", " + rtosfix(c.a) + ")"); + p_store_string_func(p_store_string_ud, "Color(" + rtos_fix(c.r) + ", " + rtos_fix(c.g) + ", " + rtos_fix(c.b) + ", " + rtos_fix(c.a) + ")"); } break; case Variant::STRING_NAME: { @@ -1566,14 +1635,14 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } //try path because it's a file - if (res_text == String() && res->get_path().is_resource_file()) { + if (res_text.is_empty() && res->get_path().is_resource_file()) { //external resource String path = res->get_path(); res_text = "Resource(\"" + path + "\")"; } //could come up with some sort of text - if (res_text != String()) { + if (!res_text.is_empty()) { p_store_string_func(p_store_string_ud, res_text); break; } @@ -1607,41 +1676,57 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str case Variant::DICTIONARY: { Dictionary dict = p_variant; + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + p_store_string_func(p_store_string_ud, "{}"); + } else { + recursion_count++; - List<Variant> keys; - dict.get_key_list(&keys); - keys.sort(); + List<Variant> keys; + dict.get_key_list(&keys); + keys.sort(); - p_store_string_func(p_store_string_ud, "{\n"); - for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - /* - if (!_check_type(dict[E])) - continue; - */ - write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); - p_store_string_func(p_store_string_ud, ": "); - write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); - if (E->next()) { - p_store_string_func(p_store_string_ud, ",\n"); - } else { - p_store_string_func(p_store_string_ud, "\n"); + if (keys.is_empty()) { // Avoid unnecessary line break. + p_store_string_func(p_store_string_ud, "{}"); + break; } - } - p_store_string_func(p_store_string_ud, "}"); + p_store_string_func(p_store_string_ud, "{\n"); + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { + write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, recursion_count); + p_store_string_func(p_store_string_ud, ": "); + write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, recursion_count); + if (E->next()) { + p_store_string_func(p_store_string_ud, ",\n"); + } else { + p_store_string_func(p_store_string_ud, "\n"); + } + } + + p_store_string_func(p_store_string_ud, "}"); + } } break; + case Variant::ARRAY: { - p_store_string_func(p_store_string_ud, "["); - Array array = p_variant; - int len = array.size(); - for (int i = 0; i < len; i++) { - if (i > 0) { - p_store_string_func(p_store_string_ud, ", "); + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + p_store_string_func(p_store_string_ud, "[]"); + } else { + recursion_count++; + + p_store_string_func(p_store_string_ud, "["); + Array array = p_variant; + int len = array.size(); + for (int i = 0; i < len; i++) { + if (i > 0) { + p_store_string_func(p_store_string_ud, ", "); + } + write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, recursion_count); } - write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); + + p_store_string_func(p_store_string_ud, "]"); } - p_store_string_func(p_store_string_ud, "]"); } break; @@ -1707,7 +1792,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i])); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i])); } p_store_string_func(p_store_string_ud, ")"); @@ -1723,7 +1808,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i])); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i])); } p_store_string_func(p_store_string_ud, ")"); @@ -1759,7 +1844,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y)); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x) + ", " + rtos_fix(ptr[i].y)); } p_store_string_func(p_store_string_ud, ")"); @@ -1775,7 +1860,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y) + ", " + rtosfix(ptr[i].z)); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x) + ", " + rtos_fix(ptr[i].y) + ", " + rtos_fix(ptr[i].z)); } p_store_string_func(p_store_string_ud, ")"); @@ -1792,7 +1877,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i].r) + ", " + rtosfix(ptr[i].g) + ", " + rtosfix(ptr[i].b) + ", " + rtosfix(ptr[i].a)); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].r) + ", " + rtos_fix(ptr[i].g) + ", " + rtos_fix(ptr[i].b) + ", " + rtos_fix(ptr[i].a)); } p_store_string_func(p_store_string_ud, ")"); diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index 1ba26db6ed..07d89d30cb 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -49,11 +49,11 @@ public: }; struct StreamFile : public Stream { - FileAccess *f = nullptr; + Ref<FileAccess> f; - virtual char32_t get_char(); - virtual bool is_utf8() const; - virtual bool is_eof() const; + virtual char32_t get_char() override; + virtual bool is_utf8() const override; + virtual bool is_eof() const override; StreamFile() {} }; @@ -62,9 +62,9 @@ public: String s; int pos = 0; - virtual char32_t get_char(); - virtual bool is_utf8() const; - virtual bool is_eof() const; + virtual char32_t get_char() override; + virtual bool is_utf8() const override; + virtual bool is_eof() const override; StreamString() {} }; @@ -140,7 +140,7 @@ public: typedef Error (*StoreStringFunc)(void *ud, const String &p_string); typedef String (*EncodeResourceFunc)(void *ud, const RES &p_resource); - static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud); + static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int recursion_count = 0); static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr); }; diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 3bba68d75e..705aa27be6 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -239,7 +239,8 @@ void Variant::set_named(const StringName &p_member, const Variant &p_value, bool *v = p_value; r_valid = true; } else { - r_valid = false; + VariantGetInternalPtr<Dictionary>::get_ptr(this)->operator[](p_member) = p_value; + r_valid = true; } } else { @@ -703,7 +704,7 @@ struct VariantIndexedSetGet_String { String *b = VariantGetInternalPtr<String>::get_ptr(base); const String *v = VariantInternal::get_string(value); if (v->length() == 0) { - b->remove(index); + b->remove_at(index); } else { b->set(index, v->get(0)); } @@ -722,7 +723,7 @@ struct VariantIndexedSetGet_String { String *b = VariantGetInternalPtr<String>::get_ptr(base); const String *v = VariantInternal::get_string(value); if (v->length() == 0) { - b->remove(index); + b->remove_at(index); } else { b->set(index, v->get(0)); } @@ -737,7 +738,7 @@ struct VariantIndexedSetGet_String { OOB_TEST(index, v.length()); const String &m = *reinterpret_cast<const String *>(member); if (unlikely(m.length() == 0)) { - v.remove(index); + v.remove_at(index); } else { v.set(index, m.unicode_at(0)); } @@ -1276,7 +1277,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { 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); + Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->_iter_init, refp, 1, ce); if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) { valid = false; @@ -1503,7 +1504,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { 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); + Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->_iter_next, refp, 1, ce); if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) { valid = false; @@ -1685,7 +1686,7 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { 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); + Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->_iter_get, refp, 1, ce); if (ce.error != Callable::CallError::CALL_OK) { r_valid = false; @@ -1823,11 +1824,15 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { return Variant(); } -Variant Variant::duplicate(bool deep) const { +Variant Variant::duplicate(bool p_deep) const { + return recursive_duplicate(p_deep, 0); +} + +Variant Variant::recursive_duplicate(bool p_deep, int recursion_count) const { switch (type) { case OBJECT: { /* breaks stuff :( - if (deep && !_get_obj().ref.is_null()) { + if (p_deep && !_get_obj().ref.is_null()) { Ref<Resource> resource = _get_obj().ref; if (resource.is_valid()) { return resource->duplicate(true); @@ -1837,9 +1842,9 @@ Variant Variant::duplicate(bool deep) const { return *this; } break; case DICTIONARY: - return operator Dictionary().duplicate(deep); + return operator Dictionary().recursive_duplicate(p_deep, recursion_count); case ARRAY: - return operator Array().duplicate(deep); + return operator Array().recursive_duplicate(p_deep, recursion_count); case PACKED_BYTE_ARRAY: return operator Vector<uint8_t>().duplicate(); case PACKED_INT32_ARRAY: @@ -1863,6 +1868,110 @@ Variant Variant::duplicate(bool deep) const { } } +void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) { + if (a.type != b.type) { + return; + } + + switch (a.type) { + case NIL: { + r_dst = Variant(); + } + return; + case INT: { + int64_t va = a._data._int; + int64_t vb = b._data._int; + r_dst = int(va - vb); + } + return; + case FLOAT: { + double ra = a._data._float; + double rb = b._data._float; + r_dst = ra - rb; + } + return; + case VECTOR2: { + r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) - *reinterpret_cast<const Vector2 *>(b._data._mem); + } + 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), int32_t(vay - vby)); + } + 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, ra->size - rb->size); + } + 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), int32_t(vay - vby), int32_t(vcx - vdx), int32_t(vcy - vdy)); + } + return; + case VECTOR3: { + r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) - *reinterpret_cast<const Vector3 *>(b._data._mem); + } + 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), int32_t(vay - vby), int32_t(vaz - vbz)); + } + return; + case AABB: { + const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem); + const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem); + r_dst = ::AABB(ra->position - rb->position, ra->size - rb->size); + } + return; + case QUATERNION: { + Quaternion empty_rot; + const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem); + const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem); + r_dst = (*qb).inverse() * *qa; + } + return; + case COLOR: { + const Color *ca = reinterpret_cast<const Color *>(a._data._mem); + const Color *cb = reinterpret_cast<const Color *>(b._data._mem); + float new_r = ca->r - cb->r; + float new_g = ca->g - cb->g; + float new_b = ca->b - cb->b; + float new_a = ca->a - cb->a; + new_r = new_r > 1.0 ? 1.0 : new_r; + new_g = new_g > 1.0 ? 1.0 : new_g; + new_b = new_b > 1.0 ? 1.0 : new_b; + new_a = new_a > 1.0 ? 1.0 : new_a; + r_dst = Color(new_r, new_g, new_b, new_a); + } + return; + default: { + r_dst = a; + } + return; + } +} + void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) { if (a.type != b.type) { if (a.is_num() && b.is_num()) { @@ -2115,7 +2224,7 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & } return; case BASIS: { - r_dst = Transform3D(*a._data._basis).interpolate_with(Transform3D(*b._data._basis), c).basis; + r_dst = a._data._basis->lerp(*b._data._basis, c); } return; case TRANSFORM3D: { diff --git a/core/variant/variant_setget.h b/core/variant/variant_setget.h index dbf24ab3e3..28277fa5d0 100644 --- a/core/variant/variant_setget.h +++ b/core/variant/variant_setget.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 232054d0ca..6ed85815be 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -151,10 +151,10 @@ struct VariantUtilityFunctions { r_error.error = Callable::CallError::CALL_OK; switch (x.get_type()) { case Variant::INT: { - return SGN(VariantInternalAccessor<int64_t>::get(&x)); + return SIGN(VariantInternalAccessor<int64_t>::get(&x)); } break; case Variant::FLOAT: { - return SGN(VariantInternalAccessor<double>::get(&x)); + return SIGN(VariantInternalAccessor<double>::get(&x)); } break; case Variant::VECTOR2: { return VariantInternalAccessor<Vector2>::get(&x).sign(); @@ -176,11 +176,11 @@ struct VariantUtilityFunctions { } static inline double signf(double x) { - return SGN(x); + return SIGN(x); } static inline int64_t signi(int64_t x) { - return SGN(x); + return SIGN(x); } static inline double pow(double x, double y) { @@ -219,10 +219,6 @@ struct VariantUtilityFunctions { return Math::step_decimals(step); } - static inline int range_step_decimals(float step) { - return Math::range_step_decimals(step); - } - static inline double snapped(double value, double step) { return Math::snapped(value, step); } @@ -231,6 +227,10 @@ struct VariantUtilityFunctions { return Math::lerp(from, to, weight); } + static inline double cubic_interpolate(double from, double to, double pre, double post, double weight) { + return Math::cubic_interpolate(from, to, pre, post, weight); + } + static inline double lerp_angle(double from, double to, double weight) { return Math::lerp_angle(from, to, weight); } @@ -275,6 +275,10 @@ struct VariantUtilityFunctions { return Math::wrapf(value, min, max); } + static inline double pingpong(double value, double length) { + return Math::pingpong(value, length); + } + static inline Variant max(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 2) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; @@ -399,6 +403,10 @@ struct VariantUtilityFunctions { return Math::randf(); } + static inline double randfn(double mean, double deviation) { + return Math::randfn(mean, deviation); + } + static inline int64_t randi_range(int64_t from, int64_t to) { return Math::random((int32_t)from, (int32_t)to); } @@ -425,7 +433,7 @@ struct VariantUtilityFunctions { static inline Variant weakref(const Variant &obj, Callable::CallError &r_error) { if (obj.get_type() == Variant::OBJECT) { r_error.error = Callable::CallError::CALL_OK; - if (obj.is_ref()) { + if (obj.is_ref_counted()) { Ref<WeakRef> wref = memnew(WeakRef); REF r = obj; if (r.is_valid()) { @@ -462,20 +470,20 @@ struct VariantUtilityFunctions { r_error.argument = 1; return String(); } - String str; + String s; for (int i = 0; i < p_arg_count; i++) { String os = p_args[i]->operator String(); if (i == 0) { - str = os; + s = os; } else { - str += os; + s += os; } } r_error.error = Callable::CallError::CALL_OK; - return str; + return s; } static inline String error_string(Error error) { @@ -487,96 +495,98 @@ struct VariantUtilityFunctions { } static inline void print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - if (p_arg_count < 1) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 1; - } - String str; + String s; for (int i = 0; i < p_arg_count; i++) { String os = p_args[i]->operator String(); if (i == 0) { - str = os; + s = os; } else { - str += os; + s += os; } } - print_line(str); + print_line(s); r_error.error = Callable::CallError::CALL_OK; } - static inline void printerr(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - if (p_arg_count < 1) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 1; + static inline void print_verbose(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { + if (OS::get_singleton()->is_stdout_verbose()) { + String s; + for (int i = 0; i < p_arg_count; i++) { + String os = p_args[i]->operator String(); + + if (i == 0) { + s = os; + } else { + s += os; + } + } + + // No need to use `print_verbose()` as this call already only happens + // when verbose mode is enabled. This avoids performing string argument concatenation + // when not needed. + print_line(s); } - String str; + + r_error.error = Callable::CallError::CALL_OK; + } + + static inline void printerr(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { + String s; for (int i = 0; i < p_arg_count; i++) { String os = p_args[i]->operator String(); if (i == 0) { - str = os; + s = os; } else { - str += os; + s += os; } } - print_error(str); + print_error(s); r_error.error = Callable::CallError::CALL_OK; } static inline void printt(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - if (p_arg_count < 1) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 1; - } - String str; + String s; for (int i = 0; i < p_arg_count; i++) { if (i) { - str += "\t"; + s += "\t"; } - str += p_args[i]->operator String(); + s += p_args[i]->operator String(); } - print_line(str); + print_line(s); r_error.error = Callable::CallError::CALL_OK; } static inline void prints(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - if (p_arg_count < 1) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 1; - } - String str; + String s; for (int i = 0; i < p_arg_count; i++) { if (i) { - str += " "; + s += " "; } - str += p_args[i]->operator String(); + s += p_args[i]->operator String(); } - print_line(str); + print_line(s); r_error.error = Callable::CallError::CALL_OK; } static inline void printraw(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - if (p_arg_count < 1) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 1; - } - String str; + String s; for (int i = 0; i < p_arg_count; i++) { String os = p_args[i]->operator String(); if (i == 0) { - str = os; + s = os; } else { - str += os; + s += os; } } - OS::get_singleton()->print("%s", str.utf8().get_data()); + OS::get_singleton()->print("%s", s.utf8().get_data()); r_error.error = Callable::CallError::CALL_OK; } @@ -585,18 +595,18 @@ struct VariantUtilityFunctions { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 1; } - String str; + String s; for (int i = 0; i < p_arg_count; i++) { String os = p_args[i]->operator String(); if (i == 0) { - str = os; + s = os; } else { - str += os; + s += os; } } - ERR_PRINT(str); + ERR_PRINT(s); r_error.error = Callable::CallError::CALL_OK; } @@ -605,18 +615,18 @@ struct VariantUtilityFunctions { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 1; } - String str; + String s; for (int i = 0; i < p_arg_count; i++) { String os = p_args[i]->operator String(); if (i == 0) { - str = os; + s = os; } else { - str += os; + s += os; } } - WARN_PRINT(str); + WARN_PRINT(s); r_error.error = Callable::CallError::CALL_OK; } @@ -1190,10 +1200,10 @@ void Variant::_register_variant_utility_functions() { FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(range_step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(snapped, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cubic_interpolate, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(range_lerp, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH); @@ -1224,6 +1234,7 @@ void Variant::_register_variant_utility_functions() { FUNCBINDR(clampf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(nearest_po2, sarray("value"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(pingpong, sarray("value", "length"), Variant::UTILITY_FUNC_TYPE_MATH); // Random @@ -1232,6 +1243,7 @@ void Variant::_register_variant_utility_functions() { FUNCBINDR(randf, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM); FUNCBINDR(randi_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM); FUNCBINDR(randf_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randfn, sarray("mean", "deviation"), Variant::UTILITY_FUNC_TYPE_RANDOM); FUNCBIND(seed, sarray("base"), Variant::UTILITY_FUNC_TYPE_RANDOM); FUNCBINDR(rand_from_seed, sarray("seed"), Variant::UTILITY_FUNC_TYPE_RANDOM); @@ -1246,6 +1258,7 @@ void Variant::_register_variant_utility_functions() { FUNCBINDVARARGV(printt, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); FUNCBINDVARARGV(prints, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); FUNCBINDVARARGV(printraw, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(print_verbose, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); FUNCBINDVARARGV(push_error, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); FUNCBINDVARARGV(push_warning, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); @@ -1330,6 +1343,28 @@ Variant::UtilityFunctionType Variant::get_utility_function_type(const StringName return bfi->type; } +MethodInfo Variant::get_utility_function_info(const StringName &p_name) { + MethodInfo info; + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); + if (bfi) { + info.name = p_name; + if (bfi->returns_value && bfi->return_type == Variant::NIL) { + info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + } + info.return_val.type = bfi->return_type; + if (bfi->is_vararg) { + info.flags |= METHOD_FLAG_VARARG; + } + for (int i = 0; i < bfi->argnames.size(); ++i) { + PropertyInfo arg; + arg.type = bfi->get_arg_type(i); + arg.name = bfi->argnames[i]; + info.arguments.push_back(arg); + } + } + return info; +} + int Variant::get_utility_function_argument_count(const StringName &p_name) { const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { |