summaryrefslogtreecommitdiffstats
path: root/core/variant
diff options
context:
space:
mode:
Diffstat (limited to 'core/variant')
-rw-r--r--core/variant/array.cpp4
-rw-r--r--core/variant/binder_common.h56
-rw-r--r--core/variant/callable.cpp15
-rw-r--r--core/variant/callable.h2
-rw-r--r--core/variant/callable_bind.cpp6
-rw-r--r--core/variant/container_type_validate.h2
-rw-r--r--core/variant/dictionary.cpp4
-rw-r--r--core/variant/method_ptrcall.h44
-rw-r--r--core/variant/typed_array.h3
-rw-r--r--core/variant/variant.cpp17
-rw-r--r--core/variant/variant.h17
-rw-r--r--core/variant/variant_call.cpp34
-rw-r--r--core/variant/variant_internal.h2
-rw-r--r--core/variant/variant_op.h4
-rw-r--r--core/variant/variant_parser.cpp2
-rw-r--r--core/variant/variant_setget.cpp6
-rw-r--r--core/variant/variant_utility.cpp260
-rw-r--r--core/variant/variant_utility.h3
18 files changed, 349 insertions, 132 deletions
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 5a0ded6c01..ab0315ae34 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -52,7 +52,7 @@ public:
void Array::_ref(const Array &p_from) const {
ArrayPrivate *_fp = p_from._p;
- ERR_FAIL_COND(!_fp); // should NOT happen.
+ ERR_FAIL_NULL(_fp); // Should NOT happen.
if (_fp == _p) {
return; // whatever it is, nothing to do here move along
@@ -137,7 +137,7 @@ bool Array::recursive_equal(const Array &p_array, int recursion_count) const {
}
recursion_count++;
for (int i = 0; i < size; i++) {
- if (!a1[i].hash_compare(a2[i], recursion_count)) {
+ if (!a1[i].hash_compare(a2[i], recursion_count, false)) {
return false;
}
}
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index 9f8fb7e95e..34b54f1d00 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -404,13 +404,13 @@ void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Vari
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -422,7 +422,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const V
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -433,7 +433,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const V
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -455,13 +455,13 @@ void call_with_variant_argsc(T *p_instance, void (T::*p_method)(P...) const, con
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -473,7 +473,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -484,7 +484,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -506,7 +506,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -517,7 +517,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -539,7 +539,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -550,7 +550,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -785,13 +785,13 @@ void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Var
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -815,13 +815,13 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -833,13 +833,13 @@ void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -851,13 +851,13 @@ void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, co
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -882,7 +882,7 @@ void call_with_variant_args_retc_static_helper_dv(T *p_instance, R (*p_method)(T
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -893,7 +893,7 @@ void call_with_variant_args_retc_static_helper_dv(T *p_instance, R (*p_method)(T
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -928,7 +928,7 @@ void call_with_variant_args_static_helper_dv(T *p_instance, void (*p_method)(T *
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -939,7 +939,7 @@ void call_with_variant_args_static_helper_dv(T *p_instance, void (*p_method)(T *
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -961,7 +961,7 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const Variant **p
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -972,7 +972,7 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const Variant **p
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -994,7 +994,7 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const Variant **p_
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
@@ -1005,7 +1005,7 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const Variant **p_
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
+ r_error.expected = sizeof...(P);
return;
}
#endif
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 630873ec2e..0b1174c873 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -47,6 +47,13 @@ void Callable::callp(const Variant **p_arguments, int p_argcount, Variant &r_ret
r_call_error.expected = 0;
r_return_value = Variant();
} else if (is_custom()) {
+ if (!is_valid()) {
+ r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ r_return_value = Variant();
+ return;
+ }
custom->call(p_arguments, p_argcount, r_return_value, r_call_error);
} else {
Object *obj = ObjectDB::get_instance(ObjectID(object));
@@ -465,20 +472,20 @@ Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
Error Signal::connect(const Callable &p_callable, uint32_t p_flags) {
Object *obj = get_object();
- ERR_FAIL_COND_V(!obj, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(obj, ERR_UNCONFIGURED);
return obj->connect(name, p_callable, p_flags);
}
void Signal::disconnect(const Callable &p_callable) {
Object *obj = get_object();
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->disconnect(name, p_callable);
}
bool Signal::is_connected(const Callable &p_callable) const {
Object *obj = get_object();
- ERR_FAIL_COND_V(!obj, false);
+ ERR_FAIL_NULL_V(obj, false);
return obj->is_connected(name, p_callable);
}
@@ -500,7 +507,7 @@ Array Signal::get_connections() const {
}
Signal::Signal(const Object *p_object, const StringName &p_name) {
- ERR_FAIL_COND_MSG(p_object == nullptr, "Object argument to Signal constructor must be non-null");
+ ERR_FAIL_NULL_MSG(p_object, "Object argument to Signal constructor must be non-null.");
object = p_object->get_instance_id();
name = p_name;
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 086e5d2a00..3ae424e9bf 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -69,6 +69,8 @@ public:
int expected = 0;
};
+ template <typename... VarArgs>
+ Variant call(VarArgs... p_args) const;
void callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
void call_deferredp(const Variant **p_arguments, int p_argcount) const;
Variant callv(const Array &p_arguments) const;
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
index a5629d5d39..9a6380a55f 100644
--- a/core/variant/callable_bind.cpp
+++ b/core/variant/callable_bind.cpp
@@ -245,9 +245,8 @@ void CallableCustomUnbind::get_bound_arguments(Vector<Variant> &r_arguments, int
}
void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
- if (argcount > p_argcount) {
+ if (p_argcount < argcount) {
r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_call_error.argument = 0;
r_call_error.expected = argcount;
return;
}
@@ -255,9 +254,8 @@ void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Var
}
Error CallableCustomUnbind::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
- if (argcount > p_argcount) {
+ if (p_argcount < argcount) {
r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_call_error.argument = 0;
r_call_error.expected = argcount;
return ERR_UNCONFIGURED;
}
diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h
index ffe1dc90a3..0a23c69cb4 100644
--- a/core/variant/container_type_validate.h
+++ b/core/variant/container_type_validate.h
@@ -113,7 +113,7 @@ struct ContainerTypeValidate {
return true; // This is fine, it's null.
}
Object *object = ObjectDB::get_instance(object_id);
- ERR_FAIL_COND_V_MSG(object == nullptr, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
+ ERR_FAIL_NULL_V_MSG(object, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
#else
Object *object = p_variant;
if (object == nullptr) {
diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp
index f019273735..141ce25fa6 100644
--- a/core/variant/dictionary.cpp
+++ b/core/variant/dictionary.cpp
@@ -210,7 +210,7 @@ bool Dictionary::recursive_equal(const Dictionary &p_dictionary, int recursion_c
recursion_count++;
for (const KeyValue<Variant, Variant> &this_E : _p->variant_map) {
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator other_E(p_dictionary._p->variant_map.find(this_E.key));
- if (!other_E || !this_E.value.hash_compare(other_E->value, recursion_count)) {
+ if (!other_E || !this_E.value.hash_compare(other_E->value, recursion_count, false)) {
return false;
}
}
@@ -248,7 +248,7 @@ void Dictionary::merge(const Dictionary &p_dictionary, bool p_overwrite) {
}
void Dictionary::_unref() const {
- ERR_FAIL_COND(!_p);
+ ERR_FAIL_NULL(_p);
if (_p->refcount.unref()) {
if (_p->read_only) {
memdelete(_p->read_only);
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index cbfb9cc257..79be85cae6 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -38,26 +38,26 @@
template <class T>
struct PtrToArg {};
-#define MAKE_PTRARG(m_type) \
- template <> \
- struct PtrToArg<m_type> { \
- _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
- return *reinterpret_cast<const m_type *>(p_ptr); \
- } \
- typedef m_type EncodeT; \
- _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
- *((m_type *)p_ptr) = p_val; \
- } \
- }; \
- template <> \
- struct PtrToArg<const m_type &> { \
- _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
- return *reinterpret_cast<const m_type *>(p_ptr); \
- } \
- typedef m_type EncodeT; \
- _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
- *((m_type *)p_ptr) = p_val; \
- } \
+#define MAKE_PTRARG(m_type) \
+ template <> \
+ struct PtrToArg<m_type> { \
+ _FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
+ return *reinterpret_cast<const m_type *>(p_ptr); \
+ } \
+ typedef m_type EncodeT; \
+ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
+ *((m_type *)p_ptr) = p_val; \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<const m_type &> { \
+ _FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
+ return *reinterpret_cast<const m_type *>(p_ptr); \
+ } \
+ typedef m_type EncodeT; \
+ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
+ *((m_type *)p_ptr) = p_val; \
+ } \
}
#define MAKE_PTRARGCONV(m_type, m_conv) \
@@ -85,7 +85,7 @@ struct PtrToArg {};
#define MAKE_PTRARG_BY_REFERENCE(m_type) \
template <> \
struct PtrToArg<m_type> { \
- _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
+ _FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
@@ -95,7 +95,7 @@ struct PtrToArg {};
}; \
template <> \
struct PtrToArg<const m_type &> { \
- _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
+ _FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h
index 055c52aa63..037c5c7c2e 100644
--- a/core/variant/typed_array.h
+++ b/core/variant/typed_array.h
@@ -145,8 +145,7 @@ struct PtrToArg<TypedArray<T>> {
template <class T>
struct PtrToArg<const TypedArray<T> &> {
typedef Array EncodeT;
- _FORCE_INLINE_ static TypedArray<T>
- convert(const void *p_ptr) {
+ _FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
}
};
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 8a0289898d..4c0212075b 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -1291,7 +1291,13 @@ void Variant::zero() {
break;
default:
+ Type prev_type = type;
this->clear();
+ if (type != prev_type) {
+ // clear() changes type to NIL, so it needs to be restored.
+ Callable::CallError ce;
+ Variant::construct(prev_type, *this, nullptr, 0, ce);
+ }
break;
}
}
@@ -2117,7 +2123,7 @@ Variant::operator ::RID() const {
} else if (type == OBJECT && _get_obj().obj) {
#ifdef DEBUG_ENABLED
if (EngineDebugger::is_active()) {
- ERR_FAIL_COND_V_MSG(ObjectDB::get_instance(_get_obj().id) == nullptr, ::RID(), "Invalid pointer (object was freed).");
+ ERR_FAIL_NULL_V_MSG(ObjectDB::get_instance(_get_obj().id), ::RID(), "Invalid pointer (object was freed).");
}
#endif
Callable::CallError ce;
@@ -3235,8 +3241,11 @@ uint32_t Variant::recursive_hash(int recursion_count) const {
return 0;
}
+#define hash_compare_scalar_base(p_lhs, p_rhs, semantic_comparison) \
+ (((p_lhs) == (p_rhs)) || (semantic_comparison && Math::is_nan(p_lhs) && Math::is_nan(p_rhs)))
+
#define hash_compare_scalar(p_lhs, p_rhs) \
- (((p_lhs) == (p_rhs)) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)))
+ (hash_compare_scalar_base(p_lhs, p_rhs, true))
#define hash_compare_vector2(p_lhs, p_rhs) \
(hash_compare_scalar((p_lhs).x, (p_rhs).x) && \
@@ -3282,7 +3291,7 @@ uint32_t Variant::recursive_hash(int recursion_count) const {
\
return true
-bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const {
+bool Variant::hash_compare(const Variant &p_variant, int recursion_count, bool semantic_comparison) const {
if (type != p_variant.type) {
return false;
}
@@ -3293,7 +3302,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
} break;
case FLOAT: {
- return hash_compare_scalar(_data._float, p_variant._data._float);
+ return hash_compare_scalar_base(_data._float, p_variant._data._float, semantic_comparison);
} break;
case STRING: {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 04c2fe2012..21342ae6ef 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -751,7 +751,8 @@ public:
uint32_t hash() const;
uint32_t recursive_hash(int recursion_count) const;
- bool hash_compare(const Variant &p_variant, int recursion_count = 0) const;
+ // By default, performs a semantic comparison. Otherwise, numeric/binary comparison (if appropriate).
+ bool hash_compare(const Variant &p_variant, int recursion_count = 0, bool semantic_comparison = true) const;
bool identity_compare(const Variant &p_variant) const;
bool booleanize() const;
String stringify(int recursion_count = 0) const;
@@ -833,6 +834,20 @@ String vformat(const String &p_text, const VarArgs... p_args) {
}
template <typename... VarArgs>
+Variant Callable::call(VarArgs... p_args) const {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., 0 }; // +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];
+ }
+
+ Variant ret;
+ CallError ce;
+ callp(sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), ret, ce);
+ return ret;
+}
+
+template <typename... VarArgs>
Callable Callable::bind(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];
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 5a405a7080..f041d2c95e 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1037,9 +1037,7 @@ struct _VariantCall {
static void func_Callable_rpc_id(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
if (p_argcount == 0) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 0;
r_error.expected = 1;
-
} else if (p_args[0]->get_type() != Variant::INT) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
@@ -1259,28 +1257,28 @@ bool Variant::has_builtin_method(Variant::Type p_type, const StringName &p_metho
Variant::ValidatedBuiltInMethod Variant::get_validated_builtin_method(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, nullptr);
+ ERR_FAIL_NULL_V(method, nullptr);
return method->validated_call;
}
Variant::PTRBuiltInMethod Variant::get_ptr_builtin_method(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, nullptr);
+ ERR_FAIL_NULL_V(method, nullptr);
return method->ptrcall;
}
int Variant::get_builtin_method_argument_count(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, 0);
+ ERR_FAIL_NULL_V(method, 0);
return method->argument_count;
}
Variant::Type Variant::get_builtin_method_argument_type(Variant::Type p_type, const StringName &p_method, int p_argument) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::NIL);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, Variant::NIL);
+ ERR_FAIL_NULL_V(method, Variant::NIL);
ERR_FAIL_INDEX_V(p_argument, method->argument_count, Variant::NIL);
return method->get_argument_type(p_argument);
}
@@ -1288,7 +1286,7 @@ Variant::Type Variant::get_builtin_method_argument_type(Variant::Type p_type, co
String Variant::get_builtin_method_argument_name(Variant::Type p_type, const StringName &p_method, int p_argument) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, String());
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, String());
+ ERR_FAIL_NULL_V(method, String());
#ifdef DEBUG_METHODS_ENABLED
ERR_FAIL_INDEX_V(p_argument, method->argument_count, String());
return method->argument_names[p_argument];
@@ -1300,14 +1298,14 @@ String Variant::get_builtin_method_argument_name(Variant::Type p_type, const Str
Vector<Variant> Variant::get_builtin_method_default_arguments(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Vector<Variant>());
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, Vector<Variant>());
+ ERR_FAIL_NULL_V(method, Vector<Variant>());
return method->default_arguments;
}
bool Variant::has_builtin_method_return_value(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, false);
+ ERR_FAIL_NULL_V(method, false);
return method->has_return_type;
}
@@ -1326,35 +1324,35 @@ int Variant::get_builtin_method_count(Variant::Type p_type) {
Variant::Type Variant::get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::NIL);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, Variant::NIL);
+ ERR_FAIL_NULL_V(method, Variant::NIL);
return method->return_type;
}
bool Variant::is_builtin_method_const(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, false);
+ ERR_FAIL_NULL_V(method, false);
return method->is_const;
}
bool Variant::is_builtin_method_static(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, false);
+ ERR_FAIL_NULL_V(method, false);
return method->is_static;
}
bool Variant::is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, false);
+ ERR_FAIL_NULL_V(method, false);
return method->is_vararg;
}
uint32_t Variant::get_builtin_method_hash(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, 0);
+ ERR_FAIL_NULL_V(method, 0);
uint32_t hash = hash_murmur3_one_32(method->is_const);
hash = hash_murmur3_one_32(method->is_static, hash);
hash = hash_murmur3_one_32(method->is_vararg, hash);
@@ -2076,6 +2074,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, basis_xform, sarray("v"), varray());
bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray());
+ bind_method(Transform2D, is_conformal, sarray(), varray());
bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
bind_method(Transform2D, is_finite, sarray(), varray());
// Do not bind functions like set_rotation, set_scale, set_skew, etc because this type is immutable and can't be modified.
@@ -2095,6 +2094,7 @@ static void _register_variant_builtin_methods() {
bind_method(Basis, tdoty, sarray("with"), varray());
bind_method(Basis, tdotz, sarray("with"), varray());
bind_method(Basis, slerp, sarray("to", "weight"), varray());
+ bind_method(Basis, is_conformal, sarray(), varray());
bind_method(Basis, is_equal_approx, sarray("b"), varray());
bind_method(Basis, is_finite, sarray(), varray());
bind_method(Basis, get_rotation_quaternion, sarray(), varray());
@@ -2569,9 +2569,13 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::VECTOR4I, "ZERO", Vector4i(0, 0, 0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR4I, "ONE", Vector4i(1, 1, 1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR4I, "MIN", Vector4i(INT32_MIN, INT32_MIN, INT32_MIN, INT32_MIN));
+ _VariantCall::add_variant_constant(Variant::VECTOR4I, "MAX", Vector4i(INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "ZERO", Vector3i(0, 0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "ONE", Vector3i(1, 1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "MIN", Vector3i(INT32_MIN, INT32_MIN, INT32_MIN));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "MAX", Vector3i(INT32_MAX, INT32_MAX, INT32_MAX));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "LEFT", Vector3i(-1, 0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "RIGHT", Vector3i(1, 0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "UP", Vector3i(0, 1, 0));
@@ -2601,6 +2605,8 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::VECTOR2I, "ZERO", Vector2i(0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "ONE", Vector2i(1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "MIN", Vector2i(INT32_MIN, INT32_MIN));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "MAX", Vector2i(INT32_MAX, INT32_MAX));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "LEFT", Vector2i(-1, 0));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "RIGHT", Vector2i(1, 0));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1));
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 782053b613..116210e8de 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -418,7 +418,7 @@ public:
case Variant::PACKED_COLOR_ARRAY:
return get_color_array(v);
case Variant::OBJECT:
- return v->_get_obj().obj;
+ return get_object(v);
case Variant::VARIANT_MAX:
ERR_FAIL_V(nullptr);
}
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index fc1f7828a2..9e6367ab6d 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -1493,7 +1493,7 @@ public:
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
Object *l = right->get_validated_object();
- ERR_FAIL_COND(l == nullptr);
+ ERR_FAIL_NULL(l);
const String &a = *VariantGetInternalPtr<String>::get_ptr(left);
bool valid;
@@ -1527,7 +1527,7 @@ public:
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
Object *l = right->get_validated_object();
- ERR_FAIL_COND(l == nullptr);
+ ERR_FAIL_NULL(l);
const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(left);
bool valid;
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index fea1622222..86e7654090 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -1075,7 +1075,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
return ERR_PARSE_ERROR;
}
- static HashMap<StringName, Variant::Type> builtin_types;
+ static HashMap<String, Variant::Type> builtin_types;
if (builtin_types.is_empty()) {
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
builtin_types[Variant::get_type_name((Variant::Type)i)] = (Variant::Type)i;
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index 30fb5d0e9f..05f7abf32c 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -318,7 +318,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#ifdef DEBUG_ENABLED
#define NULL_TEST(m_key) \
- ERR_FAIL_COND(!m_key)
+ ERR_FAIL_NULL(m_key)
#else
@@ -1068,7 +1068,7 @@ struct VariantKeyedSetGetObject {
}
static uint32_t ptr_has(const void *base, const void *key) {
const Object *obj = PtrToArg<Object *>::convert(base);
- ERR_FAIL_COND_V(!obj, false);
+ ERR_FAIL_NULL_V(obj, false);
bool valid;
obj->getvar(PtrToArg<Variant>::convert(key), &valid);
return valid;
@@ -1245,7 +1245,7 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const {
}
} else if (type == OBJECT) {
Object *obj = get_validated_object();
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->get_property_list(p_list);
} else {
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index b51df89bec..cc48394b64 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -121,16 +121,27 @@ Variant VariantUtilityFunctions::floor(Variant x, Callable::CallError &r_error)
case Variant::VECTOR2: {
return VariantInternalAccessor<Vector2>::get(&x).floor();
} break;
+ case Variant::VECTOR2I: {
+ return VariantInternalAccessor<Vector2i>::get(&x);
+ } break;
case Variant::VECTOR3: {
return VariantInternalAccessor<Vector3>::get(&x).floor();
} break;
+ case Variant::VECTOR3I: {
+ return VariantInternalAccessor<Vector3i>::get(&x);
+ } break;
case Variant::VECTOR4: {
return VariantInternalAccessor<Vector4>::get(&x).floor();
} break;
+ case Variant::VECTOR4I: {
+ return VariantInternalAccessor<Vector4i>::get(&x);
+ } break;
default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ return R"(Argument "x" must be "int", "float", "Vector2", "Vector2i", "Vector3", "Vector3i", "Vector4", or "Vector4i".)";
+ } break;
}
}
@@ -154,16 +165,27 @@ Variant VariantUtilityFunctions::ceil(Variant x, Callable::CallError &r_error) {
case Variant::VECTOR2: {
return VariantInternalAccessor<Vector2>::get(&x).ceil();
} break;
+ case Variant::VECTOR2I: {
+ return VariantInternalAccessor<Vector2i>::get(&x);
+ } break;
case Variant::VECTOR3: {
return VariantInternalAccessor<Vector3>::get(&x).ceil();
} break;
+ case Variant::VECTOR3I: {
+ return VariantInternalAccessor<Vector3i>::get(&x);
+ } break;
case Variant::VECTOR4: {
return VariantInternalAccessor<Vector4>::get(&x).ceil();
} break;
+ case Variant::VECTOR4I: {
+ return VariantInternalAccessor<Vector4i>::get(&x);
+ } break;
default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ return R"(Argument "x" must be "int", "float", "Vector2", "Vector2i", "Vector3", "Vector3i", "Vector4", or "Vector4i".)";
+ } break;
}
}
@@ -187,16 +209,27 @@ Variant VariantUtilityFunctions::round(Variant x, Callable::CallError &r_error)
case Variant::VECTOR2: {
return VariantInternalAccessor<Vector2>::get(&x).round();
} break;
+ case Variant::VECTOR2I: {
+ return VariantInternalAccessor<Vector2i>::get(&x);
+ } break;
case Variant::VECTOR3: {
return VariantInternalAccessor<Vector3>::get(&x).round();
} break;
+ case Variant::VECTOR3I: {
+ return VariantInternalAccessor<Vector3i>::get(&x);
+ } break;
case Variant::VECTOR4: {
return VariantInternalAccessor<Vector4>::get(&x).round();
} break;
+ case Variant::VECTOR4I: {
+ return VariantInternalAccessor<Vector4i>::get(&x);
+ } break;
default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ return R"(Argument "x" must be "int", "float", "Vector2", "Vector2i", "Vector3", "Vector3i", "Vector4", or "Vector4i".)";
+ } break;
}
}
@@ -236,9 +269,11 @@ Variant VariantUtilityFunctions::abs(const Variant &x, Callable::CallError &r_er
return VariantInternalAccessor<Vector4i>::get(&x).abs();
} break;
default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ return R"(Argument "x" must be "int", "float", "Vector2", "Vector2i", "Vector3", "Vector3i", "Vector4", or "Vector4i".)";
+ } break;
}
}
@@ -278,9 +313,11 @@ Variant VariantUtilityFunctions::sign(const Variant &x, Callable::CallError &r_e
return VariantInternalAccessor<Vector4i>::get(&x).sign();
} break;
default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ return R"(Argument "x" must be "int", "float", "Vector2", "Vector2i", "Vector3", "Vector3i", "Vector4", or "Vector4i".)";
+ } break;
}
}
@@ -333,13 +370,40 @@ int VariantUtilityFunctions::step_decimals(float step) {
}
Variant VariantUtilityFunctions::snapped(const Variant &x, const Variant &step, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
- if (x.get_type() != step.get_type() && !((x.get_type() == Variant::INT && step.get_type() == Variant::FLOAT) || (x.get_type() == Variant::FLOAT && step.get_type() == Variant::INT))) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- return Variant();
+ switch (x.get_type()) {
+ case Variant::INT:
+ case Variant::FLOAT:
+ case Variant::VECTOR2:
+ case Variant::VECTOR2I:
+ case Variant::VECTOR3:
+ case Variant::VECTOR3I:
+ case Variant::VECTOR4:
+ case Variant::VECTOR4I:
+ break;
+ default:
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ return R"(Argument "x" must be "int", "float", "Vector2", "Vector2i", "Vector3", "Vector3i", "Vector4", or "Vector4i".)";
+ }
+
+ if (x.get_type() != step.get_type()) {
+ if (x.get_type() == Variant::INT || x.get_type() == Variant::FLOAT) {
+ if (step.get_type() != Variant::INT && step.get_type() != Variant::FLOAT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::NIL;
+ return R"(Argument "step" must be "int" or "float".)";
+ }
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = x.get_type();
+ return Variant();
+ }
}
+ r_error.error = Callable::CallError::CALL_OK;
switch (step.get_type()) {
case Variant::INT: {
return snappedi(x, VariantInternalAccessor<int64_t>::get(&step));
@@ -366,9 +430,8 @@ Variant VariantUtilityFunctions::snapped(const Variant &x, const Variant &step,
return VariantInternalAccessor<Vector4i>::get(&x).snapped(VariantInternalAccessor<Vector4i>::get(&step));
} break;
default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+ return Variant(); // Already handled.
+ } break;
}
}
@@ -381,14 +444,31 @@ int64_t VariantUtilityFunctions::snappedi(double x, int64_t step) {
}
Variant VariantUtilityFunctions::lerp(const Variant &from, const Variant &to, double weight, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
+ switch (from.get_type()) {
+ case Variant::INT:
+ case Variant::FLOAT:
+ case Variant::VECTOR2:
+ case Variant::VECTOR3:
+ case Variant::VECTOR4:
+ case Variant::QUATERNION:
+ case Variant::BASIS:
+ case Variant::COLOR:
+ break;
+ default:
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ return R"(Argument "from" must be "int", "float", "Vector2", "Vector3", "Vector4", "Quaternion", "Basis, or "Color".)";
+ }
+
if (from.get_type() != to.get_type()) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = from.get_type();
r_error.argument = 1;
+ r_error.expected = from.get_type();
return Variant();
}
+ r_error.error = Callable::CallError::CALL_OK;
switch (from.get_type()) {
case Variant::INT: {
return lerpf(VariantInternalAccessor<int64_t>::get(&from), to, weight);
@@ -415,9 +495,8 @@ Variant VariantUtilityFunctions::lerp(const Variant &from, const Variant &to, do
return VariantInternalAccessor<Color>::get(&from).lerp(VariantInternalAccessor<Color>::get(&to), weight);
} break;
default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+ return Variant(); // Already handled.
+ } break;
}
}
@@ -451,6 +530,10 @@ double VariantUtilityFunctions::bezier_derivative(double p_start, double p_contr
return Math::bezier_derivative(p_start, p_control_1, p_control_2, p_end, p_t);
}
+double VariantUtilityFunctions::angle_difference(double from, double to) {
+ return Math::angle_difference(from, to);
+}
+
double VariantUtilityFunctions::lerp_angle(double from, double to, double weight) {
return Math::lerp_angle(from, to, weight);
}
@@ -471,6 +554,10 @@ double VariantUtilityFunctions::move_toward(double from, double to, double delta
return Math::move_toward(from, to, delta);
}
+double VariantUtilityFunctions::rotate_toward(double from, double to, double delta) {
+ return Math::rotate_toward(from, to, delta);
+}
+
double VariantUtilityFunctions::deg_to_rad(double angle_deg) {
return Math::deg_to_rad(angle_deg);
}
@@ -492,7 +579,7 @@ Variant VariantUtilityFunctions::wrap(const Variant &p_x, const Variant &p_min,
if (x_type != Variant::INT && x_type != Variant::FLOAT) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
- r_error.expected = x_type;
+ r_error.expected = Variant::FLOAT;
return Variant();
}
@@ -558,8 +645,8 @@ Variant VariantUtilityFunctions::max(const Variant **p_args, int p_argcount, Cal
Variant::Type arg_type = p_args[i]->get_type();
if (arg_type != Variant::INT && arg_type != Variant::FLOAT) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = Variant::FLOAT;
r_error.argument = i;
+ r_error.expected = Variant::FLOAT;
return Variant();
}
if (i == 0) {
@@ -569,8 +656,8 @@ Variant VariantUtilityFunctions::max(const Variant **p_args, int p_argcount, Cal
Variant::evaluate(Variant::OP_LESS, base, *p_args[i], ret, valid);
if (!valid) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = base.get_type();
r_error.argument = i;
+ r_error.expected = base.get_type();
return Variant();
}
if (ret.booleanize()) {
@@ -602,8 +689,8 @@ Variant VariantUtilityFunctions::min(const Variant **p_args, int p_argcount, Cal
Variant::Type arg_type = p_args[i]->get_type();
if (arg_type != Variant::INT && arg_type != Variant::FLOAT) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = Variant::FLOAT;
r_error.argument = i;
+ r_error.expected = Variant::FLOAT;
return Variant();
}
if (i == 0) {
@@ -613,8 +700,8 @@ Variant VariantUtilityFunctions::min(const Variant **p_args, int p_argcount, Cal
Variant::evaluate(Variant::OP_GREATER, base, *p_args[i], ret, valid);
if (!valid) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = base.get_type();
r_error.argument = i;
+ r_error.expected = base.get_type();
return Variant();
}
if (ret.booleanize()) {
@@ -642,8 +729,8 @@ Variant VariantUtilityFunctions::clamp(const Variant &x, const Variant &min, con
Variant::evaluate(Variant::OP_LESS, value, min, ret, valid);
if (!valid) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = value.get_type();
r_error.argument = 1;
+ r_error.expected = value.get_type();
return Variant();
}
if (ret.booleanize()) {
@@ -652,8 +739,8 @@ Variant VariantUtilityFunctions::clamp(const Variant &x, const Variant &min, con
Variant::evaluate(Variant::OP_GREATER, value, max, ret, valid);
if (!valid) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = value.get_type();
r_error.argument = 2;
+ r_error.expected = value.get_type();
return Variant();
}
if (ret.booleanize()) {
@@ -752,10 +839,94 @@ int64_t VariantUtilityFunctions::_typeof(const Variant &obj) {
return obj.get_type();
}
+Variant VariantUtilityFunctions::type_convert(const Variant &p_variant, const Variant::Type p_type) {
+ switch (p_type) {
+ case Variant::Type::NIL:
+ return Variant();
+ case Variant::Type::BOOL:
+ return p_variant.operator bool();
+ case Variant::Type::INT:
+ return p_variant.operator int64_t();
+ case Variant::Type::FLOAT:
+ return p_variant.operator double();
+ case Variant::Type::STRING:
+ return p_variant.operator String();
+ case Variant::Type::VECTOR2:
+ return p_variant.operator Vector2();
+ case Variant::Type::VECTOR2I:
+ return p_variant.operator Vector2i();
+ case Variant::Type::RECT2:
+ return p_variant.operator Rect2();
+ case Variant::Type::RECT2I:
+ return p_variant.operator Rect2i();
+ case Variant::Type::VECTOR3:
+ return p_variant.operator Vector3();
+ case Variant::Type::VECTOR3I:
+ return p_variant.operator Vector3i();
+ case Variant::Type::TRANSFORM2D:
+ return p_variant.operator Transform2D();
+ case Variant::Type::VECTOR4:
+ return p_variant.operator Vector4();
+ case Variant::Type::VECTOR4I:
+ return p_variant.operator Vector4i();
+ case Variant::Type::PLANE:
+ return p_variant.operator Plane();
+ case Variant::Type::QUATERNION:
+ return p_variant.operator Quaternion();
+ case Variant::Type::AABB:
+ return p_variant.operator ::AABB();
+ case Variant::Type::BASIS:
+ return p_variant.operator Basis();
+ case Variant::Type::TRANSFORM3D:
+ return p_variant.operator Transform3D();
+ case Variant::Type::PROJECTION:
+ return p_variant.operator Projection();
+ case Variant::Type::COLOR:
+ return p_variant.operator Color();
+ case Variant::Type::STRING_NAME:
+ return p_variant.operator StringName();
+ case Variant::Type::NODE_PATH:
+ return p_variant.operator NodePath();
+ case Variant::Type::RID:
+ return p_variant.operator ::RID();
+ case Variant::Type::OBJECT:
+ return p_variant.operator Object *();
+ case Variant::Type::CALLABLE:
+ return p_variant.operator Callable();
+ case Variant::Type::SIGNAL:
+ return p_variant.operator Signal();
+ case Variant::Type::DICTIONARY:
+ return p_variant.operator Dictionary();
+ case Variant::Type::ARRAY:
+ return p_variant.operator Array();
+ case Variant::Type::PACKED_BYTE_ARRAY:
+ return p_variant.operator PackedByteArray();
+ case Variant::Type::PACKED_INT32_ARRAY:
+ return p_variant.operator PackedInt32Array();
+ case Variant::Type::PACKED_INT64_ARRAY:
+ return p_variant.operator PackedInt64Array();
+ case Variant::Type::PACKED_FLOAT32_ARRAY:
+ return p_variant.operator PackedFloat32Array();
+ case Variant::Type::PACKED_FLOAT64_ARRAY:
+ return p_variant.operator PackedFloat64Array();
+ case Variant::Type::PACKED_STRING_ARRAY:
+ return p_variant.operator PackedStringArray();
+ case Variant::Type::PACKED_VECTOR2_ARRAY:
+ return p_variant.operator PackedVector2Array();
+ case Variant::Type::PACKED_VECTOR3_ARRAY:
+ return p_variant.operator PackedVector3Array();
+ case Variant::Type::PACKED_COLOR_ARRAY:
+ return p_variant.operator PackedColorArray();
+ case Variant::Type::VARIANT_MAX:
+ ERR_PRINT("Invalid type argument to type_convert(), use the TYPE_* constants. Returning the unconverted Variant.");
+ }
+ return p_variant;
+}
+
String VariantUtilityFunctions::str(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;
+ r_error.expected = 1;
return String();
}
String s;
@@ -782,6 +953,11 @@ String VariantUtilityFunctions::error_string(Error error) {
return String(error_names[error]);
}
+String VariantUtilityFunctions::type_string(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V_MSG((int)p_type, (int)Variant::VARIANT_MAX, "<invalid type>", "Invalid type argument to type_string(), use the TYPE_* constants.");
+ return Variant::get_type_name(p_type);
+}
+
void VariantUtilityFunctions::print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
String s;
for (int i = 0; i < p_arg_count; i++) {
@@ -899,7 +1075,7 @@ void VariantUtilityFunctions::printraw(const Variant **p_args, int p_arg_count,
void VariantUtilityFunctions::push_error(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;
+ r_error.expected = 1;
}
String s;
for (int i = 0; i < p_arg_count; i++) {
@@ -919,7 +1095,7 @@ void VariantUtilityFunctions::push_error(const Variant **p_args, int p_arg_count
void VariantUtilityFunctions::push_warning(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;
+ r_error.expected = 1;
}
String s;
for (int i = 0; i < p_arg_count; i++) {
@@ -1569,12 +1745,14 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(cubic_interpolate_angle_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(bezier_derivative, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(angle_difference, sarray("from", "to"), 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(remap, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(smoothstep, sarray("from", "to", "x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(move_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(rotate_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(deg_to_rad, sarray("deg"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(rad_to_deg, sarray("rad"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1615,8 +1793,10 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDVR(weakref, sarray("obj"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDR(_typeof, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(type_convert, sarray("variant", "type"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGS(str, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDR(error_string, sarray("error"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(type_string, sarray("type"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGV(print, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGV(print_rich, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGV(printerr, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
@@ -1664,14 +1844,12 @@ void Variant::call_utility_function(const StringName &p_name, Variant *r_ret, co
if (unlikely(!bfi->is_vararg && p_argcount < bfi->argcount)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 0;
r_error.expected = bfi->argcount;
return;
}
if (unlikely(!bfi->is_vararg && p_argcount > bfi->argcount)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 0;
r_error.expected = bfi->argcount;
return;
}
@@ -1788,7 +1966,7 @@ bool Variant::is_utility_function_vararg(const StringName &p_name) {
uint32_t Variant::get_utility_function_hash(const StringName &p_name) {
const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
- ERR_FAIL_COND_V(!bfi, 0);
+ ERR_FAIL_NULL_V(bfi, 0);
uint32_t hash = hash_murmur3_one_32(bfi->is_vararg);
hash = hash_murmur3_one_32(bfi->returns_value, hash);
diff --git a/core/variant/variant_utility.h b/core/variant/variant_utility.h
index 66883fb140..a56c84a8e9 100644
--- a/core/variant/variant_utility.h
+++ b/core/variant/variant_utility.h
@@ -90,11 +90,13 @@ struct VariantUtilityFunctions {
double to_t, double pre_t, double post_t);
static double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t);
static double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t);
+ static double angle_difference(double from, double to);
static double lerp_angle(double from, double to, double weight);
static double inverse_lerp(double from, double to, double weight);
static double remap(double value, double istart, double istop, double ostart, double ostop);
static double smoothstep(double from, double to, double val);
static double move_toward(double from, double to, double delta);
+ static double rotate_toward(double from, double to, double delta);
static double deg_to_rad(double angle_deg);
static double rad_to_deg(double angle_rad);
static double linear_to_db(double linear);
@@ -128,6 +130,7 @@ struct VariantUtilityFunctions {
static Variant type_convert(const Variant &p_variant, const Variant::Type p_type);
static String str(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
static String error_string(Error error);
+ static String type_string(Variant::Type p_type);
static void print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
static void print_rich(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
#undef print_verbose