summaryrefslogtreecommitdiff
path: root/core/variant
diff options
context:
space:
mode:
authorreduz <reduzio@gmail.com>2020-11-07 19:33:38 -0300
committerreduz <reduzio@gmail.com>2020-11-07 20:17:12 -0300
commit127458ed175c5aeac8dee7f09d23fae4c8928eb7 (patch)
treea1dd3ae46bf575cb8296df38568dfce237c6ecd8 /core/variant
parent30b6db99a99a94c64d906c1b828ff44f79a1bc75 (diff)
Reorganized core/ directory, it was too fatty already
-Removed FuncRef, since Callable makes it obsolete -Removed int_types.h as its obsolete in c++11+ -Changed color names code
Diffstat (limited to 'core/variant')
-rw-r--r--core/variant/SCsub7
-rw-r--r--core/variant/array.cpp556
-rw-r--r--core/variant/array.h118
-rw-r--r--core/variant/binder_common.h657
-rw-r--r--core/variant/callable.cpp393
-rw-r--r--core/variant/callable.h167
-rw-r--r--core/variant/callable_bind.cpp193
-rw-r--r--core/variant/callable_bind.h85
-rw-r--r--core/variant/container_type_validate.h126
-rw-r--r--core/variant/dictionary.cpp273
-rw-r--r--core/variant/dictionary.h91
-rw-r--r--core/variant/method_ptrcall.h453
-rw-r--r--core/variant/type_info.h270
-rw-r--r--core/variant/typed_array.h227
-rw-r--r--core/variant/variant.cpp3521
-rw-r--r--core/variant/variant.h613
-rw-r--r--core/variant/variant_call.cpp2089
-rw-r--r--core/variant/variant_internal.h652
-rw-r--r--core/variant/variant_op.cpp2135
-rw-r--r--core/variant/variant_parser.cpp1803
-rw-r--r--core/variant/variant_parser.h148
-rw-r--r--core/variant/variant_setget.cpp2587
22 files changed, 17164 insertions, 0 deletions
diff --git a/core/variant/SCsub b/core/variant/SCsub
new file mode 100644
index 0000000000..7f4c8b7788
--- /dev/null
+++ b/core/variant/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env_variant = env.Clone()
+
+env_variant.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
new file mode 100644
index 0000000000..64e31189de
--- /dev/null
+++ b/core/variant/array.cpp
@@ -0,0 +1,556 @@
+/*************************************************************************/
+/* array.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "array.h"
+
+#include "container_type_validate.h"
+#include "core/object/class_db.h"
+#include "core/object/script_language.h"
+#include "core/templates/hashfuncs.h"
+#include "core/templates/vector.h"
+#include "core/variant/variant.h"
+
+class ArrayPrivate {
+public:
+ SafeRefCount refcount;
+ Vector<Variant> array;
+
+ ContainerTypeValidate typed;
+};
+
+void Array::_ref(const Array &p_from) const {
+ ArrayPrivate *_fp = p_from._p;
+
+ ERR_FAIL_COND(!_fp); // should NOT happen.
+
+ if (_fp == _p) {
+ return; // whatever it is, nothing to do here move along
+ }
+
+ bool success = _fp->refcount.ref();
+
+ ERR_FAIL_COND(!success); // should really not happen either
+
+ _unref();
+
+ _p = p_from._p;
+}
+
+void Array::_unref() const {
+ if (!_p) {
+ return;
+ }
+
+ if (_p->refcount.unref()) {
+ memdelete(_p);
+ }
+ _p = nullptr;
+}
+
+Variant &Array::operator[](int p_idx) {
+ return _p->array.write[p_idx];
+}
+
+const Variant &Array::operator[](int p_idx) const {
+ return _p->array[p_idx];
+}
+
+int Array::size() const {
+ return _p->array.size();
+}
+
+bool Array::empty() const {
+ return _p->array.empty();
+}
+
+void Array::clear() {
+ _p->array.clear();
+}
+
+bool Array::operator==(const Array &p_array) const {
+ return _p == p_array._p;
+}
+
+bool Array::operator!=(const Array &p_array) const {
+ return !operator==(p_array);
+}
+
+bool Array::operator<(const Array &p_array) const {
+ int a_len = size();
+ int b_len = p_array.size();
+
+ int min_cmp = MIN(a_len, b_len);
+
+ for (int i = 0; i < min_cmp; i++) {
+ if (operator[](i) < p_array[i]) {
+ return true;
+ } else if (p_array[i] < operator[](i)) {
+ return false;
+ }
+ }
+
+ return a_len < b_len;
+}
+
+bool Array::operator<=(const Array &p_array) const {
+ return !operator>(p_array);
+}
+bool Array::operator>(const Array &p_array) const {
+ return p_array < *this;
+}
+bool Array::operator>=(const Array &p_array) const {
+ return !operator<(p_array);
+}
+
+uint32_t Array::hash() const {
+ uint32_t h = hash_djb2_one_32(0);
+
+ for (int i = 0; i < _p->array.size(); i++) {
+ h = hash_djb2_one_32(_p->array[i].hash(), h);
+ }
+ return h;
+}
+
+void Array::_assign(const Array &p_array) {
+ if (_p->typed.type != Variant::OBJECT && _p->typed.type == p_array._p->typed.type) {
+ //same type or untyped, just reference, shuold be fine
+ _ref(p_array);
+ } else if (_p->typed.type == Variant::NIL) { //from typed to untyped, must copy, but this is cheap anyway
+ _p->array = p_array._p->array;
+ } else if (p_array._p->typed.type == Variant::NIL) { //from untyped to typed, must try to check if they are all valid
+ if (_p->typed.type == Variant::OBJECT) {
+ //for objects, it needs full validation, either can be converted or fail
+ for (int i = 0; i < p_array._p->array.size(); i++) {
+ if (!_p->typed.validate(p_array._p->array[i], "assign")) {
+ return;
+ }
+ }
+ _p->array = p_array._p->array; //then just copy, which is cheap anyway
+
+ } else {
+ //for non objects, we need to check if there is a valid conversion, which needs to happen one by one, so this is the worst case.
+ Vector<Variant> new_array;
+ new_array.resize(p_array._p->array.size());
+ for (int i = 0; i < p_array._p->array.size(); i++) {
+ Variant src_val = p_array._p->array[i];
+ if (src_val.get_type() == _p->typed.type) {
+ new_array.write[i] = src_val;
+ } else if (Variant::can_convert_strict(src_val.get_type(), _p->typed.type)) {
+ Variant *ptr = &src_val;
+ Callable::CallError ce;
+ new_array.write[i] = Variant::construct(_p->typed.type, (const Variant **)&ptr, 1, ce, true);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_FAIL_MSG("Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
+ }
+ } else {
+ ERR_FAIL_MSG("Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
+ }
+ }
+
+ _p->array = new_array;
+ }
+ } else if (_p->typed.can_reference(p_array._p->typed)) { //same type or compatible
+ _ref(p_array);
+ } else {
+ ERR_FAIL_MSG("Assignment of arrays of incompatible types.");
+ }
+}
+
+void Array::operator=(const Array &p_array) {
+ _assign(p_array);
+}
+
+void Array::push_back(const Variant &p_value) {
+ ERR_FAIL_COND(!_p->typed.validate(p_value, "push_back"));
+ _p->array.push_back(p_value);
+}
+
+Error Array::resize(int p_new_size) {
+ return _p->array.resize(p_new_size);
+}
+
+void Array::insert(int p_pos, const Variant &p_value) {
+ ERR_FAIL_COND(!_p->typed.validate(p_value, "insert"));
+ _p->array.insert(p_pos, p_value);
+}
+
+void Array::erase(const Variant &p_value) {
+ ERR_FAIL_COND(!_p->typed.validate(p_value, "erase"));
+ _p->array.erase(p_value);
+}
+
+Variant Array::front() const {
+ ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");
+ return operator[](0);
+}
+
+Variant Array::back() const {
+ ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");
+ return operator[](_p->array.size() - 1);
+}
+
+int Array::find(const Variant &p_value, int p_from) const {
+ ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find"), -1);
+ return _p->array.find(p_value, p_from);
+}
+
+int Array::rfind(const Variant &p_value, int p_from) const {
+ if (_p->array.size() == 0) {
+ return -1;
+ }
+ ERR_FAIL_COND_V(!_p->typed.validate(p_value, "rfind"), -1);
+
+ if (p_from < 0) {
+ // Relative offset from the end
+ p_from = _p->array.size() + p_from;
+ }
+ if (p_from < 0 || p_from >= _p->array.size()) {
+ // Limit to array boundaries
+ p_from = _p->array.size() - 1;
+ }
+
+ for (int i = p_from; i >= 0; i--) {
+ if (_p->array[i] == p_value) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int Array::find_last(const Variant &p_value) const {
+ ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find_last"), -1);
+ return rfind(p_value);
+}
+
+int Array::count(const Variant &p_value) const {
+ ERR_FAIL_COND_V(!_p->typed.validate(p_value, "count"), 0);
+ if (_p->array.size() == 0) {
+ return 0;
+ }
+
+ int amount = 0;
+ for (int i = 0; i < _p->array.size(); i++) {
+ if (_p->array[i] == p_value) {
+ amount++;
+ }
+ }
+
+ return amount;
+}
+
+bool Array::has(const Variant &p_value) const {
+ ERR_FAIL_COND_V(!_p->typed.validate(p_value, "use 'has'"), false);
+
+ return _p->array.find(p_value, 0) != -1;
+}
+
+void Array::remove(int p_pos) {
+ _p->array.remove(p_pos);
+}
+
+void Array::set(int p_idx, const Variant &p_value) {
+ ERR_FAIL_COND(!_p->typed.validate(p_value, "set"));
+
+ operator[](p_idx) = p_value;
+}
+
+const Variant &Array::get(int p_idx) const {
+ return operator[](p_idx);
+}
+
+Array Array::duplicate(bool p_deep) const {
+ Array 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);
+ }
+
+ 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 new_arr;
+
+ ERR_FAIL_COND_V_MSG(p_step == 0, new_arr, "Array slice step size cannot be zero.");
+
+ if (empty()) { // Don't try to slice empty arrays.
+ return new_arr;
+ }
+ 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 begin = _clamp_slice_index(p_begin);
+ int end = _clamp_slice_index(p_end);
+
+ int new_arr_size = MAX(((end - begin + p_step) / p_step), 0);
+ new_arr.resize(new_arr_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);
+ }
+ }
+
+ return new_arr;
+}
+
+struct _ArrayVariantSort {
+ _FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
+ bool valid = false;
+ Variant res;
+ Variant::evaluate(Variant::OP_LESS, p_l, p_r, res, valid);
+ if (!valid) {
+ res = false;
+ }
+ return res;
+ }
+};
+
+void Array::sort() {
+ _p->array.sort_custom<_ArrayVariantSort>();
+}
+
+struct _ArrayVariantSortCustom {
+ Object *obj;
+ StringName 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;
+ bool res = obj->call(func, args, 2, err);
+ if (err.error != Callable::CallError::CALL_OK) {
+ res = false;
+ }
+ return res;
+ }
+};
+void Array::sort_custom(Object *p_obj, const StringName &p_function) {
+ ERR_FAIL_NULL(p_obj);
+
+ SortArray<Variant, _ArrayVariantSortCustom, true> avs;
+ avs.compare.obj = p_obj;
+ avs.compare.func = p_function;
+ avs.sort(_p->array.ptrw(), _p->array.size());
+}
+
+void Array::shuffle() {
+ const int n = _p->array.size();
+ if (n < 2) {
+ return;
+ }
+ Variant *data = _p->array.ptrw();
+ for (int i = n - 1; i >= 1; i--) {
+ const int j = Math::rand() % (i + 1);
+ const Variant tmp = data[j];
+ data[j] = data[i];
+ data[i] = tmp;
+ }
+}
+
+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());
+}
+
+int Array::bsearch_custom(const Variant &p_value, Object *p_obj, const StringName &p_function, bool p_before) {
+ ERR_FAIL_COND_V(!_p->typed.validate(p_value, "custom binary search"), -1);
+ ERR_FAIL_NULL_V(p_obj, 0);
+
+ _ArrayVariantSortCustom less;
+ less.obj = p_obj;
+ less.func = p_function;
+
+ return bisect(_p->array, p_value, p_before, less);
+}
+
+void Array::invert() {
+ _p->array.invert();
+}
+
+void Array::push_front(const Variant &p_value) {
+ ERR_FAIL_COND(!_p->typed.validate(p_value, "push_front"));
+ _p->array.insert(0, p_value);
+}
+
+Variant Array::pop_back() {
+ if (!_p->array.empty()) {
+ int n = _p->array.size() - 1;
+ Variant ret = _p->array.get(n);
+ _p->array.resize(n);
+ return ret;
+ }
+ return Variant();
+}
+
+Variant Array::pop_front() {
+ if (!_p->array.empty()) {
+ Variant ret = _p->array.get(0);
+ _p->array.remove(0);
+ return ret;
+ }
+ return Variant();
+}
+
+Variant Array::min() const {
+ Variant minval;
+ for (int i = 0; i < size(); i++) {
+ if (i == 0) {
+ minval = get(i);
+ } else {
+ bool valid;
+ Variant ret;
+ Variant test = get(i);
+ Variant::evaluate(Variant::OP_LESS, test, minval, ret, valid);
+ if (!valid) {
+ return Variant(); //not a valid comparison
+ }
+ if (bool(ret)) {
+ //is less
+ minval = test;
+ }
+ }
+ }
+ return minval;
+}
+
+Variant Array::max() const {
+ Variant maxval;
+ for (int i = 0; i < size(); i++) {
+ if (i == 0) {
+ maxval = get(i);
+ } else {
+ bool valid;
+ Variant ret;
+ Variant test = get(i);
+ Variant::evaluate(Variant::OP_GREATER, test, maxval, ret, valid);
+ if (!valid) {
+ return Variant(); //not a valid comparison
+ }
+ if (bool(ret)) {
+ //is less
+ maxval = test;
+ }
+ }
+ }
+ return maxval;
+}
+
+const void *Array::id() const {
+ return _p->array.ptr();
+}
+
+Array::Array(const Array &p_from, uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
+ _p = memnew(ArrayPrivate);
+ _p->refcount.init();
+ set_typed(p_type, p_class_name, p_script);
+ _assign(p_from);
+}
+
+void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
+ ERR_FAIL_COND_MSG(_p->array.size() > 0, "Type can only be set when array is empty.");
+ ERR_FAIL_COND_MSG(_p->refcount.get() > 1, "Type can only be set when array has no more than one user.");
+ ERR_FAIL_COND_MSG(_p->typed.type != Variant::NIL, "Type can only be set once.");
+ ERR_FAIL_COND_MSG(p_class_name != StringName() && p_type != Variant::OBJECT, "Class names can only be set for type OBJECT");
+ Ref<Script> script = p_script;
+ ERR_FAIL_COND_MSG(script.is_valid() && p_class_name == StringName(), "Script class can only be set together with base class name");
+
+ _p->typed.type = Variant::Type(p_type);
+ _p->typed.class_name = p_class_name;
+ _p->typed.script = script;
+ _p->typed.where = "TypedArray";
+}
+
+Array::Array(const Array &p_from) {
+ _p = nullptr;
+ _ref(p_from);
+}
+
+Array::Array() {
+ _p = memnew(ArrayPrivate);
+ _p->refcount.init();
+}
+
+Array::~Array() {
+ _unref();
+}
diff --git a/core/variant/array.h b/core/variant/array.h
new file mode 100644
index 0000000000..b37d600abd
--- /dev/null
+++ b/core/variant/array.h
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/* array.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#include "core/typedefs.h"
+
+class Variant;
+class ArrayPrivate;
+class Object;
+class StringName;
+
+class Array {
+ mutable ArrayPrivate *_p;
+ 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);
+ void _assign(const Array &p_array);
+
+public:
+ Variant &operator[](int p_idx);
+ const Variant &operator[](int p_idx) const;
+
+ void set(int p_idx, const Variant &p_value);
+ const Variant &get(int p_idx) const;
+
+ int size() const;
+ bool empty() const;
+ void clear();
+
+ bool operator==(const Array &p_array) const;
+ bool operator!=(const Array &p_array) const;
+
+ uint32_t hash() const;
+ void operator=(const Array &p_array);
+
+ void push_back(const Variant &p_value);
+ _FORCE_INLINE_ void append(const Variant &p_value) { push_back(p_value); } //for python compatibility
+ Error resize(int p_new_size);
+
+ void insert(int p_pos, const Variant &p_value);
+ void remove(int p_pos);
+
+ Variant front() const;
+ Variant back() const;
+
+ void sort();
+ void sort_custom(Object *p_obj, const StringName &p_function);
+ void shuffle();
+ int bsearch(const Variant &p_value, bool p_before = true);
+ int bsearch_custom(const Variant &p_value, Object *p_obj, const StringName &p_function, bool p_before = true);
+ void invert();
+
+ int find(const Variant &p_value, int p_from = 0) const;
+ int rfind(const Variant &p_value, int p_from = -1) const;
+ int find_last(const Variant &p_value) const;
+ int count(const Variant &p_value) const;
+ bool has(const Variant &p_value) const;
+
+ void erase(const Variant &p_value);
+
+ void push_front(const Variant &p_value);
+ Variant pop_back();
+ Variant pop_front();
+
+ Array duplicate(bool p_deep = false) const;
+
+ Array slice(int p_begin, int p_end, int p_step = 1, bool p_deep = false) const;
+
+ bool operator<(const Array &p_array) const;
+ bool operator<=(const Array &p_array) const;
+ bool operator>(const Array &p_array) const;
+ bool operator>=(const Array &p_array) const;
+
+ Variant min() const;
+ Variant max() const;
+
+ const void *id() const;
+
+ void set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
+ Array(const Array &p_from);
+ Array();
+ ~Array();
+};
+
+#endif // ARRAY_H
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
new file mode 100644
index 0000000000..e72f76c5e1
--- /dev/null
+++ b/core/variant/binder_common.h
@@ -0,0 +1,657 @@
+/*************************************************************************/
+/* binder_common.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BINDER_COMMON_H
+#define BINDER_COMMON_H
+
+#include "core/object/object.h"
+#include "core/templates/list.h"
+#include "core/templates/simple_type.h"
+#include "core/typedefs.h"
+#include "core/variant/method_ptrcall.h"
+#include "core/variant/type_info.h"
+#include "core/variant/variant.h"
+#include "core/variant/variant_internal.h"
+
+#include <stdio.h>
+
+template <class T>
+struct VariantCaster {
+ static _FORCE_INLINE_ T cast(const Variant &p_variant) {
+ return p_variant;
+ }
+};
+
+template <class T>
+struct VariantCaster<T &> {
+ static _FORCE_INLINE_ T cast(const Variant &p_variant) {
+ return p_variant;
+ }
+};
+
+template <class T>
+struct VariantCaster<const T &> {
+ static _FORCE_INLINE_ T cast(const Variant &p_variant) {
+ return p_variant;
+ }
+};
+
+#ifdef PTRCALL_ENABLED
+
+#define VARIANT_ENUM_CAST(m_enum) \
+ MAKE_ENUM_TYPE_INFO(m_enum) \
+ template <> \
+ struct VariantCaster<m_enum> { \
+ static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \
+ return (m_enum)p_variant.operator int(); \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<m_enum> { \
+ _FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \
+ return m_enum(*reinterpret_cast<const int *>(p_ptr)); \
+ } \
+ _FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \
+ *(int *)p_ptr = p_val; \
+ } \
+ };
+
+#else
+
+#define VARIANT_ENUM_CAST(m_enum) \
+ MAKE_ENUM_TYPE_INFO(m_enum) \
+ template <> \
+ struct VariantCaster<m_enum> { \
+ static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \
+ return (m_enum)p_variant.operator int(); \
+ } \
+ };
+
+#endif
+
+// Object enum casts must go here
+VARIANT_ENUM_CAST(Object::ConnectFlags);
+
+VARIANT_ENUM_CAST(Vector3::Axis);
+
+VARIANT_ENUM_CAST(Error);
+VARIANT_ENUM_CAST(Margin);
+VARIANT_ENUM_CAST(Corner);
+VARIANT_ENUM_CAST(Orientation);
+VARIANT_ENUM_CAST(HAlign);
+VARIANT_ENUM_CAST(VAlign);
+VARIANT_ENUM_CAST(PropertyHint);
+VARIANT_ENUM_CAST(PropertyUsageFlags);
+VARIANT_ENUM_CAST(Variant::Type);
+VARIANT_ENUM_CAST(Variant::Operator);
+
+template <>
+struct VariantCaster<char32_t> {
+ static _FORCE_INLINE_ char32_t cast(const Variant &p_variant) {
+ return (char32_t)p_variant.operator int();
+ }
+};
+#ifdef PTRCALL_ENABLED
+template <>
+struct PtrToArg<char32_t> {
+ _FORCE_INLINE_ static char32_t convert(const void *p_ptr) {
+ return char32_t(*reinterpret_cast<const int *>(p_ptr));
+ }
+ _FORCE_INLINE_ static void encode(char32_t p_val, const void *p_ptr) {
+ *(int *)p_ptr = p_val;
+ }
+};
+#endif
+
+template <typename T>
+struct VariantObjectClassChecker {
+ static _FORCE_INLINE_ bool check(const Variant &p_variant) {
+ return true;
+ }
+};
+
+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>
+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])) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = p_arg_idx;
+ r_error.expected = argtype;
+ }
+
+ return VariantCaster<T>::cast(*p_args[p_arg_idx]);
+ }
+};
+
+template <class T>
+struct VariantCasterAndValidate<T &> {
+ static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
+ Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
+ if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
+ !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;
+ }
+
+ return VariantCaster<T>::cast(*p_args[p_arg_idx]);
+ }
+};
+
+template <class T>
+struct VariantCasterAndValidate<const T &> {
+ static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
+ Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
+ if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
+ !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;
+ }
+
+ return VariantCaster<T>::cast(*p_args[p_arg_idx]);
+ }
+};
+
+#endif // DEBUG_METHODS_ENABLED
+
+template <class T, class... P, size_t... Is>
+void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+ (void)(p_args); //avoid warning
+}
+
+template <class T, class... P, size_t... Is>
+void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+ (void)(p_args); //avoid warning
+}
+
+#ifdef PTRCALL_ENABLED
+
+template <class T, class... P, size_t... Is>
+void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const void **p_args, IndexSequence<Is...>) {
+ (p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
+}
+
+template <class T, class... P, size_t... Is>
+void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const void **p_args, IndexSequence<Is...>) {
+ (p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
+ PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const void **p_args, void *r_ret, IndexSequence<Is...>) {
+ PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_ptr_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
+ PtrToArg<R>::encode(p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...), r_ret);
+}
+
+#endif // PTRCALL_ENABLED
+
+template <class T, class... P, size_t... Is>
+void call_with_validated_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
+ (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+}
+
+template <class T, class... P, size_t... Is>
+void call_with_validated_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, IndexSequence<Is...>) {
+ (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_validated_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
+ VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_validated_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
+ VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_validated_variant_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
+ VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+}
+
+template <class T, class... P>
+void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#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);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_variant_argsc(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#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);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_argsc_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#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);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_ret_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#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);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_retc_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+#ifdef PTRCALL_ENABLED
+
+template <class T, class... P>
+void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const void **p_args) {
+ call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_ptr_argsc(T *p_instance, void (T::*p_method)(P...) const, const void **p_args) {
+ call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_ptr_args_ret(T *p_instance, R (T::*p_method)(P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_ptr_args_retc(T *p_instance, R (T::*p_method)(P...) const, const void **p_args, void *r_ret) {
+ call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_ptr_args_static_retc(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+#endif // PTRCALL_ENABLED
+
+template <class T, class... P>
+void call_with_validated_variant_args(Variant *base, void (T::*p_method)(P...), const Variant **p_args) {
+ call_with_validated_variant_args_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_validated_variant_args_ret(Variant *base, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_ret_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_validated_variant_args_retc(Variant *base, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_validated_variant_args_static_retc(Variant *base, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+// 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__)
+#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) {
+ type = GetTypeInfo<Q>::VARIANT_TYPE;
+ }
+ index++;
+}
+
+template <class... P>
+Variant::Type call_get_argument_type(int p_arg) {
+ Variant::Type type = Variant::NIL;
+ int index = 0;
+ // I think rocket science is simpler than modern C++.
+ using expand_type = int[];
+ expand_type a{ 0, (call_get_argument_type_helper<P>(p_arg, index, type), 0)... };
+ (void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
+ (void)index; // Suppress GCC warning.
+ return type;
+}
+
+template <class Q>
+void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
+ if (p_arg == index) {
+ info = GetTypeInfo<Q>::get_class_info();
+ }
+ index++;
+}
+
+template <class... P>
+void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
+ int index = 0;
+ // I think rocket science is simpler than modern C++.
+ using expand_type = int[];
+ expand_type a{ 0, (call_get_argument_type_info_helper<P>(p_arg, index, info), 0)... };
+ (void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
+ (void)index; // Suppress GCC warning.
+}
+
+template <class Q>
+void call_get_argument_metadata_helper(int p_arg, int &index, GodotTypeInfo::Metadata &md) {
+ if (p_arg == index) {
+ md = GetTypeInfo<Q>::METADATA;
+ }
+ index++;
+}
+
+template <class... P>
+GodotTypeInfo::Metadata call_get_argument_metadata(int p_arg) {
+ GodotTypeInfo::Metadata md = GodotTypeInfo::METADATA_NONE;
+
+ int index = 0;
+ // I think rocket science is simpler than modern C++.
+ using expand_type = int[];
+ expand_type a{ 0, (call_get_argument_metadata_helper<P>(p_arg, index, md), 0)... };
+ (void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
+ (void)index;
+ return md;
+}
+
+#else
+
+template <class... P>
+Variant::Type call_get_argument_type(int p_arg) {
+ return Variant::NIL;
+}
+
+#endif // DEBUG_METHODS_ENABLED
+
+//////////////////////
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+}
+
+template <class T, class R, class... P>
+void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+ (void)p_args;
+}
+
+template <class T, class R, class... P>
+void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_variant_args_retc_static_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ r_ret = (p_method)(p_instance, VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ r_ret = (p_method)(p_instance, VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+
+ (void)p_args;
+}
+
+#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+#endif // BINDER_COMMON_H
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
new file mode 100644
index 0000000000..e504fd05e3
--- /dev/null
+++ b/core/variant/callable.cpp
@@ -0,0 +1,393 @@
+/*************************************************************************/
+/* callable.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "callable.h"
+
+#include "callable_bind.h"
+#include "core/object/message_queue.h"
+#include "core/object/object.h"
+#include "core/object/reference.h"
+#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);
+}
+
+void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const {
+ if (is_null()) {
+ r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ r_return_value = Variant();
+ } else if (is_custom()) {
+ custom->call(p_arguments, p_argcount, r_return_value, r_call_error);
+ } else {
+ Object *obj = ObjectDB::get_instance(ObjectID(object));
+ r_return_value = obj->call(method, p_arguments, p_argcount, r_call_error);
+ }
+}
+
+Callable Callable::bind(const Variant **p_arguments, int p_argcount) const {
+ Vector<Variant> args;
+ args.resize(p_argcount);
+ for (int i = 0; i < p_argcount; i++) {
+ args.write[i] = *p_arguments[i];
+ }
+ return Callable(memnew(CallableCustomBind(*this, args)));
+}
+Callable Callable::unbind(int p_argcount) const {
+ return Callable(memnew(CallableCustomUnbind(*this, p_argcount)));
+}
+
+Object *Callable::get_object() const {
+ if (is_null()) {
+ return nullptr;
+ } else if (is_custom()) {
+ return ObjectDB::get_instance(custom->get_object());
+ } else {
+ return ObjectDB::get_instance(ObjectID(object));
+ }
+}
+
+ObjectID Callable::get_object_id() const {
+ if (is_null()) {
+ return ObjectID();
+ } else if (is_custom()) {
+ return custom->get_object();
+ } else {
+ return ObjectID(object);
+ }
+}
+
+StringName Callable::get_method() const {
+ ERR_FAIL_COND_V_MSG(is_custom(), StringName(),
+ vformat("Can't get method on CallableCustom \"%s\".", operator String()));
+ return method;
+}
+
+CallableCustom *Callable::get_custom() const {
+ ERR_FAIL_COND_V_MSG(!is_custom(), nullptr,
+ vformat("Can't get custom on non-CallableCustom \"%s\".", operator String()));
+ return custom;
+}
+
+const Callable *Callable::get_base_comparator() const {
+ const Callable *comparator = nullptr;
+ if (is_custom()) {
+ comparator = custom->get_base_comparator();
+ }
+ if (comparator) {
+ return comparator;
+ } else {
+ return this;
+ }
+}
+
+uint32_t Callable::hash() const {
+ if (is_custom()) {
+ return custom->hash();
+ } else {
+ uint32_t hash = method.hash();
+ return hash_djb2_one_64(object, hash);
+ }
+}
+
+bool Callable::operator==(const Callable &p_callable) const {
+ bool custom_a = is_custom();
+ bool custom_b = p_callable.is_custom();
+
+ if (custom_a == custom_b) {
+ if (custom_a) {
+ if (custom == p_callable.custom) {
+ return true; //same pointer, dont even compare
+ }
+
+ CallableCustom::CompareEqualFunc eq_a = custom->get_compare_equal_func();
+ CallableCustom::CompareEqualFunc eq_b = p_callable.custom->get_compare_equal_func();
+ if (eq_a == eq_b) {
+ return eq_a(custom, p_callable.custom);
+ } else {
+ return false;
+ }
+ } else {
+ return object == p_callable.object && method == p_callable.method;
+ }
+ } else {
+ return false;
+ }
+}
+
+bool Callable::operator!=(const Callable &p_callable) const {
+ return !(*this == p_callable);
+}
+
+bool Callable::operator<(const Callable &p_callable) const {
+ bool custom_a = is_custom();
+ bool custom_b = p_callable.is_custom();
+
+ if (custom_a == custom_b) {
+ if (custom_a) {
+ if (custom == p_callable.custom) {
+ return false; //same pointer, dont even compare
+ }
+
+ CallableCustom::CompareLessFunc less_a = custom->get_compare_less_func();
+ CallableCustom::CompareLessFunc less_b = p_callable.custom->get_compare_less_func();
+ if (less_a == less_b) {
+ return less_a(custom, p_callable.custom);
+ } else {
+ return less_a < less_b; //it's something..
+ }
+
+ } else {
+ if (object == p_callable.object) {
+ return method < p_callable.method;
+ } else {
+ return object < p_callable.object;
+ }
+ }
+ } else {
+ return int(custom_a ? 1 : 0) < int(custom_b ? 1 : 0);
+ }
+}
+
+void Callable::operator=(const Callable &p_callable) {
+ if (is_custom()) {
+ if (p_callable.is_custom()) {
+ if (custom == p_callable.custom) {
+ return;
+ }
+ }
+
+ if (custom->ref_count.unref()) {
+ memdelete(custom);
+ }
+ }
+
+ if (p_callable.is_custom()) {
+ method = StringName();
+ if (!p_callable.custom->ref_count.ref()) {
+ object = 0;
+ } else {
+ object = 0;
+ custom = p_callable.custom;
+ }
+ } else {
+ method = p_callable.method;
+ object = p_callable.object;
+ }
+}
+
+Callable::operator String() const {
+ if (is_custom()) {
+ return custom->get_as_text();
+ } else {
+ if (is_null()) {
+ return "null::null";
+ }
+
+ Object *base = get_object();
+ if (base) {
+ String class_name = base->get_class();
+ Ref<Script> script = base->get_script();
+ if (script.is_valid() && script->get_path().is_resource_file()) {
+ class_name += "(" + script->get_path().get_file() + ")";
+ }
+ return class_name + "::" + String(method);
+ } else {
+ return "null::" + String(method);
+ }
+ }
+}
+
+Callable::Callable(const Object *p_object, const StringName &p_method) {
+ if (p_method == StringName()) {
+ object = 0;
+ ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string");
+ }
+ if (p_object == nullptr) {
+ object = 0;
+ ERR_FAIL_MSG("Object argument to Callable constructor must be non-null");
+ }
+
+ object = p_object->get_instance_id();
+ method = p_method;
+}
+
+Callable::Callable(ObjectID p_object, const StringName &p_method) {
+ if (p_method == StringName()) {
+ object = 0;
+ ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string");
+ }
+
+ object = p_object;
+ method = p_method;
+}
+
+Callable::Callable(CallableCustom *p_custom) {
+ if (p_custom->referenced) {
+ object = 0;
+ ERR_FAIL_MSG("Callable custom is already referenced");
+ }
+ p_custom->referenced = true;
+ object = 0; //ensure object is all zero, since pointer may be 32 bits
+ custom = p_custom;
+}
+
+Callable::Callable(const Callable &p_callable) {
+ if (p_callable.is_custom()) {
+ if (!p_callable.custom->ref_count.ref()) {
+ object = 0;
+ } else {
+ object = 0;
+ custom = p_callable.custom;
+ }
+ } else {
+ method = p_callable.method;
+ object = p_callable.object;
+ }
+}
+
+Callable::~Callable() {
+ if (is_custom()) {
+ if (custom->ref_count.unref()) {
+ memdelete(custom);
+ }
+ }
+}
+
+const Callable *CallableCustom::get_base_comparator() const {
+ return nullptr;
+}
+
+CallableCustom::CallableCustom() {
+ ref_count.init();
+}
+
+//////////////////////////////////
+
+Object *Signal::get_object() const {
+ return ObjectDB::get_instance(object);
+}
+
+ObjectID Signal::get_object_id() const {
+ return object;
+}
+
+StringName Signal::get_name() const {
+ return name;
+}
+
+bool Signal::operator==(const Signal &p_signal) const {
+ return object == p_signal.object && name == p_signal.name;
+}
+
+bool Signal::operator!=(const Signal &p_signal) const {
+ return object != p_signal.object || name != p_signal.name;
+}
+
+bool Signal::operator<(const Signal &p_signal) const {
+ if (object == p_signal.object) {
+ return name < p_signal.name;
+ } else {
+ return object < p_signal.object;
+ }
+}
+
+Signal::operator String() const {
+ Object *base = get_object();
+ if (base) {
+ String class_name = base->get_class();
+ Ref<Script> script = base->get_script();
+ if (script.is_valid() && script->get_path().is_resource_file()) {
+ class_name += "(" + script->get_path().get_file() + ")";
+ }
+ return class_name + "::[signal]" + String(name);
+ } else {
+ return "null::[signal]" + String(name);
+ }
+}
+
+Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
+ Object *obj = ObjectDB::get_instance(object);
+ if (!obj) {
+ return ERR_INVALID_DATA;
+ }
+
+ return obj->emit_signal(name, p_arguments, p_argcount);
+}
+
+Error Signal::connect(const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) {
+ Object *object = get_object();
+ ERR_FAIL_COND_V(!object, ERR_UNCONFIGURED);
+
+ return object->connect(name, p_callable, p_binds, p_flags);
+}
+
+void Signal::disconnect(const Callable &p_callable) {
+ Object *object = get_object();
+ ERR_FAIL_COND(!object);
+ object->disconnect(name, p_callable);
+}
+
+bool Signal::is_connected(const Callable &p_callable) const {
+ Object *object = get_object();
+ ERR_FAIL_COND_V(!object, false);
+
+ return object->is_connected(name, p_callable);
+}
+
+Array Signal::get_connections() const {
+ Object *object = get_object();
+ if (!object) {
+ return Array();
+ }
+
+ List<Object::Connection> connections;
+ object->get_signal_connection_list(name, &connections);
+
+ Array arr;
+ for (List<Object::Connection>::Element *E = connections.front(); E; E = E->next()) {
+ arr.push_back(E->get());
+ }
+ return arr;
+}
+
+Signal::Signal(const Object *p_object, const StringName &p_name) {
+ ERR_FAIL_COND_MSG(p_object == nullptr, "Object argument to Signal constructor must be non-null");
+
+ object = p_object->get_instance_id();
+ name = p_name;
+}
+
+Signal::Signal(ObjectID p_object, const StringName &p_name) {
+ object = p_object;
+ name = p_name;
+}
diff --git a/core/variant/callable.h b/core/variant/callable.h
new file mode 100644
index 0000000000..40621fbde3
--- /dev/null
+++ b/core/variant/callable.h
@@ -0,0 +1,167 @@
+/*************************************************************************/
+/* callable.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CALLABLE_H
+#define CALLABLE_H
+
+#include "core/object/object_id.h"
+#include "core/string/string_name.h"
+#include "core/templates/list.h"
+
+class Object;
+class Variant;
+class CallableCustom;
+
+// This is an abstraction of things that can be called.
+// It is used for signals and other cases where efficient calling of functions
+// is required. It is designed for the standard case (object and method)
+// but can be optimized or customized.
+
+class Callable {
+ //needs to be max 16 bytes in 64 bits
+ StringName method;
+ union {
+ uint64_t object = 0;
+ CallableCustom *custom;
+ };
+
+public:
+ struct CallError {
+ enum Error {
+ CALL_OK,
+ CALL_ERROR_INVALID_METHOD,
+ CALL_ERROR_INVALID_ARGUMENT, // expected is variant type
+ CALL_ERROR_TOO_MANY_ARGUMENTS, // expected is number of arguments
+ CALL_ERROR_TOO_FEW_ARGUMENTS, // expected is number of arguments
+ CALL_ERROR_INSTANCE_IS_NULL,
+ };
+ Error error;
+ int argument;
+ int expected;
+ };
+
+ void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
+ void call_deferred(const Variant **p_arguments, int p_argcount) const;
+
+ _FORCE_INLINE_ bool is_null() const {
+ return method == StringName() && object == 0;
+ }
+ _FORCE_INLINE_ bool is_custom() const {
+ return method == StringName() && custom != nullptr;
+ }
+ _FORCE_INLINE_ bool is_standard() const {
+ return method != StringName();
+ }
+
+ Callable bind(const Variant **p_arguments, int p_argcount) const;
+ Callable unbind(int p_argcount) const;
+
+ Object *get_object() const;
+ ObjectID get_object_id() const;
+ StringName get_method() const;
+ CallableCustom *get_custom() const;
+
+ uint32_t hash() const;
+
+ const Callable *get_base_comparator() const; //used for bind/unbind to do less precise comparisons (ignoring binds) in signal connect/disconnect
+
+ bool operator==(const Callable &p_callable) const;
+ bool operator!=(const Callable &p_callable) const;
+ bool operator<(const Callable &p_callable) const;
+
+ void operator=(const Callable &p_callable);
+
+ operator String() const;
+
+ Callable(const Object *p_object, const StringName &p_method);
+ Callable(ObjectID p_object, const StringName &p_method);
+ Callable(CallableCustom *p_custom);
+ Callable(const Callable &p_callable);
+ Callable() {}
+ ~Callable();
+};
+
+class CallableCustom {
+ friend class Callable;
+ SafeRefCount ref_count;
+ bool referenced = false;
+
+public:
+ typedef bool (*CompareEqualFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
+ typedef bool (*CompareLessFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
+
+ //for every type that inherits, these must always be the same for this type
+ virtual uint32_t hash() const = 0;
+ virtual String get_as_text() const = 0;
+ virtual CompareEqualFunc get_compare_equal_func() const = 0;
+ virtual CompareLessFunc get_compare_less_func() const = 0;
+ virtual ObjectID get_object() const = 0; //must always be able to provide an object
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const = 0;
+ virtual const Callable *get_base_comparator() const;
+
+ CallableCustom();
+ virtual ~CallableCustom() {}
+};
+
+// This is just a proxy object to object signals, its only
+// allocated on demand by/for scripting languages so it can
+// be put inside a Variant, but it is not
+// used by the engine itself.
+
+class Signal {
+ StringName name;
+ ObjectID object;
+
+public:
+ _FORCE_INLINE_ bool is_null() const {
+ return object.is_null() && name == StringName();
+ }
+ Object *get_object() const;
+ ObjectID get_object_id() const;
+ StringName get_name() const;
+
+ bool operator==(const Signal &p_signal) const;
+ bool operator!=(const Signal &p_signal) const;
+ bool operator<(const Signal &p_signal) const;
+
+ operator String() const;
+
+ Error emit(const Variant **p_arguments, int p_argcount) const;
+ Error connect(const Callable &p_callable, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0);
+ void disconnect(const Callable &p_callable);
+ bool is_connected(const Callable &p_callable) const;
+
+ Array get_connections() const;
+ Signal(const Object *p_object, const StringName &p_name);
+ Signal(ObjectID p_object, const StringName &p_name);
+ Signal() {}
+};
+
+#endif // CALLABLE_H
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
new file mode 100644
index 0000000000..da08d3ccbd
--- /dev/null
+++ b/core/variant/callable_bind.cpp
@@ -0,0 +1,193 @@
+/*************************************************************************/
+/* callable_bind.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "callable_bind.h"
+
+//////////////////////////////////
+
+uint32_t CallableCustomBind::hash() const {
+ return callable.hash();
+}
+String CallableCustomBind::get_as_text() const {
+ return callable.operator String();
+}
+
+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;
+
+ if (!(a->callable != b->callable)) {
+ return false;
+ }
+
+ if (a->binds.size() != b->binds.size()) {
+ return false;
+ }
+
+ return true;
+}
+
+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;
+
+ if (a->callable < b->callable) {
+ return true;
+ } else if (b->callable < a->callable) {
+ return false;
+ }
+
+ return a->binds.size() < b->binds.size();
+}
+
+CallableCustom::CompareEqualFunc CallableCustomBind::get_compare_equal_func() const {
+ return _equal_func;
+}
+CallableCustom::CompareLessFunc CallableCustomBind::get_compare_less_func() const {
+ return _less_func;
+}
+ObjectID CallableCustomBind::get_object() const {
+ return callable.get_object_id();
+}
+const Callable *CallableCustomBind::get_base_comparator() const {
+ return &callable;
+}
+
+void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * (binds.size() + p_argcount));
+ for (int i = 0; i < p_argcount; i++) {
+ args[i] = (const Variant *)p_arguments[i];
+ }
+ for (int i = 0; i < binds.size(); i++) {
+ args[i + p_argcount] = (const Variant *)&binds[i];
+ }
+
+ callable.call(args, p_argcount + binds.size(), r_return_value, r_call_error);
+}
+
+CallableCustomBind::CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds) {
+ callable = p_callable;
+ binds = p_binds;
+}
+
+CallableCustomBind::~CallableCustomBind() {
+}
+
+//////////////////////////////////
+
+uint32_t CallableCustomUnbind::hash() const {
+ return callable.hash();
+}
+String CallableCustomUnbind::get_as_text() const {
+ return callable.operator String();
+}
+
+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;
+
+ if (!(a->callable != b->callable)) {
+ return false;
+ }
+
+ if (a->argcount != b->argcount) {
+ return false;
+ }
+
+ return true;
+}
+
+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;
+
+ if (a->callable < b->callable) {
+ return true;
+ } else if (b->callable < a->callable) {
+ return false;
+ }
+
+ return a->argcount < b->argcount;
+}
+
+CallableCustom::CompareEqualFunc CallableCustomUnbind::get_compare_equal_func() const {
+ return _equal_func;
+}
+CallableCustom::CompareLessFunc CallableCustomUnbind::get_compare_less_func() const {
+ return _less_func;
+}
+ObjectID CallableCustomUnbind::get_object() const {
+ return callable.get_object_id();
+}
+const Callable *CallableCustomUnbind::get_base_comparator() const {
+ return &callable;
+}
+
+void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ if (argcount > p_argcount) {
+ r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_call_error.argument = 0;
+ r_call_error.expected = argcount;
+ return;
+ }
+ callable.call(p_arguments, p_argcount - argcount, r_return_value, r_call_error);
+}
+
+CallableCustomUnbind::CallableCustomUnbind(const Callable &p_callable, int p_argcount) {
+ callable = p_callable;
+ argcount = p_argcount;
+}
+
+CallableCustomUnbind::~CallableCustomUnbind() {
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1) {
+ return p_callable.bind((const Variant **)&p_arg1, 1);
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2) {
+ const Variant *args[2] = { &p_arg1, &p_arg2 };
+ return p_callable.bind(args, 2);
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3) {
+ const Variant *args[3] = { &p_arg1, &p_arg2, &p_arg3 };
+ return p_callable.bind(args, 3);
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4) {
+ const Variant *args[4] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4 };
+ return p_callable.bind(args, 4);
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5) {
+ const Variant *args[5] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4, &p_arg5 };
+ return p_callable.bind(args, 5);
+}
diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h
new file mode 100644
index 0000000000..fc5659e412
--- /dev/null
+++ b/core/variant/callable_bind.h
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* callable_bind.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CALLABLE_BIND_H
+#define CALLABLE_BIND_H
+
+#include "core/variant/callable.h"
+#include "core/variant/variant.h"
+
+class CallableCustomBind : public CallableCustom {
+ Callable callable;
+ Vector<Variant> binds;
+
+ static bool _equal_func(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool _less_func(const CallableCustom *p_a, const CallableCustom *p_b);
+
+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;
+
+ CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds);
+ virtual ~CallableCustomBind();
+};
+
+class CallableCustomUnbind : public CallableCustom {
+ Callable callable;
+ int argcount;
+
+ static bool _equal_func(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool _less_func(const CallableCustom *p_a, const CallableCustom *p_b);
+
+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;
+
+ CallableCustomUnbind(const Callable &p_callable, int p_argcount);
+ virtual ~CallableCustomUnbind();
+};
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1);
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2);
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3);
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4);
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5);
+
+#endif // CALLABLE_BIND_H
diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h
new file mode 100644
index 0000000000..4d3a5f683b
--- /dev/null
+++ b/core/variant/container_type_validate.h
@@ -0,0 +1,126 @@
+/*************************************************************************/
+/* container_type_validate.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CONTAINER_TYPE_VALIDATE_H
+#define CONTAINER_TYPE_VALIDATE_H
+
+#include "core/object/script_language.h"
+#include "core/variant/variant.h"
+
+struct ContainerTypeValidate {
+ Variant::Type type = Variant::NIL;
+ StringName class_name;
+ Ref<Script> script;
+ const char *where = "container";
+
+ _FORCE_INLINE_ bool can_reference(const ContainerTypeValidate &p_type) const {
+ if (type == p_type.type) {
+ if (type != Variant::OBJECT) {
+ return true; //nothing else to check
+ }
+ } else {
+ return false;
+ }
+
+ //both are object
+
+ if ((class_name != StringName()) != (p_type.class_name != StringName())) {
+ return false; //both need to have class or none
+ }
+
+ if (class_name != p_type.class_name) {
+ if (!ClassDB::is_parent_class(p_type.class_name, class_name)) {
+ return false;
+ }
+ }
+
+ if (script.is_null() != p_type.script.is_null()) {
+ return false;
+ }
+
+ if (script != p_type.script) {
+ if (!p_type.script->inherits_script(script)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ _FORCE_INLINE_ bool validate(const Variant &p_variant, const char *p_operation = "use") {
+ if (type == Variant::NIL) {
+ return true;
+ }
+
+ ERR_FAIL_COND_V_MSG(type != p_variant.get_type(), false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
+ if (type != p_variant.get_type()) {
+ return false;
+ }
+
+ if (type != Variant::OBJECT) {
+ return true;
+ }
+#ifdef DEBUG_ENABLED
+ ObjectID object_id = p_variant;
+ if (object_id == ObjectID()) {
+ return true; //fine its 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) + ".");
+#else
+ Object *object = p_variant;
+ if (object == nullptr) {
+ return true; //fine
+ }
+#endif
+ if (class_name == StringName()) {
+ return true; //all good, no class type requested
+ }
+
+ StringName obj_class = object->get_class_name();
+ if (obj_class != class_name) {
+ ERR_FAIL_COND_V_MSG(!ClassDB::is_parent_class(object->get_class_name(), class_name), false, "Attempted to " + String(p_operation) + " an object of type '" + object->get_class() + "' into a " + where + ", which does not inherit from '" + String(class_name) + "'.");
+ }
+
+ if (script.is_null()) {
+ return true; //all good
+ }
+
+ Ref<Script> other_script = object->get_script();
+
+ //check base script..
+ ERR_FAIL_COND_V_MSG(other_script.is_null(), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
+ ERR_FAIL_COND_V_MSG(!other_script->inherits_script(script), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
+
+ return true;
+ }
+};
+
+#endif // CONTAINER_TYPE_VALIDATE_H
diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp
new file mode 100644
index 0000000000..2bc1f7a86d
--- /dev/null
+++ b/core/variant/dictionary.cpp
@@ -0,0 +1,273 @@
+/*************************************************************************/
+/* dictionary.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "dictionary.h"
+
+#include "core/templates/ordered_hash_map.h"
+#include "core/templates/safe_refcount.h"
+#include "core/variant/variant.h"
+
+struct DictionaryPrivate {
+ SafeRefCount refcount;
+ OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> variant_map;
+};
+
+void Dictionary::get_key_list(List<Variant> *p_keys) const {
+ if (_p->variant_map.empty()) {
+ return;
+ }
+
+ for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ p_keys->push_back(E.key());
+ }
+}
+
+Variant Dictionary::get_key_at_index(int p_index) const {
+ int index = 0;
+ for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ if (index == p_index) {
+ return E.key();
+ }
+ index++;
+ }
+
+ return Variant();
+}
+
+Variant Dictionary::get_value_at_index(int p_index) const {
+ int index = 0;
+ for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ if (index == p_index) {
+ return E.value();
+ }
+ index++;
+ }
+
+ return Variant();
+}
+
+Variant &Dictionary::operator[](const Variant &p_key) {
+ return _p->variant_map[p_key];
+}
+
+const Variant &Dictionary::operator[](const Variant &p_key) const {
+ return _p->variant_map[p_key];
+}
+
+const Variant *Dictionary::getptr(const Variant &p_key) const {
+ OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
+
+ if (!E) {
+ return nullptr;
+ }
+ return &E.get();
+}
+
+Variant *Dictionary::getptr(const Variant &p_key) {
+ OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.find(p_key);
+
+ if (!E) {
+ return nullptr;
+ }
+ return &E.get();
+}
+
+Variant Dictionary::get_valid(const Variant &p_key) const {
+ OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
+
+ if (!E) {
+ return Variant();
+ }
+ return E.get();
+}
+
+Variant Dictionary::get(const Variant &p_key, const Variant &p_default) const {
+ const Variant *result = getptr(p_key);
+ if (!result) {
+ return p_default;
+ }
+
+ return *result;
+}
+
+int Dictionary::size() const {
+ return _p->variant_map.size();
+}
+
+bool Dictionary::empty() const {
+ return !_p->variant_map.size();
+}
+
+bool Dictionary::has(const Variant &p_key) const {
+ return _p->variant_map.has(p_key);
+}
+
+bool Dictionary::has_all(const Array &p_keys) const {
+ for (int i = 0; i < p_keys.size(); i++) {
+ if (!has(p_keys[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Dictionary::erase(const Variant &p_key) {
+ return _p->variant_map.erase(p_key);
+}
+
+bool Dictionary::operator==(const Dictionary &p_dictionary) const {
+ return _p == p_dictionary._p;
+}
+
+bool Dictionary::operator!=(const Dictionary &p_dictionary) const {
+ return _p != p_dictionary._p;
+}
+
+void Dictionary::_ref(const Dictionary &p_from) const {
+ //make a copy first (thread safe)
+ if (!p_from._p->refcount.ref()) {
+ return; // couldn't copy
+ }
+
+ //if this is the same, unreference the other one
+ if (p_from._p == _p) {
+ _p->refcount.unref();
+ return;
+ }
+ if (_p) {
+ _unref();
+ }
+ _p = p_from._p;
+}
+
+void Dictionary::clear() {
+ _p->variant_map.clear();
+}
+
+void Dictionary::_unref() const {
+ ERR_FAIL_COND(!_p);
+ if (_p->refcount.unref()) {
+ memdelete(_p);
+ }
+ _p = nullptr;
+}
+
+uint32_t Dictionary::hash() const {
+ uint32_t h = hash_djb2_one_32(Variant::DICTIONARY);
+
+ 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);
+ }
+
+ return h;
+}
+
+Array Dictionary::keys() const {
+ Array varr;
+ if (_p->variant_map.empty()) {
+ return varr;
+ }
+
+ varr.resize(size());
+
+ int i = 0;
+ for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ varr[i] = E.key();
+ i++;
+ }
+
+ return varr;
+}
+
+Array Dictionary::values() const {
+ Array varr;
+ if (_p->variant_map.empty()) {
+ return varr;
+ }
+
+ varr.resize(size());
+
+ int i = 0;
+ for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ varr[i] = E.get();
+ i++;
+ }
+
+ return varr;
+}
+
+const Variant *Dictionary::next(const Variant *p_key) const {
+ if (p_key == nullptr) {
+ // caller wants to get the first element
+ if (_p->variant_map.front()) {
+ return &_p->variant_map.front().key();
+ }
+ return nullptr;
+ }
+ OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.find(*p_key);
+
+ if (E && E.next()) {
+ return &E.next().key();
+ }
+ return nullptr;
+}
+
+Dictionary Dictionary::duplicate(bool p_deep) 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();
+ }
+
+ return n;
+}
+
+void Dictionary::operator=(const Dictionary &p_dictionary) {
+ _ref(p_dictionary);
+}
+
+const void *Dictionary::id() const {
+ return _p->variant_map.id();
+}
+
+Dictionary::Dictionary(const Dictionary &p_from) {
+ _p = nullptr;
+ _ref(p_from);
+}
+
+Dictionary::Dictionary() {
+ _p = memnew(DictionaryPrivate);
+ _p->refcount.init();
+}
+
+Dictionary::~Dictionary() {
+ _unref();
+}
diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h
new file mode 100644
index 0000000000..bbe94122ad
--- /dev/null
+++ b/core/variant/dictionary.h
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* dictionary.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef DICTIONARY_H
+#define DICTIONARY_H
+
+#include "core/string/ustring.h"
+#include "core/templates/list.h"
+#include "core/variant/array.h"
+
+class Variant;
+
+struct DictionaryPrivate;
+
+class Dictionary {
+ mutable DictionaryPrivate *_p;
+
+ void _ref(const Dictionary &p_from) const;
+ void _unref() const;
+
+public:
+ void get_key_list(List<Variant> *p_keys) const;
+ Variant get_key_at_index(int p_index) const;
+ Variant get_value_at_index(int p_index) const;
+
+ Variant &operator[](const Variant &p_key);
+ const Variant &operator[](const Variant &p_key) const;
+
+ const Variant *getptr(const Variant &p_key) const;
+ Variant *getptr(const Variant &p_key);
+
+ Variant get_valid(const Variant &p_key) const;
+ Variant get(const Variant &p_key, const Variant &p_default) const;
+
+ int size() const;
+ bool empty() const;
+ void clear();
+
+ bool has(const Variant &p_key) const;
+ bool has_all(const Array &p_keys) const;
+
+ bool erase(const Variant &p_key);
+
+ bool operator==(const Dictionary &p_dictionary) const;
+ bool operator!=(const Dictionary &p_dictionary) const;
+
+ uint32_t hash() const;
+ void operator=(const Dictionary &p_dictionary);
+
+ const Variant *next(const Variant *p_key = nullptr) const;
+
+ Array keys() const;
+ Array values() const;
+
+ Dictionary duplicate(bool p_deep = false) const;
+
+ const void *id() const;
+
+ Dictionary(const Dictionary &p_from);
+ Dictionary();
+ ~Dictionary();
+};
+
+#endif // DICTIONARY_H
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
new file mode 100644
index 0000000000..936de145f8
--- /dev/null
+++ b/core/variant/method_ptrcall.h
@@ -0,0 +1,453 @@
+/*************************************************************************/
+/* method_ptrcall.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef 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"
+
+#ifdef PTRCALL_ENABLED
+
+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); \
+ } \
+ _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); \
+ } \
+ _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) \
+ template <> \
+ struct PtrToArg<m_type> { \
+ _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
+ return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
+ } \
+ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
+ *((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<const m_type &> { \
+ _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
+ return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
+ } \
+ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
+ *((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
+ } \
+ }
+
+#define MAKE_PTRARG_BY_REFERENCE(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); \
+ } \
+ _FORCE_INLINE_ static void encode(const 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); \
+ } \
+ _FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
+ *((m_type *)p_ptr) = p_val; \
+ } \
+ }
+
+MAKE_PTRARG(bool);
+MAKE_PTRARGCONV(uint8_t, int64_t);
+MAKE_PTRARGCONV(int8_t, int64_t);
+MAKE_PTRARGCONV(uint16_t, int64_t);
+MAKE_PTRARGCONV(int16_t, int64_t);
+MAKE_PTRARGCONV(uint32_t, int64_t);
+MAKE_PTRARGCONV(int32_t, int64_t);
+MAKE_PTRARG(int64_t);
+MAKE_PTRARG(uint64_t);
+MAKE_PTRARGCONV(float, double);
+MAKE_PTRARG(double);
+
+MAKE_PTRARG(String);
+MAKE_PTRARG(Vector2);
+MAKE_PTRARG(Rect2);
+MAKE_PTRARG_BY_REFERENCE(Vector3);
+MAKE_PTRARG(Vector2i);
+MAKE_PTRARG(Rect2i);
+MAKE_PTRARG_BY_REFERENCE(Vector3i);
+MAKE_PTRARG(Transform2D);
+MAKE_PTRARG_BY_REFERENCE(Plane);
+MAKE_PTRARG(Quat);
+MAKE_PTRARG_BY_REFERENCE(AABB);
+MAKE_PTRARG_BY_REFERENCE(Basis);
+MAKE_PTRARG_BY_REFERENCE(Transform);
+MAKE_PTRARG_BY_REFERENCE(Color);
+MAKE_PTRARG(StringName);
+MAKE_PTRARG(NodePath);
+MAKE_PTRARG(RID);
+MAKE_PTRARG(Dictionary);
+MAKE_PTRARG(Callable);
+MAKE_PTRARG(Signal);
+MAKE_PTRARG(Array);
+MAKE_PTRARG(PackedByteArray);
+MAKE_PTRARG(PackedInt32Array);
+MAKE_PTRARG(PackedInt64Array);
+MAKE_PTRARG(PackedFloat32Array);
+MAKE_PTRARG(PackedFloat64Array);
+MAKE_PTRARG(PackedStringArray);
+MAKE_PTRARG(PackedVector2Array);
+MAKE_PTRARG(PackedVector3Array);
+MAKE_PTRARG(PackedColorArray);
+MAKE_PTRARG_BY_REFERENCE(Variant);
+
+//this is for Object
+
+template <class T>
+struct PtrToArg<T *> {
+ _FORCE_INLINE_ static T *convert(const void *p_ptr) {
+ return const_cast<T *>(reinterpret_cast<const T *>(p_ptr));
+ }
+
+ _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
+ *((T **)p_ptr) = p_var;
+ }
+};
+
+template <class T>
+struct PtrToArg<const T *> {
+ _FORCE_INLINE_ static const T *convert(const void *p_ptr) {
+ return reinterpret_cast<const T *>(p_ptr);
+ }
+
+ _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
+ *((T **)p_ptr) = p_var;
+ }
+};
+
+//this is for ObjectID
+
+template <>
+struct PtrToArg<ObjectID> {
+ _FORCE_INLINE_ static const ObjectID convert(const void *p_ptr) {
+ return ObjectID(*reinterpret_cast<const uint64_t *>(p_ptr));
+ }
+
+ _FORCE_INLINE_ static void encode(const ObjectID &p_val, void *p_ptr) {
+ *((uint64_t *)p_ptr) = p_val;
+ }
+};
+
+//this is for the special cases used by Variant
+
+#define MAKE_VECARG(m_type) \
+ template <> \
+ struct PtrToArg<Vector<m_type>> { \
+ _FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
+ const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
+ Vector<m_type> ret; \
+ int len = dvs->size(); \
+ ret.resize(len); \
+ { \
+ const m_type *r = dvs->ptr(); \
+ for (int i = 0; i < len; i++) { \
+ ret.write[i] = r[i]; \
+ } \
+ } \
+ return ret; \
+ } \
+ _FORCE_INLINE_ static void encode(Vector<m_type> p_vec, void *p_ptr) { \
+ Vector<m_type> *dv = reinterpret_cast<Vector<m_type> *>(p_ptr); \
+ int len = p_vec.size(); \
+ dv->resize(len); \
+ { \
+ m_type *w = dv->ptrw(); \
+ for (int i = 0; i < len; i++) { \
+ w[i] = p_vec[i]; \
+ } \
+ } \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<const Vector<m_type> &> { \
+ _FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
+ const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
+ Vector<m_type> ret; \
+ int len = dvs->size(); \
+ ret.resize(len); \
+ { \
+ const m_type *r = dvs->ptr(); \
+ for (int i = 0; i < len; i++) { \
+ ret.write[i] = r[i]; \
+ } \
+ } \
+ return ret; \
+ } \
+ }
+
+#define MAKE_VECARG_ALT(m_type, m_type_alt) \
+ template <> \
+ struct PtrToArg<Vector<m_type_alt>> { \
+ _FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \
+ const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
+ Vector<m_type_alt> ret; \
+ int len = dvs->size(); \
+ ret.resize(len); \
+ { \
+ const m_type *r = dvs->ptr(); \
+ for (int i = 0; i < len; i++) { \
+ ret.write[i] = r[i]; \
+ } \
+ } \
+ return ret; \
+ } \
+ _FORCE_INLINE_ static void encode(Vector<m_type_alt> p_vec, void *p_ptr) { \
+ Vector<m_type> *dv = reinterpret_cast<Vector<m_type> *>(p_ptr); \
+ int len = p_vec.size(); \
+ dv->resize(len); \
+ { \
+ m_type *w = dv->ptrw(); \
+ for (int i = 0; i < len; i++) { \
+ w[i] = p_vec[i]; \
+ } \
+ } \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<const Vector<m_type_alt> &> { \
+ _FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \
+ const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
+ Vector<m_type_alt> ret; \
+ int len = dvs->size(); \
+ ret.resize(len); \
+ { \
+ const m_type *r = dvs->ptr(); \
+ for (int i = 0; i < len; i++) { \
+ ret.write[i] = r[i]; \
+ } \
+ } \
+ return ret; \
+ } \
+ }
+/*
+MAKE_VECARG(String);
+MAKE_VECARG(uint8_t);
+MAKE_VECARG(int);
+MAKE_VECARG(float);
+MAKE_VECARG(Vector2);
+MAKE_VECARG(Vector3);
+MAKE_VECARG(Color);
+*/
+MAKE_VECARG_ALT(String, StringName);
+
+//for stuff that gets converted to Array vectors
+#define MAKE_VECARR(m_type) \
+ template <> \
+ struct PtrToArg<Vector<m_type>> { \
+ _FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
+ const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
+ Vector<m_type> ret; \
+ int len = arr->size(); \
+ ret.resize(len); \
+ for (int i = 0; i < len; i++) { \
+ ret.write[i] = (*arr)[i]; \
+ } \
+ return ret; \
+ } \
+ _FORCE_INLINE_ static void encode(Vector<m_type> p_vec, void *p_ptr) { \
+ Array *arr = reinterpret_cast<Array *>(p_ptr); \
+ int len = p_vec.size(); \
+ arr->resize(len); \
+ for (int i = 0; i < len; i++) { \
+ (*arr)[i] = p_vec[i]; \
+ } \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<const Vector<m_type> &> { \
+ _FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
+ const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
+ Vector<m_type> ret; \
+ int len = arr->size(); \
+ ret.resize(len); \
+ for (int i = 0; i < len; i++) { \
+ ret.write[i] = (*arr)[i]; \
+ } \
+ return ret; \
+ } \
+ }
+
+MAKE_VECARR(Variant);
+MAKE_VECARR(RID);
+MAKE_VECARR(Plane);
+
+#define MAKE_DVECARR(m_type) \
+ template <> \
+ struct PtrToArg<Vector<m_type>> { \
+ _FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
+ const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
+ Vector<m_type> ret; \
+ int len = arr->size(); \
+ ret.resize(len); \
+ { \
+ m_type *w = ret.ptrw(); \
+ for (int i = 0; i < len; i++) { \
+ w[i] = (*arr)[i]; \
+ } \
+ } \
+ return ret; \
+ } \
+ _FORCE_INLINE_ static void encode(Vector<m_type> p_vec, void *p_ptr) { \
+ Array *arr = reinterpret_cast<Array *>(p_ptr); \
+ int len = p_vec.size(); \
+ arr->resize(len); \
+ { \
+ const m_type *r = p_vec.ptr(); \
+ for (int i = 0; i < len; i++) { \
+ (*arr)[i] = r[i]; \
+ } \
+ } \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<const Vector<m_type> &> { \
+ _FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
+ const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
+ Vector<m_type> ret; \
+ int len = arr->size(); \
+ ret.resize(len); \
+ { \
+ m_type *w = ret.ptrw(); \
+ for (int i = 0; i < len; i++) { \
+ w[i] = (*arr)[i]; \
+ } \
+ } \
+ return ret; \
+ } \
+ }
+
+// Special case for IP_Address.
+
+#define MAKE_STRINGCONV_BY_REFERENCE(m_type) \
+ template <> \
+ struct PtrToArg<m_type> { \
+ _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
+ m_type s = *reinterpret_cast<const String *>(p_ptr); \
+ return s; \
+ } \
+ _FORCE_INLINE_ static void encode(const m_type &p_vec, void *p_ptr) { \
+ String *arr = reinterpret_cast<String *>(p_ptr); \
+ *arr = p_vec; \
+ } \
+ }; \
+ \
+ template <> \
+ struct PtrToArg<const m_type &> { \
+ _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
+ m_type s = *reinterpret_cast<const String *>(p_ptr); \
+ return s; \
+ } \
+ }
+
+MAKE_STRINGCONV_BY_REFERENCE(IP_Address);
+
+template <>
+struct PtrToArg<Vector<Face3>> {
+ _FORCE_INLINE_ static Vector<Face3> convert(const void *p_ptr) {
+ const Vector<Vector3> *dvs = reinterpret_cast<const Vector<Vector3> *>(p_ptr);
+ Vector<Face3> ret;
+ int len = dvs->size() / 3;
+ ret.resize(len);
+ {
+ const Vector3 *r = dvs->ptr();
+ Face3 *w = ret.ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i].vertex[0] = r[i * 3 + 0];
+ w[i].vertex[1] = r[i * 3 + 1];
+ w[i].vertex[2] = r[i * 3 + 2];
+ }
+ }
+ return ret;
+ }
+ _FORCE_INLINE_ static void encode(Vector<Face3> p_vec, void *p_ptr) {
+ Vector<Vector3> *arr = reinterpret_cast<Vector<Vector3> *>(p_ptr);
+ int len = p_vec.size();
+ arr->resize(len * 3);
+ {
+ const Face3 *r = p_vec.ptr();
+ Vector3 *w = arr->ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i * 3 + 0] = r[i].vertex[0];
+ w[i * 3 + 1] = r[i].vertex[1];
+ w[i * 3 + 2] = r[i].vertex[2];
+ }
+ }
+ }
+};
+template <>
+struct PtrToArg<const Vector<Face3> &> {
+ _FORCE_INLINE_ static Vector<Face3> convert(const void *p_ptr) {
+ const Vector<Vector3> *dvs = reinterpret_cast<const Vector<Vector3> *>(p_ptr);
+ Vector<Face3> ret;
+ int len = dvs->size() / 3;
+ ret.resize(len);
+ {
+ const Vector3 *r = dvs->ptr();
+ Face3 *w = ret.ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i].vertex[0] = r[i * 3 + 0];
+ w[i].vertex[1] = r[i * 3 + 1];
+ w[i].vertex[2] = r[i * 3 + 2];
+ }
+ }
+ return ret;
+ }
+};
+
+#endif // METHOD_PTRCALL_H
+#endif
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
new file mode 100644
index 0000000000..b9ae88d97c
--- /dev/null
+++ b/core/variant/type_info.h
@@ -0,0 +1,270 @@
+/*************************************************************************/
+/* type_info.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TYPE_INFO_H
+#define TYPE_INFO_H
+
+#include "core/typedefs.h"
+
+template <bool C, typename T = void>
+struct EnableIf {
+ typedef T type;
+};
+
+template <typename T>
+struct EnableIf<false, T> {
+};
+
+template <typename, typename>
+struct TypesAreSame {
+ static bool const value = false;
+};
+
+template <typename A>
+struct TypesAreSame<A, A> {
+ static bool const value = true;
+};
+
+template <typename B, typename D>
+struct TypeInherits {
+ static D *get_d();
+
+ static char (&test(B *))[1];
+ static char (&test(...))[2];
+
+ static bool const value = sizeof(test(get_d())) == sizeof(char) &&
+ !TypesAreSame<B volatile const, void volatile const>::value;
+};
+
+namespace GodotTypeInfo {
+enum Metadata {
+ METADATA_NONE,
+ METADATA_INT_IS_INT8,
+ METADATA_INT_IS_INT16,
+ METADATA_INT_IS_INT32,
+ METADATA_INT_IS_INT64,
+ METADATA_INT_IS_UINT8,
+ METADATA_INT_IS_UINT16,
+ METADATA_INT_IS_UINT32,
+ METADATA_INT_IS_UINT64,
+ METADATA_REAL_IS_FLOAT,
+ METADATA_REAL_IS_DOUBLE
+};
+}
+
+// If the compiler fails because it's trying to instantiate the primary 'GetTypeInfo' template
+// instead of one of the specializations, it's most likely because the type 'T' is not supported.
+// If 'T' is a class that inherits 'Object', make sure it can see the actual class declaration
+// instead of a forward declaration. You can always forward declare 'T' in a header file, and then
+// include the actual declaration of 'T' in the source file where 'GetTypeInfo<T>' is instantiated.
+template <class T, typename = void>
+struct GetTypeInfo;
+
+#define MAKE_TYPE_INFO(m_type, m_var_type) \
+ template <> \
+ struct GetTypeInfo<m_type> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_type &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ };
+
+#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \
+ template <> \
+ struct GetTypeInfo<m_type> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = m_metadata; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_type &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = m_metadata; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ };
+
+MAKE_TYPE_INFO(bool, Variant::BOOL)
+MAKE_TYPE_INFO_WITH_META(uint8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT8)
+MAKE_TYPE_INFO_WITH_META(int8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT8)
+MAKE_TYPE_INFO_WITH_META(uint16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT16)
+MAKE_TYPE_INFO_WITH_META(int16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT16)
+MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT32)
+MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32)
+MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64)
+MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64)
+MAKE_TYPE_INFO(char16_t, Variant::INT)
+MAKE_TYPE_INFO(char32_t, Variant::INT)
+MAKE_TYPE_INFO_WITH_META(float, Variant::FLOAT, GodotTypeInfo::METADATA_REAL_IS_FLOAT)
+MAKE_TYPE_INFO_WITH_META(double, Variant::FLOAT, GodotTypeInfo::METADATA_REAL_IS_DOUBLE)
+
+MAKE_TYPE_INFO(String, Variant::STRING)
+MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
+MAKE_TYPE_INFO(Rect2, Variant::RECT2)
+MAKE_TYPE_INFO(Vector3, Variant::VECTOR3)
+MAKE_TYPE_INFO(Vector2i, Variant::VECTOR2I)
+MAKE_TYPE_INFO(Rect2i, Variant::RECT2I)
+MAKE_TYPE_INFO(Vector3i, Variant::VECTOR3I)
+MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D)
+MAKE_TYPE_INFO(Plane, Variant::PLANE)
+MAKE_TYPE_INFO(Quat, Variant::QUAT)
+MAKE_TYPE_INFO(AABB, Variant::AABB)
+MAKE_TYPE_INFO(Basis, Variant::BASIS)
+MAKE_TYPE_INFO(Transform, Variant::TRANSFORM)
+MAKE_TYPE_INFO(Color, Variant::COLOR)
+MAKE_TYPE_INFO(StringName, Variant::STRING_NAME)
+MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH)
+MAKE_TYPE_INFO(RID, Variant::_RID)
+MAKE_TYPE_INFO(Callable, Variant::CALLABLE)
+MAKE_TYPE_INFO(Signal, Variant::SIGNAL)
+MAKE_TYPE_INFO(Dictionary, Variant::DICTIONARY)
+MAKE_TYPE_INFO(Array, Variant::ARRAY)
+MAKE_TYPE_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
+MAKE_TYPE_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
+MAKE_TYPE_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
+MAKE_TYPE_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
+MAKE_TYPE_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
+MAKE_TYPE_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
+MAKE_TYPE_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
+MAKE_TYPE_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
+MAKE_TYPE_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
+
+MAKE_TYPE_INFO(IP_Address, Variant::STRING)
+
+//objectID
+template <>
+struct GetTypeInfo<ObjectID> {
+ static const Variant::Type VARIANT_TYPE = Variant::INT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_INT_IS_UINT64;
+ static inline PropertyInfo get_class_info() {
+ return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_OBJECTID);
+ }
+};
+
+//for variant
+template <>
+struct GetTypeInfo<Variant> {
+ static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
+ static inline PropertyInfo get_class_info() {
+ return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
+ }
+};
+
+template <>
+struct GetTypeInfo<const Variant &> {
+ static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
+ static inline PropertyInfo get_class_info() {
+ return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
+ }
+};
+
+#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \
+ template <> \
+ struct GetTypeInfo<m_template<m_type>> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_template<m_type> &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ };
+
+MAKE_TEMPLATE_TYPE_INFO(Vector, Variant, Variant::ARRAY)
+MAKE_TEMPLATE_TYPE_INFO(Vector, RID, Variant::ARRAY)
+MAKE_TEMPLATE_TYPE_INFO(Vector, Plane, Variant::ARRAY)
+MAKE_TEMPLATE_TYPE_INFO(Vector, Face3, Variant::PACKED_VECTOR3_ARRAY)
+MAKE_TEMPLATE_TYPE_INFO(Vector, StringName, Variant::PACKED_STRING_ARRAY)
+
+template <typename T>
+struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
+ static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
+ static inline PropertyInfo get_class_info() {
+ return PropertyInfo(StringName(T::get_class_static()));
+ }
+};
+
+template <typename T>
+struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
+ static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
+ static inline PropertyInfo get_class_info() {
+ return PropertyInfo(StringName(T::get_class_static()));
+ }
+};
+
+#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \
+ template <> \
+ struct GetTypeInfo<m_impl> { \
+ static const Variant::Type VARIANT_TYPE = Variant::INT; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, String(#m_enum).replace("::", ".")); \
+ } \
+ };
+
+#define MAKE_ENUM_TYPE_INFO(m_enum) \
+ TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum) \
+ TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum const) \
+ TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum &) \
+ TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &)
+
+template <typename T>
+inline StringName __constant_get_enum_name(T param, const String &p_constant) {
+ if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
+ ERR_PRINT("Missing VARIANT_ENUM_CAST for constant's enum: " + p_constant);
+ }
+ return GetTypeInfo<T>::get_class_info().class_name;
+}
+
+#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
+
+#endif // TYPE_INFO_H
diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h
new file mode 100644
index 0000000000..0f3985b2f1
--- /dev/null
+++ b/core/variant/typed_array.h
@@ -0,0 +1,227 @@
+/*************************************************************************/
+/* typed_array.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TYPED_ARRAY_H
+#define TYPED_ARRAY_H
+
+#include "core/variant/array.h"
+#include "core/variant/method_ptrcall.h"
+#include "core/variant/variant.h"
+
+template <class T>
+class TypedArray : public Array {
+public:
+ template <class U>
+ _FORCE_INLINE_ void operator=(const TypedArray<U> &p_array) {
+ static_assert(__is_base_of(T, U));
+ _assign(p_array);
+ }
+
+ _FORCE_INLINE_ void operator=(const Array &p_array) {
+ _assign(p_array);
+ }
+ _FORCE_INLINE_ TypedArray(const Variant &p_variant) :
+ Array(Array(p_variant), Variant::OBJECT, T::get_class_static(), Variant()) {
+ }
+ _FORCE_INLINE_ TypedArray(const Array &p_array) :
+ Array(p_array, Variant::OBJECT, T::get_class_static(), Variant()) {
+ }
+ _FORCE_INLINE_ TypedArray() {
+ set_typed(Variant::OBJECT, T::get_class_static(), Variant());
+ }
+};
+
+//specialization for the rest of variant types
+
+#define MAKE_TYPED_ARRAY(m_type, m_variant_type) \
+ template <> \
+ class TypedArray<m_type> : public Array { \
+ public: \
+ _FORCE_INLINE_ void operator=(const Array &p_array) { \
+ _assign(p_array); \
+ } \
+ _FORCE_INLINE_ TypedArray(const Variant &p_variant) : \
+ Array(Array(p_variant), m_variant_type, StringName(), Variant()) { \
+ } \
+ _FORCE_INLINE_ TypedArray(const Array &p_array) : \
+ Array(p_array, m_variant_type, StringName(), Variant()) { \
+ } \
+ _FORCE_INLINE_ TypedArray() { \
+ set_typed(m_variant_type, StringName(), Variant()); \
+ } \
+ };
+
+MAKE_TYPED_ARRAY(bool, Variant::BOOL)
+MAKE_TYPED_ARRAY(uint8_t, Variant::INT)
+MAKE_TYPED_ARRAY(int8_t, Variant::INT)
+MAKE_TYPED_ARRAY(uint16_t, Variant::INT)
+MAKE_TYPED_ARRAY(int16_t, Variant::INT)
+MAKE_TYPED_ARRAY(uint32_t, Variant::INT)
+MAKE_TYPED_ARRAY(int32_t, Variant::INT)
+MAKE_TYPED_ARRAY(uint64_t, Variant::INT)
+MAKE_TYPED_ARRAY(int64_t, Variant::INT)
+MAKE_TYPED_ARRAY(float, Variant::FLOAT)
+MAKE_TYPED_ARRAY(double, Variant::FLOAT)
+MAKE_TYPED_ARRAY(String, Variant::STRING)
+MAKE_TYPED_ARRAY(Vector2, Variant::VECTOR2)
+MAKE_TYPED_ARRAY(Vector2i, Variant::VECTOR2I)
+MAKE_TYPED_ARRAY(Rect2, Variant::RECT2)
+MAKE_TYPED_ARRAY(Rect2i, Variant::RECT2I)
+MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3)
+MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I)
+MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D)
+MAKE_TYPED_ARRAY(Plane, Variant::PLANE)
+MAKE_TYPED_ARRAY(Quat, Variant::QUAT)
+MAKE_TYPED_ARRAY(AABB, Variant::AABB)
+MAKE_TYPED_ARRAY(Basis, Variant::BASIS)
+MAKE_TYPED_ARRAY(Transform, Variant::TRANSFORM)
+MAKE_TYPED_ARRAY(Color, Variant::COLOR)
+MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
+MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH)
+MAKE_TYPED_ARRAY(RID, Variant::_RID)
+MAKE_TYPED_ARRAY(Callable, Variant::CALLABLE)
+MAKE_TYPED_ARRAY(Signal, Variant::SIGNAL)
+MAKE_TYPED_ARRAY(Dictionary, Variant::DICTIONARY)
+MAKE_TYPED_ARRAY(Array, Variant::ARRAY)
+MAKE_TYPED_ARRAY(Vector<uint8_t>, Variant::PACKED_BYTE_ARRAY)
+MAKE_TYPED_ARRAY(Vector<int32_t>, Variant::PACKED_INT32_ARRAY)
+MAKE_TYPED_ARRAY(Vector<int64_t>, Variant::PACKED_INT64_ARRAY)
+MAKE_TYPED_ARRAY(Vector<float>, Variant::PACKED_FLOAT32_ARRAY)
+MAKE_TYPED_ARRAY(Vector<double>, Variant::PACKED_FLOAT64_ARRAY)
+MAKE_TYPED_ARRAY(Vector<String>, Variant::PACKED_STRING_ARRAY)
+MAKE_TYPED_ARRAY(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
+MAKE_TYPED_ARRAY(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
+MAKE_TYPED_ARRAY(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
+
+#ifdef PTRCALL_ENABLED
+
+template <class T>
+struct PtrToArg<TypedArray<T>> {
+ _FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
+ return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
+ }
+
+ _FORCE_INLINE_ static void encode(TypedArray<T> p_val, void *p_ptr) {
+ *(Array *)p_ptr = p_val;
+ }
+};
+
+template <class T>
+struct PtrToArg<const TypedArray<T> &> {
+ _FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
+ return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
+ }
+};
+
+#endif // PTRCALL_ENABLED
+
+#ifdef DEBUG_METHODS_ENABLED
+
+template <class T>
+struct GetTypeInfo<TypedArray<T>> {
+ static const Variant::Type VARIANT_TYPE = Variant::ARRAY;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
+ static inline PropertyInfo get_class_info() {
+ return PropertyInfo(Variant::ARRAY, String(), PROPERTY_HINT_ARRAY_TYPE, T::get_class_static());
+ }
+};
+
+template <class T>
+struct GetTypeInfo<const TypedArray<T> &> {
+ static const Variant::Type VARIANT_TYPE = Variant::ARRAY;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
+ static inline PropertyInfo get_class_info() {
+ return PropertyInfo(Variant::ARRAY, String(), PROPERTY_HINT_ARRAY_TYPE, T::get_class_static());
+ }
+};
+
+#define MAKE_TYPED_ARRAY_INFO(m_type, m_variant_type) \
+ template <> \
+ struct GetTypeInfo<TypedArray<m_type>> { \
+ static const Variant::Type VARIANT_TYPE = Variant::ARRAY; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(Variant::ARRAY, String(), PROPERTY_HINT_ARRAY_TYPE, Variant::get_type_name(m_variant_type)); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const TypedArray<m_type> &> { \
+ static const Variant::Type VARIANT_TYPE = Variant::ARRAY; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(Variant::ARRAY, String(), PROPERTY_HINT_ARRAY_TYPE, Variant::get_type_name(m_variant_type)); \
+ } \
+ };
+
+MAKE_TYPED_ARRAY_INFO(bool, Variant::BOOL)
+MAKE_TYPED_ARRAY_INFO(uint8_t, Variant::INT)
+MAKE_TYPED_ARRAY_INFO(int8_t, Variant::INT)
+MAKE_TYPED_ARRAY_INFO(uint16_t, Variant::INT)
+MAKE_TYPED_ARRAY_INFO(int16_t, Variant::INT)
+MAKE_TYPED_ARRAY_INFO(uint32_t, Variant::INT)
+MAKE_TYPED_ARRAY_INFO(int32_t, Variant::INT)
+MAKE_TYPED_ARRAY_INFO(uint64_t, Variant::INT)
+MAKE_TYPED_ARRAY_INFO(int64_t, Variant::INT)
+MAKE_TYPED_ARRAY_INFO(float, Variant::FLOAT)
+MAKE_TYPED_ARRAY_INFO(double, Variant::FLOAT)
+MAKE_TYPED_ARRAY_INFO(String, Variant::STRING)
+MAKE_TYPED_ARRAY_INFO(Vector2, Variant::VECTOR2)
+MAKE_TYPED_ARRAY_INFO(Vector2i, Variant::VECTOR2I)
+MAKE_TYPED_ARRAY_INFO(Rect2, Variant::RECT2)
+MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
+MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
+MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
+MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
+MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
+MAKE_TYPED_ARRAY_INFO(Quat, Variant::QUAT)
+MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
+MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
+MAKE_TYPED_ARRAY_INFO(Transform, Variant::TRANSFORM)
+MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
+MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
+MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
+MAKE_TYPED_ARRAY_INFO(RID, Variant::_RID)
+MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
+MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
+MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
+MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY)
+MAKE_TYPED_ARRAY_INFO(Vector<uint8_t>, Variant::PACKED_BYTE_ARRAY)
+MAKE_TYPED_ARRAY_INFO(Vector<int32_t>, Variant::PACKED_INT32_ARRAY)
+MAKE_TYPED_ARRAY_INFO(Vector<int64_t>, Variant::PACKED_INT64_ARRAY)
+MAKE_TYPED_ARRAY_INFO(Vector<float>, Variant::PACKED_FLOAT32_ARRAY)
+MAKE_TYPED_ARRAY_INFO(Vector<double>, Variant::PACKED_FLOAT64_ARRAY)
+MAKE_TYPED_ARRAY_INFO(Vector<String>, Variant::PACKED_STRING_ARRAY)
+MAKE_TYPED_ARRAY_INFO(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
+MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
+MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
+
+#endif
+
+#endif // TYPED_ARRAY_H
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
new file mode 100644
index 0000000000..126420bd02
--- /dev/null
+++ b/core/variant/variant.cpp
@@ -0,0 +1,3521 @@
+/*************************************************************************/
+/* variant.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "variant.h"
+
+#include "core/core_string_names.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/io/marshalls.h"
+#include "core/io/resource.h"
+#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) {
+ case NIL: {
+ return "Nil";
+ } break;
+
+ // atomic types
+ case BOOL: {
+ return "bool";
+ } break;
+ case INT: {
+ return "int";
+
+ } break;
+ case FLOAT: {
+ return "float";
+
+ } break;
+ case STRING: {
+ return "String";
+ } break;
+
+ // math types
+ case VECTOR2: {
+ return "Vector2";
+ } break;
+ case VECTOR2I: {
+ return "Vector2i";
+ } break;
+ case RECT2: {
+ return "Rect2";
+ } break;
+ case RECT2I: {
+ return "Rect2i";
+ } break;
+ case TRANSFORM2D: {
+ return "Transform2D";
+ } break;
+ case VECTOR3: {
+ return "Vector3";
+ } break;
+ case VECTOR3I: {
+ return "Vector3i";
+ } break;
+ case PLANE: {
+ return "Plane";
+
+ } break;
+ case AABB: {
+ return "AABB";
+ } break;
+ case QUAT: {
+ return "Quat";
+
+ } break;
+ case BASIS: {
+ return "Basis";
+
+ } break;
+ case TRANSFORM: {
+ return "Transform";
+
+ } break;
+
+ // misc types
+ case COLOR: {
+ return "Color";
+
+ } break;
+ case _RID: {
+ return "RID";
+ } break;
+ case OBJECT: {
+ return "Object";
+ } break;
+ case CALLABLE: {
+ return "Callable";
+ } break;
+ case SIGNAL: {
+ return "Signal";
+ } break;
+ case STRING_NAME: {
+ return "StringName";
+
+ } break;
+ case NODE_PATH: {
+ return "NodePath";
+
+ } break;
+ case DICTIONARY: {
+ return "Dictionary";
+
+ } break;
+ case ARRAY: {
+ return "Array";
+
+ } break;
+
+ // arrays
+ case PACKED_BYTE_ARRAY: {
+ return "PackedByteArray";
+
+ } break;
+ case PACKED_INT32_ARRAY: {
+ return "PackedInt32Array";
+
+ } break;
+ case PACKED_INT64_ARRAY: {
+ return "PackedInt64Array";
+
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ return "PackedFloat32Array";
+
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ return "PackedFloat64Array";
+
+ } break;
+ case PACKED_STRING_ARRAY: {
+ return "PackedStringArray";
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ return "PackedVector2Array";
+
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ return "PackedVector3Array";
+
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ return "PackedColorArray";
+
+ } break;
+ default: {
+ }
+ }
+
+ return "";
+}
+
+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
+ return true;
+ }
+
+ if (p_type_from == NIL) {
+ return (p_type_to == OBJECT);
+ }
+
+ const Type *valid_types = nullptr;
+ const Type *invalid_types = nullptr;
+
+ switch (p_type_to) {
+ case BOOL: {
+ static const Type valid[] = {
+ INT,
+ FLOAT,
+ STRING,
+ NIL,
+ };
+
+ valid_types = valid;
+ } break;
+ case INT: {
+ static const Type valid[] = {
+ BOOL,
+ FLOAT,
+ STRING,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case FLOAT: {
+ static const Type valid[] = {
+ BOOL,
+ INT,
+ STRING,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case STRING: {
+ static const Type invalid[] = {
+ OBJECT,
+ NIL
+ };
+
+ invalid_types = invalid;
+ } break;
+ case VECTOR2: {
+ static const Type valid[] = {
+ VECTOR2I,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case VECTOR2I: {
+ static const Type valid[] = {
+ VECTOR2,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case RECT2: {
+ static const Type valid[] = {
+ RECT2I,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case RECT2I: {
+ static const Type valid[] = {
+ RECT2,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case TRANSFORM2D: {
+ static const Type valid[] = {
+ TRANSFORM,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case VECTOR3: {
+ static const Type valid[] = {
+ VECTOR3I,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case VECTOR3I: {
+ static const Type valid[] = {
+ VECTOR3,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+
+ case QUAT: {
+ static const Type valid[] = {
+ BASIS,
+ NIL
+ };
+
+ valid_types = valid;
+
+ } break;
+ case BASIS: {
+ static const Type valid[] = {
+ QUAT,
+ VECTOR3,
+ NIL
+ };
+
+ valid_types = valid;
+
+ } break;
+ case TRANSFORM: {
+ static const Type valid[] = {
+ TRANSFORM2D,
+ QUAT,
+ BASIS,
+ NIL
+ };
+
+ valid_types = valid;
+
+ } break;
+
+ case COLOR: {
+ static const Type valid[] = {
+ STRING,
+ INT,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+
+ case _RID: {
+ static const Type valid[] = {
+ OBJECT,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case OBJECT: {
+ static const Type valid[] = {
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case STRING_NAME: {
+ static const Type valid[] = {
+ STRING,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case NODE_PATH: {
+ static const Type valid[] = {
+ STRING,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case ARRAY: {
+ static const Type valid[] = {
+ PACKED_BYTE_ARRAY,
+ PACKED_INT32_ARRAY,
+ PACKED_INT64_ARRAY,
+ PACKED_FLOAT32_ARRAY,
+ PACKED_FLOAT64_ARRAY,
+ PACKED_STRING_ARRAY,
+ PACKED_COLOR_ARRAY,
+ PACKED_VECTOR2_ARRAY,
+ PACKED_VECTOR3_ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ // arrays
+ case PACKED_BYTE_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case PACKED_INT32_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+ } break;
+ case PACKED_INT64_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case PACKED_STRING_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+
+ } break;
+ default: {
+ }
+ }
+
+ if (valid_types) {
+ int i = 0;
+ while (valid_types[i] != NIL) {
+ if (p_type_from == valid_types[i]) {
+ return true;
+ }
+ i++;
+ }
+
+ } else if (invalid_types) {
+ int i = 0;
+ while (invalid_types[i] != NIL) {
+ if (p_type_from == invalid_types[i]) {
+ return false;
+ }
+ i++;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Variant::can_convert_strict(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
+ return true;
+ }
+
+ if (p_type_from == NIL) {
+ return (p_type_to == OBJECT);
+ }
+
+ const Type *valid_types = nullptr;
+
+ switch (p_type_to) {
+ case BOOL: {
+ static const Type valid[] = {
+ INT,
+ FLOAT,
+ //STRING,
+ NIL,
+ };
+
+ valid_types = valid;
+ } break;
+ case INT: {
+ static const Type valid[] = {
+ BOOL,
+ FLOAT,
+ //STRING,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case FLOAT: {
+ static const Type valid[] = {
+ BOOL,
+ INT,
+ //STRING,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case STRING: {
+ static const Type valid[] = {
+ NODE_PATH,
+ STRING_NAME,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case VECTOR2: {
+ static const Type valid[] = {
+ VECTOR2I,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case VECTOR2I: {
+ static const Type valid[] = {
+ VECTOR2,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case RECT2: {
+ static const Type valid[] = {
+ RECT2I,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case RECT2I: {
+ static const Type valid[] = {
+ RECT2,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case TRANSFORM2D: {
+ static const Type valid[] = {
+ TRANSFORM,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case VECTOR3: {
+ static const Type valid[] = {
+ VECTOR3I,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+ case VECTOR3I: {
+ static const Type valid[] = {
+ VECTOR3,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+
+ case QUAT: {
+ static const Type valid[] = {
+ BASIS,
+ NIL
+ };
+
+ valid_types = valid;
+
+ } break;
+ case BASIS: {
+ static const Type valid[] = {
+ QUAT,
+ VECTOR3,
+ NIL
+ };
+
+ valid_types = valid;
+
+ } break;
+ case TRANSFORM: {
+ static const Type valid[] = {
+ TRANSFORM2D,
+ QUAT,
+ BASIS,
+ NIL
+ };
+
+ valid_types = valid;
+
+ } break;
+
+ case COLOR: {
+ static const Type valid[] = {
+ STRING,
+ INT,
+ NIL,
+ };
+
+ valid_types = valid;
+
+ } break;
+
+ case _RID: {
+ static const Type valid[] = {
+ OBJECT,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case OBJECT: {
+ static const Type valid[] = {
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case STRING_NAME: {
+ static const Type valid[] = {
+ STRING,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case NODE_PATH: {
+ static const Type valid[] = {
+ STRING,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case ARRAY: {
+ static const Type valid[] = {
+ PACKED_BYTE_ARRAY,
+ PACKED_INT32_ARRAY,
+ PACKED_INT64_ARRAY,
+ PACKED_FLOAT32_ARRAY,
+ PACKED_FLOAT64_ARRAY,
+ PACKED_STRING_ARRAY,
+ PACKED_COLOR_ARRAY,
+ PACKED_VECTOR2_ARRAY,
+ PACKED_VECTOR3_ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ // arrays
+ case PACKED_BYTE_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case PACKED_INT32_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+ } break;
+ case PACKED_INT64_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+ } break;
+ case PACKED_STRING_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+ valid_types = valid;
+
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ static const Type valid[] = {
+ ARRAY,
+ NIL
+ };
+
+ valid_types = valid;
+
+ } break;
+ default: {
+ }
+ }
+
+ if (valid_types) {
+ int i = 0;
+ while (valid_types[i] != NIL) {
+ if (p_type_from == valid_types[i]) {
+ return true;
+ }
+ i++;
+ }
+ }
+
+ return false;
+}
+
+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;
+}
+
+bool Variant::operator!=(const Variant &p_variant) const {
+ if (type != p_variant.type) { //evaluation of operator== needs to be more strict
+ return true;
+ }
+ bool v;
+ Variant r;
+ evaluate(OP_NOT_EQUAL, *this, p_variant, r, v);
+ return r;
+}
+
+bool Variant::operator<(const Variant &p_variant) const {
+ if (type != p_variant.type) { //if types differ, then order by type first
+ return type < p_variant.type;
+ }
+ bool v;
+ Variant r;
+ evaluate(OP_LESS, *this, p_variant, r, v);
+ return r;
+}
+
+bool Variant::is_zero() const {
+ switch (type) {
+ case NIL: {
+ return true;
+ } break;
+
+ // atomic types
+ case BOOL: {
+ return !(_data._bool);
+ } break;
+ case INT: {
+ return _data._int == 0;
+
+ } break;
+ case FLOAT: {
+ return _data._float == 0;
+
+ } break;
+ case STRING: {
+ return *reinterpret_cast<const String *>(_data._mem) == String();
+
+ } break;
+
+ // math types
+ case VECTOR2: {
+ return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2();
+
+ } break;
+ case VECTOR2I: {
+ return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i();
+
+ } break;
+ case RECT2: {
+ return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2();
+
+ } break;
+ case RECT2I: {
+ return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i();
+
+ } break;
+ case TRANSFORM2D: {
+ return *_data._transform2d == Transform2D();
+
+ } break;
+ case VECTOR3: {
+ return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3();
+
+ } break;
+ case VECTOR3I: {
+ return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i();
+
+ } break;
+ case PLANE: {
+ return *reinterpret_cast<const Plane *>(_data._mem) == Plane();
+
+ } break;
+ case AABB: {
+ return *_data._aabb == ::AABB();
+ } break;
+ case QUAT: {
+ return *reinterpret_cast<const Quat *>(_data._mem) == Quat();
+
+ } break;
+ case BASIS: {
+ return *_data._basis == Basis();
+
+ } break;
+ case TRANSFORM: {
+ return *_data._transform == Transform();
+
+ } break;
+
+ // misc types
+ case COLOR: {
+ return *reinterpret_cast<const Color *>(_data._mem) == Color();
+
+ } break;
+ case _RID: {
+ return *reinterpret_cast<const RID *>(_data._mem) == RID();
+ } break;
+ case OBJECT: {
+ return _get_obj().obj == nullptr;
+ } break;
+ case CALLABLE: {
+ return reinterpret_cast<const Callable *>(_data._mem)->is_null();
+ } break;
+ case SIGNAL: {
+ return reinterpret_cast<const Signal *>(_data._mem)->is_null();
+ } break;
+ case STRING_NAME: {
+ return *reinterpret_cast<const StringName *>(_data._mem) != StringName();
+
+ } break;
+ case NODE_PATH: {
+ return reinterpret_cast<const NodePath *>(_data._mem)->is_empty();
+
+ } break;
+ case DICTIONARY: {
+ return reinterpret_cast<const Dictionary *>(_data._mem)->empty();
+
+ } break;
+ case ARRAY: {
+ return reinterpret_cast<const Array *>(_data._mem)->empty();
+
+ } break;
+
+ // arrays
+ case PACKED_BYTE_ARRAY: {
+ return PackedArrayRef<uint8_t>::get_array(_data.packed_array).size() == 0;
+
+ } break;
+ case PACKED_INT32_ARRAY: {
+ return PackedArrayRef<int32_t>::get_array(_data.packed_array).size() == 0;
+
+ } break;
+ case PACKED_INT64_ARRAY: {
+ return PackedArrayRef<int64_t>::get_array(_data.packed_array).size() == 0;
+
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ return PackedArrayRef<float>::get_array(_data.packed_array).size() == 0;
+
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ return PackedArrayRef<double>::get_array(_data.packed_array).size() == 0;
+
+ } break;
+ case PACKED_STRING_ARRAY: {
+ return PackedArrayRef<String>::get_array(_data.packed_array).size() == 0;
+
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ return PackedArrayRef<Vector2>::get_array(_data.packed_array).size() == 0;
+
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ return PackedArrayRef<Vector3>::get_array(_data.packed_array).size() == 0;
+
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ return PackedArrayRef<Color>::get_array(_data.packed_array).size() == 0;
+
+ } break;
+ default: {
+ }
+ }
+
+ return false;
+}
+
+bool Variant::is_one() const {
+ switch (type) {
+ case NIL: {
+ return true;
+ } break;
+
+ // atomic types
+ case BOOL: {
+ return _data._bool;
+ } break;
+ case INT: {
+ return _data._int == 1;
+
+ } break;
+ case FLOAT: {
+ return _data._float == 1;
+
+ } break;
+ case VECTOR2: {
+ return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2(1, 1);
+
+ } break;
+ case VECTOR2I: {
+ return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i(1, 1);
+
+ } break;
+ case RECT2: {
+ return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2(1, 1, 1, 1);
+
+ } break;
+ case RECT2I: {
+ return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i(1, 1, 1, 1);
+
+ } break;
+ case VECTOR3: {
+ return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3(1, 1, 1);
+
+ } break;
+ case VECTOR3I: {
+ return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i(1, 1, 1);
+
+ } break;
+ case PLANE: {
+ return *reinterpret_cast<const Plane *>(_data._mem) == Plane(1, 1, 1, 1);
+
+ } break;
+ case COLOR: {
+ return *reinterpret_cast<const Color *>(_data._mem) == Color(1, 1, 1, 1);
+
+ } break;
+
+ default: {
+ return !is_zero();
+ }
+ }
+
+ return false;
+}
+
+bool Variant::is_null() const {
+ if (type == OBJECT && _get_obj().obj) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void Variant::reference(const Variant &p_variant) {
+ switch (type) {
+ case NIL:
+ case BOOL:
+ case INT:
+ case FLOAT:
+ break;
+ default:
+ clear();
+ }
+
+ type = p_variant.type;
+
+ switch (p_variant.type) {
+ case NIL: {
+ // none
+ } break;
+
+ // atomic types
+ case BOOL: {
+ _data._bool = p_variant._data._bool;
+ } break;
+ case INT: {
+ _data._int = p_variant._data._int;
+ } break;
+ case FLOAT: {
+ _data._float = p_variant._data._float;
+ } break;
+ case STRING: {
+ memnew_placement(_data._mem, String(*reinterpret_cast<const String *>(p_variant._data._mem)));
+ } break;
+
+ // math types
+ case VECTOR2: {
+ memnew_placement(_data._mem, Vector2(*reinterpret_cast<const Vector2 *>(p_variant._data._mem)));
+ } break;
+ case VECTOR2I: {
+ memnew_placement(_data._mem, Vector2i(*reinterpret_cast<const Vector2i *>(p_variant._data._mem)));
+ } break;
+ case RECT2: {
+ memnew_placement(_data._mem, Rect2(*reinterpret_cast<const Rect2 *>(p_variant._data._mem)));
+ } break;
+ case RECT2I: {
+ memnew_placement(_data._mem, Rect2i(*reinterpret_cast<const Rect2i *>(p_variant._data._mem)));
+ } break;
+ case TRANSFORM2D: {
+ _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d));
+ } break;
+ case VECTOR3: {
+ memnew_placement(_data._mem, Vector3(*reinterpret_cast<const Vector3 *>(p_variant._data._mem)));
+ } break;
+ case VECTOR3I: {
+ memnew_placement(_data._mem, Vector3i(*reinterpret_cast<const Vector3i *>(p_variant._data._mem)));
+ } break;
+ case PLANE: {
+ memnew_placement(_data._mem, Plane(*reinterpret_cast<const Plane *>(p_variant._data._mem)));
+ } break;
+
+ case AABB: {
+ _data._aabb = memnew(::AABB(*p_variant._data._aabb));
+ } break;
+ case QUAT: {
+ memnew_placement(_data._mem, Quat(*reinterpret_cast<const Quat *>(p_variant._data._mem)));
+
+ } break;
+ case BASIS: {
+ _data._basis = memnew(Basis(*p_variant._data._basis));
+
+ } break;
+ case TRANSFORM: {
+ _data._transform = memnew(Transform(*p_variant._data._transform));
+ } break;
+
+ // misc types
+ case COLOR: {
+ memnew_placement(_data._mem, Color(*reinterpret_cast<const Color *>(p_variant._data._mem)));
+
+ } break;
+ case _RID: {
+ memnew_placement(_data._mem, RID(*reinterpret_cast<const RID *>(p_variant._data._mem)));
+ } break;
+ case OBJECT: {
+ memnew_placement(_data._mem, ObjData);
+
+ if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) {
+ Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj);
+ if (!reference->reference()) {
+ _get_obj().obj = nullptr;
+ _get_obj().id = ObjectID();
+ break;
+ }
+ }
+
+ _get_obj().obj = const_cast<Object *>(p_variant._get_obj().obj);
+ _get_obj().id = p_variant._get_obj().id;
+
+ } break;
+ case CALLABLE: {
+ memnew_placement(_data._mem, Callable(*reinterpret_cast<const Callable *>(p_variant._data._mem)));
+ } break;
+ case SIGNAL: {
+ memnew_placement(_data._mem, Signal(*reinterpret_cast<const Signal *>(p_variant._data._mem)));
+ } break;
+ case STRING_NAME: {
+ memnew_placement(_data._mem, StringName(*reinterpret_cast<const StringName *>(p_variant._data._mem)));
+
+ } break;
+ case NODE_PATH: {
+ memnew_placement(_data._mem, NodePath(*reinterpret_cast<const NodePath *>(p_variant._data._mem)));
+
+ } break;
+ case DICTIONARY: {
+ memnew_placement(_data._mem, Dictionary(*reinterpret_cast<const Dictionary *>(p_variant._data._mem)));
+
+ } break;
+ case ARRAY: {
+ memnew_placement(_data._mem, Array(*reinterpret_cast<const Array *>(p_variant._data._mem)));
+
+ } break;
+
+ // arrays
+ case PACKED_BYTE_ARRAY: {
+ _data.packed_array = static_cast<PackedArrayRef<uint8_t> *>(p_variant._data.packed_array)->reference();
+ if (!_data.packed_array) {
+ _data.packed_array = PackedArrayRef<uint8_t>::create();
+ }
+
+ } break;
+ case PACKED_INT32_ARRAY: {
+ _data.packed_array = static_cast<PackedArrayRef<int32_t> *>(p_variant._data.packed_array)->reference();
+ if (!_data.packed_array) {
+ _data.packed_array = PackedArrayRef<int32_t>::create();
+ }
+
+ } break;
+ case PACKED_INT64_ARRAY: {
+ _data.packed_array = static_cast<PackedArrayRef<int64_t> *>(p_variant._data.packed_array)->reference();
+ if (!_data.packed_array) {
+ _data.packed_array = PackedArrayRef<int64_t>::create();
+ }
+
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ _data.packed_array = static_cast<PackedArrayRef<float> *>(p_variant._data.packed_array)->reference();
+ if (!_data.packed_array) {
+ _data.packed_array = PackedArrayRef<float>::create();
+ }
+
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ _data.packed_array = static_cast<PackedArrayRef<double> *>(p_variant._data.packed_array)->reference();
+ if (!_data.packed_array) {
+ _data.packed_array = PackedArrayRef<double>::create();
+ }
+
+ } break;
+ case PACKED_STRING_ARRAY: {
+ _data.packed_array = static_cast<PackedArrayRef<String> *>(p_variant._data.packed_array)->reference();
+ if (!_data.packed_array) {
+ _data.packed_array = PackedArrayRef<String>::create();
+ }
+
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ _data.packed_array = static_cast<PackedArrayRef<Vector2> *>(p_variant._data.packed_array)->reference();
+ if (!_data.packed_array) {
+ _data.packed_array = PackedArrayRef<Vector2>::create();
+ }
+
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ _data.packed_array = static_cast<PackedArrayRef<Vector3> *>(p_variant._data.packed_array)->reference();
+ if (!_data.packed_array) {
+ _data.packed_array = PackedArrayRef<Vector3>::create();
+ }
+
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ _data.packed_array = static_cast<PackedArrayRef<Color> *>(p_variant._data.packed_array)->reference();
+ if (!_data.packed_array) {
+ _data.packed_array = PackedArrayRef<Color>::create();
+ }
+
+ } break;
+ default: {
+ }
+ }
+}
+
+void Variant::zero() {
+ switch (type) {
+ case NIL:
+ break;
+ case BOOL:
+ this->_data._bool = false;
+ break;
+ case INT:
+ this->_data._int = 0;
+ break;
+ case FLOAT:
+ this->_data._float = 0;
+ break;
+ case VECTOR2:
+ *reinterpret_cast<Vector2 *>(this->_data._mem) = Vector2();
+ break;
+ case VECTOR2I:
+ *reinterpret_cast<Vector2i *>(this->_data._mem) = Vector2i();
+ break;
+ case RECT2:
+ *reinterpret_cast<Rect2 *>(this->_data._mem) = Rect2();
+ break;
+ case RECT2I:
+ *reinterpret_cast<Rect2i *>(this->_data._mem) = Rect2i();
+ break;
+ case VECTOR3:
+ *reinterpret_cast<Vector3 *>(this->_data._mem) = Vector3();
+ break;
+ case VECTOR3I:
+ *reinterpret_cast<Vector3i *>(this->_data._mem) = Vector3i();
+ break;
+ case PLANE:
+ *reinterpret_cast<Plane *>(this->_data._mem) = Plane();
+ break;
+ case QUAT:
+ *reinterpret_cast<Quat *>(this->_data._mem) = Quat();
+ break;
+ case COLOR:
+ *reinterpret_cast<Color *>(this->_data._mem) = Color();
+ break;
+ default:
+ this->clear();
+ break;
+ }
+}
+
+void Variant::clear() {
+ switch (type) {
+ case STRING: {
+ reinterpret_cast<String *>(_data._mem)->~String();
+ } break;
+ /*
+ // no point, they don't allocate memory
+ VECTOR3,
+ PLANE,
+ QUAT,
+ COLOR,
+ VECTOR2,
+ RECT2
+ */
+ case TRANSFORM2D: {
+ memdelete(_data._transform2d);
+ } break;
+ case AABB: {
+ memdelete(_data._aabb);
+ } break;
+ case BASIS: {
+ memdelete(_data._basis);
+ } break;
+ case TRANSFORM: {
+ memdelete(_data._transform);
+ } break;
+
+ // misc types
+ case STRING_NAME: {
+ reinterpret_cast<StringName *>(_data._mem)->~StringName();
+ } break;
+ case NODE_PATH: {
+ reinterpret_cast<NodePath *>(_data._mem)->~NodePath();
+ } break;
+ case OBJECT: {
+ if (_get_obj().id.is_reference()) {
+ //we are safe that there is a reference here
+ Reference *reference = static_cast<Reference *>(_get_obj().obj);
+ if (reference->unreference()) {
+ memdelete(reference);
+ }
+ }
+ _get_obj().obj = nullptr;
+ _get_obj().id = ObjectID();
+ } break;
+ case _RID: {
+ // not much need probably
+ reinterpret_cast<RID *>(_data._mem)->~RID();
+ } break;
+ case CALLABLE: {
+ reinterpret_cast<Callable *>(_data._mem)->~Callable();
+ } break;
+ case SIGNAL: {
+ reinterpret_cast<Signal *>(_data._mem)->~Signal();
+ } break;
+ case DICTIONARY: {
+ reinterpret_cast<Dictionary *>(_data._mem)->~Dictionary();
+ } break;
+ case ARRAY: {
+ reinterpret_cast<Array *>(_data._mem)->~Array();
+ } break;
+ // arrays
+ case PACKED_BYTE_ARRAY: {
+ PackedArrayRefBase::destroy(_data.packed_array);
+ } break;
+ case PACKED_INT32_ARRAY: {
+ PackedArrayRefBase::destroy(_data.packed_array);
+ } break;
+ case PACKED_INT64_ARRAY: {
+ PackedArrayRefBase::destroy(_data.packed_array);
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ PackedArrayRefBase::destroy(_data.packed_array);
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ PackedArrayRefBase::destroy(_data.packed_array);
+ } break;
+ case PACKED_STRING_ARRAY: {
+ PackedArrayRefBase::destroy(_data.packed_array);
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ PackedArrayRefBase::destroy(_data.packed_array);
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ PackedArrayRefBase::destroy(_data.packed_array);
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ PackedArrayRefBase::destroy(_data.packed_array);
+ } break;
+ default: {
+ } /* not needed */
+ }
+
+ type = NIL;
+}
+
+Variant::operator signed int() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator unsigned int() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator int64_t() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator uint64_t() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator ObjectID() const {
+ if (type == INT) {
+ return ObjectID(_data._int);
+ } else if (type == OBJECT) {
+ return _get_obj().id;
+ } else {
+ return ObjectID();
+ }
+}
+
+#ifdef NEED_LONG_INT
+Variant::operator signed long() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+Variant::operator unsigned long() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+Variant::operator signed short() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator unsigned short() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator signed char() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator unsigned char() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1 : 0;
+ case INT:
+ return _data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_int();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator char32_t() const {
+ return operator unsigned int();
+}
+
+Variant::operator float() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1.0 : 0.0;
+ case INT:
+ return (float)_data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_float();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator double() const {
+ switch (type) {
+ case NIL:
+ return 0;
+ case BOOL:
+ return _data._bool ? 1.0 : 0.0;
+ case INT:
+ return (double)_data._int;
+ case FLOAT:
+ return _data._float;
+ case STRING:
+ return operator String().to_float();
+ default: {
+ return 0;
+ }
+ }
+}
+
+Variant::operator StringName() const {
+ if (type == STRING_NAME) {
+ return *reinterpret_cast<const StringName *>(_data._mem);
+ } else if (type == STRING) {
+ return *reinterpret_cast<const String *>(_data._mem);
+ }
+
+ return StringName();
+}
+
+struct _VariantStrPair {
+ String key;
+ String value;
+
+ bool operator<(const _VariantStrPair &p) const {
+ return key < p.key;
+ }
+};
+
+Variant::operator String() const {
+ List<const void *> stack;
+
+ return stringify(stack);
+}
+
+String Variant::stringify(List<const void *> &stack) const {
+ switch (type) {
+ case NIL:
+ return "Null";
+ case BOOL:
+ return _data._bool ? "True" : "False";
+ case INT:
+ return itos(_data._int);
+ case FLOAT:
+ return rtos(_data._float);
+ case STRING:
+ return *reinterpret_cast<const String *>(_data._mem);
+ case VECTOR2:
+ return "(" + operator Vector2() + ")";
+ case VECTOR2I:
+ return "(" + operator Vector2i() + ")";
+ case RECT2:
+ return "(" + operator Rect2() + ")";
+ case RECT2I:
+ return "(" + operator Rect2i() + ")";
+ case TRANSFORM2D: {
+ Transform2D mat32 = operator Transform2D();
+ return "(" + Variant(mat32.elements[0]).operator String() + ", " + Variant(mat32.elements[1]).operator String() + ", " + Variant(mat32.elements[2]).operator String() + ")";
+ } break;
+ case VECTOR3:
+ return "(" + operator Vector3() + ")";
+ case VECTOR3I:
+ return "(" + operator Vector3i() + ")";
+ case PLANE:
+ return operator Plane();
+ //case QUAT:
+ case AABB:
+ return operator ::AABB();
+ case QUAT:
+ return "(" + operator Quat() + ")";
+ case BASIS: {
+ Basis mat3 = operator Basis();
+
+ String mtx("(");
+ for (int i = 0; i < 3; i++) {
+ if (i != 0) {
+ mtx += ", ";
+ }
+
+ mtx += "(";
+
+ for (int j = 0; j < 3; j++) {
+ if (j != 0) {
+ mtx += ", ";
+ }
+
+ mtx += Variant(mat3.elements[i][j]).operator String();
+ }
+
+ mtx += ")";
+ }
+
+ return mtx + ")";
+ } break;
+ case TRANSFORM:
+ return operator Transform();
+ case STRING_NAME:
+ return operator StringName();
+ case NODE_PATH:
+ return operator NodePath();
+ case COLOR:
+ return String::num(operator Color().r) + "," + String::num(operator Color().g) + "," + String::num(operator Color().b) + "," + String::num(operator Color().a);
+ case DICTIONARY: {
+ const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem);
+ if (stack.find(d.id())) {
+ return "{...}";
+ }
+
+ stack.push_back(d.id());
+
+ //const String *K=nullptr;
+ String str("{");
+ List<Variant> keys;
+ d.get_key_list(&keys);
+
+ Vector<_VariantStrPair> pairs;
+
+ for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
+ _VariantStrPair sp;
+ sp.key = E->get().stringify(stack);
+ sp.value = d[E->get()].stringify(stack);
+
+ pairs.push_back(sp);
+ }
+
+ pairs.sort();
+
+ for (int i = 0; i < pairs.size(); i++) {
+ if (i > 0) {
+ str += ", ";
+ }
+ str += pairs[i].key + ":" + pairs[i].value;
+ }
+ str += "}";
+
+ 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;
+ } 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;
+ } 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;
+ } 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;
+ } 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;
+ } 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;
+ } 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;
+ } break;
+ case ARRAY: {
+ Array arr = operator Array();
+ if (stack.find(arr.id())) {
+ 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 += "]";
+ return str;
+
+ } break;
+ case OBJECT: {
+ if (_get_obj().obj) {
+ if (!_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ return "[Freed Object]";
+ }
+
+ return _get_obj().obj->to_string();
+ } else {
+ return "[Object:null]";
+ }
+
+ } break;
+ case CALLABLE: {
+ const Callable &c = *reinterpret_cast<const Callable *>(_data._mem);
+ return c;
+ } break;
+ case SIGNAL: {
+ const Signal &s = *reinterpret_cast<const Signal *>(_data._mem);
+ return s;
+ } break;
+ case _RID: {
+ const RID &s = *reinterpret_cast<const RID *>(_data._mem);
+ return "RID(" + itos(s.get_id()) + ")";
+ } break;
+ default: {
+ return "[" + get_type_name(type) + "]";
+ }
+ }
+
+ return "";
+}
+
+Variant::operator Vector2() const {
+ if (type == VECTOR2) {
+ return *reinterpret_cast<const Vector2 *>(_data._mem);
+ } else if (type == VECTOR2I) {
+ return *reinterpret_cast<const Vector2i *>(_data._mem);
+ } else if (type == VECTOR3) {
+ return Vector2(reinterpret_cast<const Vector3 *>(_data._mem)->x, reinterpret_cast<const Vector3 *>(_data._mem)->y);
+ } else if (type == VECTOR3I) {
+ return Vector2(reinterpret_cast<const Vector3i *>(_data._mem)->x, reinterpret_cast<const Vector3i *>(_data._mem)->y);
+ } else {
+ return Vector2();
+ }
+}
+
+Variant::operator Vector2i() const {
+ if (type == VECTOR2I) {
+ return *reinterpret_cast<const Vector2i *>(_data._mem);
+ } else if (type == VECTOR2) {
+ return *reinterpret_cast<const Vector2 *>(_data._mem);
+ } else if (type == VECTOR3) {
+ return Vector2(reinterpret_cast<const Vector3 *>(_data._mem)->x, reinterpret_cast<const Vector3 *>(_data._mem)->y);
+ } else if (type == VECTOR3I) {
+ return Vector2(reinterpret_cast<const Vector3i *>(_data._mem)->x, reinterpret_cast<const Vector3i *>(_data._mem)->y);
+ } else {
+ return Vector2i();
+ }
+}
+
+Variant::operator Rect2() const {
+ if (type == RECT2) {
+ return *reinterpret_cast<const Rect2 *>(_data._mem);
+ } else if (type == RECT2I) {
+ return *reinterpret_cast<const Rect2i *>(_data._mem);
+ } else {
+ return Rect2();
+ }
+}
+
+Variant::operator Rect2i() const {
+ if (type == RECT2I) {
+ return *reinterpret_cast<const Rect2i *>(_data._mem);
+ } else if (type == RECT2) {
+ return *reinterpret_cast<const Rect2 *>(_data._mem);
+ } else {
+ return Rect2i();
+ }
+}
+
+Variant::operator Vector3() const {
+ if (type == VECTOR3) {
+ return *reinterpret_cast<const Vector3 *>(_data._mem);
+ } else if (type == VECTOR3I) {
+ return *reinterpret_cast<const Vector3i *>(_data._mem);
+ } else if (type == VECTOR2) {
+ return Vector3(reinterpret_cast<const Vector2 *>(_data._mem)->x, reinterpret_cast<const Vector2 *>(_data._mem)->y, 0.0);
+ } else if (type == VECTOR2I) {
+ return Vector3(reinterpret_cast<const Vector2i *>(_data._mem)->x, reinterpret_cast<const Vector2i *>(_data._mem)->y, 0.0);
+ } else {
+ return Vector3();
+ }
+}
+
+Variant::operator Vector3i() const {
+ if (type == VECTOR3I) {
+ return *reinterpret_cast<const Vector3i *>(_data._mem);
+ } else if (type == VECTOR3) {
+ return *reinterpret_cast<const Vector3 *>(_data._mem);
+ } else if (type == VECTOR2) {
+ return Vector3i(reinterpret_cast<const Vector2 *>(_data._mem)->x, reinterpret_cast<const Vector2 *>(_data._mem)->y, 0.0);
+ } else if (type == VECTOR2I) {
+ return Vector3i(reinterpret_cast<const Vector2i *>(_data._mem)->x, reinterpret_cast<const Vector2i *>(_data._mem)->y, 0.0);
+ } else {
+ return Vector3i();
+ }
+}
+
+Variant::operator Plane() const {
+ if (type == PLANE) {
+ return *reinterpret_cast<const Plane *>(_data._mem);
+ } else {
+ return Plane();
+ }
+}
+
+Variant::operator ::AABB() const {
+ if (type == AABB) {
+ return *_data._aabb;
+ } else {
+ return ::AABB();
+ }
+}
+
+Variant::operator Basis() const {
+ if (type == BASIS) {
+ return *_data._basis;
+ } else if (type == QUAT) {
+ return *reinterpret_cast<const Quat *>(_data._mem);
+ } else if (type == VECTOR3) {
+ return Basis(*reinterpret_cast<const Vector3 *>(_data._mem));
+ } else if (type == TRANSFORM) { // unexposed in Variant::can_convert?
+ return _data._transform->basis;
+ } else {
+ return Basis();
+ }
+}
+
+Variant::operator Quat() const {
+ if (type == QUAT) {
+ return *reinterpret_cast<const Quat *>(_data._mem);
+ } else if (type == BASIS) {
+ return *_data._basis;
+ } else if (type == TRANSFORM) {
+ return _data._transform->basis;
+ } else {
+ return Quat();
+ }
+}
+
+Variant::operator Transform() const {
+ if (type == TRANSFORM) {
+ return *_data._transform;
+ } else if (type == BASIS) {
+ return Transform(*_data._basis, Vector3());
+ } else if (type == QUAT) {
+ return Transform(Basis(*reinterpret_cast<const Quat *>(_data._mem)), Vector3());
+ } else if (type == TRANSFORM2D) {
+ const Transform2D &t = *_data._transform2d;
+ Transform m;
+ m.basis.elements[0][0] = t.elements[0][0];
+ m.basis.elements[1][0] = t.elements[0][1];
+ m.basis.elements[0][1] = t.elements[1][0];
+ m.basis.elements[1][1] = t.elements[1][1];
+ m.origin[0] = t.elements[2][0];
+ m.origin[1] = t.elements[2][1];
+ return m;
+ } else {
+ return Transform();
+ }
+}
+
+Variant::operator Transform2D() const {
+ if (type == TRANSFORM2D) {
+ return *_data._transform2d;
+ } else if (type == TRANSFORM) {
+ const Transform &t = *_data._transform;
+ Transform2D m;
+ m.elements[0][0] = t.basis.elements[0][0];
+ m.elements[0][1] = t.basis.elements[1][0];
+ m.elements[1][0] = t.basis.elements[0][1];
+ m.elements[1][1] = t.basis.elements[1][1];
+ m.elements[2][0] = t.origin[0];
+ m.elements[2][1] = t.origin[1];
+ return m;
+ } else {
+ return Transform2D();
+ }
+}
+
+Variant::operator Color() const {
+ if (type == COLOR) {
+ return *reinterpret_cast<const Color *>(_data._mem);
+ } else if (type == STRING) {
+ return Color::html(operator String());
+ } else if (type == INT) {
+ return Color::hex(operator int());
+ } else {
+ return Color();
+ }
+}
+
+Variant::operator NodePath() const {
+ if (type == NODE_PATH) {
+ return *reinterpret_cast<const NodePath *>(_data._mem);
+ } else if (type == STRING) {
+ return NodePath(operator String());
+ } else {
+ return NodePath();
+ }
+}
+
+Variant::operator RID() const {
+ if (type == _RID) {
+ return *reinterpret_cast<const RID *>(_data._mem);
+ } else if (type == OBJECT && _get_obj().obj == nullptr) {
+ return RID();
+ } 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).");
+ }
+#endif
+ Callable::CallError ce;
+ Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce);
+ if (ce.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::_RID) {
+ return ret;
+ }
+ return RID();
+ } else {
+ return RID();
+ }
+}
+
+Variant::operator Object *() const {
+ if (type == OBJECT) {
+ return _get_obj().obj;
+ } else {
+ return nullptr;
+ }
+}
+
+Object *Variant::get_validated_object_with_check(bool &r_previously_freed) const {
+ if (type == OBJECT) {
+ Object *instance = ObjectDB::get_instance(_get_obj().id);
+ r_previously_freed = !instance && _get_obj().id != ObjectID();
+ return instance;
+ } else {
+ r_previously_freed = false;
+ return nullptr;
+ }
+}
+
+Object *Variant::get_validated_object() const {
+ if (type == OBJECT) {
+ return ObjectDB::get_instance(_get_obj().id);
+ } else {
+ return nullptr;
+ }
+}
+
+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);
+ } else {
+ return Dictionary();
+ }
+}
+
+Variant::operator Callable() const {
+ if (type == CALLABLE) {
+ return *reinterpret_cast<const Callable *>(_data._mem);
+ } else {
+ return Callable();
+ }
+}
+
+Variant::operator Signal() const {
+ if (type == SIGNAL) {
+ return *reinterpret_cast<const Signal *>(_data._mem);
+ } else {
+ return Signal();
+ }
+}
+
+template <class DA, class SA>
+inline DA _convert_array(const SA &p_array) {
+ DA da;
+ da.resize(p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+ da.set(i, Variant(p_array.get(i)));
+ }
+
+ return da;
+}
+
+template <class DA>
+inline DA _convert_array_from_variant(const Variant &p_variant) {
+ switch (p_variant.get_type()) {
+ case Variant::ARRAY: {
+ return _convert_array<DA, Array>(p_variant.operator Array());
+ }
+ case Variant::PACKED_BYTE_ARRAY: {
+ return _convert_array<DA, Vector<uint8_t>>(p_variant.operator Vector<uint8_t>());
+ }
+ case Variant::PACKED_INT32_ARRAY: {
+ return _convert_array<DA, Vector<int32_t>>(p_variant.operator Vector<int32_t>());
+ }
+ case Variant::PACKED_INT64_ARRAY: {
+ return _convert_array<DA, Vector<int64_t>>(p_variant.operator Vector<int64_t>());
+ }
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ return _convert_array<DA, Vector<float>>(p_variant.operator Vector<float>());
+ }
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ return _convert_array<DA, Vector<double>>(p_variant.operator Vector<double>());
+ }
+ case Variant::PACKED_STRING_ARRAY: {
+ return _convert_array<DA, Vector<String>>(p_variant.operator Vector<String>());
+ }
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ return _convert_array<DA, Vector<Vector2>>(p_variant.operator Vector<Vector2>());
+ }
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ return _convert_array<DA, Vector<Vector3>>(p_variant.operator Vector<Vector3>());
+ }
+ case Variant::PACKED_COLOR_ARRAY: {
+ return _convert_array<DA, Vector<Color>>(p_variant.operator Vector<Color>());
+ }
+ default: {
+ return DA();
+ }
+ }
+}
+
+Variant::operator Array() const {
+ if (type == ARRAY) {
+ return *reinterpret_cast<const Array *>(_data._mem);
+ } else {
+ return _convert_array_from_variant<Array>(*this);
+ }
+}
+
+Variant::operator Vector<uint8_t>() const {
+ if (type == PACKED_BYTE_ARRAY) {
+ return static_cast<PackedArrayRef<uint8_t> *>(_data.packed_array)->array;
+ } else {
+ return _convert_array_from_variant<Vector<uint8_t>>(*this);
+ }
+}
+
+Variant::operator Vector<int32_t>() const {
+ if (type == PACKED_INT32_ARRAY) {
+ return static_cast<PackedArrayRef<int32_t> *>(_data.packed_array)->array;
+ } else {
+ return _convert_array_from_variant<Vector<int>>(*this);
+ }
+}
+
+Variant::operator Vector<int64_t>() const {
+ if (type == PACKED_INT64_ARRAY) {
+ return static_cast<PackedArrayRef<int64_t> *>(_data.packed_array)->array;
+ } else {
+ return _convert_array_from_variant<Vector<int64_t>>(*this);
+ }
+}
+
+Variant::operator Vector<float>() const {
+ if (type == PACKED_FLOAT32_ARRAY) {
+ return static_cast<PackedArrayRef<float> *>(_data.packed_array)->array;
+ } else {
+ return _convert_array_from_variant<Vector<float>>(*this);
+ }
+}
+
+Variant::operator Vector<double>() const {
+ if (type == PACKED_FLOAT64_ARRAY) {
+ return static_cast<PackedArrayRef<double> *>(_data.packed_array)->array;
+ } else {
+ return _convert_array_from_variant<Vector<double>>(*this);
+ }
+}
+
+Variant::operator Vector<String>() const {
+ if (type == PACKED_STRING_ARRAY) {
+ return static_cast<PackedArrayRef<String> *>(_data.packed_array)->array;
+ } else {
+ return _convert_array_from_variant<Vector<String>>(*this);
+ }
+}
+
+Variant::operator Vector<Vector3>() const {
+ if (type == PACKED_VECTOR3_ARRAY) {
+ return static_cast<PackedArrayRef<Vector3> *>(_data.packed_array)->array;
+ } else {
+ return _convert_array_from_variant<Vector<Vector3>>(*this);
+ }
+}
+
+Variant::operator Vector<Vector2>() const {
+ if (type == PACKED_VECTOR2_ARRAY) {
+ return static_cast<PackedArrayRef<Vector2> *>(_data.packed_array)->array;
+ } else {
+ return _convert_array_from_variant<Vector<Vector2>>(*this);
+ }
+}
+
+Variant::operator Vector<Color>() const {
+ if (type == PACKED_COLOR_ARRAY) {
+ return static_cast<PackedArrayRef<Color> *>(_data.packed_array)->array;
+ } else {
+ return _convert_array_from_variant<Vector<Color>>(*this);
+ }
+}
+
+/* helpers */
+
+Variant::operator Vector<RID>() const {
+ Array va = operator Array();
+ Vector<RID> rids;
+ rids.resize(va.size());
+ for (int i = 0; i < rids.size(); i++) {
+ rids.write[i] = va[i];
+ }
+ return rids;
+}
+
+Variant::operator Vector<Plane>() const {
+ Array va = operator Array();
+ Vector<Plane> planes;
+ int va_size = va.size();
+ if (va_size == 0) {
+ return planes;
+ }
+
+ planes.resize(va_size);
+ Plane *w = planes.ptrw();
+
+ for (int i = 0; i < va_size; i++) {
+ w[i] = va[i];
+ }
+
+ return planes;
+}
+
+Variant::operator Vector<Face3>() const {
+ Vector<Vector3> va = operator Vector<Vector3>();
+ Vector<Face3> faces;
+ int va_size = va.size();
+ if (va_size == 0) {
+ return faces;
+ }
+
+ faces.resize(va_size / 3);
+ Face3 *w = faces.ptrw();
+ const Vector3 *r = va.ptr();
+
+ for (int i = 0; i < va_size; i++) {
+ w[i / 3].vertex[i % 3] = r[i];
+ }
+
+ return faces;
+}
+
+Variant::operator Vector<Variant>() const {
+ Array va = operator Array();
+ Vector<Variant> variants;
+ int va_size = va.size();
+ if (va_size == 0) {
+ return variants;
+ }
+
+ variants.resize(va_size);
+ Variant *w = variants.ptrw();
+ for (int i = 0; i < va_size; i++) {
+ w[i] = va[i];
+ }
+
+ return variants;
+}
+
+Variant::operator Vector<StringName>() const {
+ Vector<String> from = operator Vector<String>();
+ Vector<StringName> to;
+ int len = from.size();
+ to.resize(len);
+ for (int i = 0; i < len; i++) {
+ to.write[i] = from[i];
+ }
+ return to;
+}
+
+Variant::operator Margin() const {
+ return (Margin) operator int();
+}
+
+Variant::operator Orientation() const {
+ return (Orientation) operator int();
+}
+
+Variant::operator IP_Address() const {
+ if (type == PACKED_FLOAT32_ARRAY || type == PACKED_INT32_ARRAY || type == PACKED_FLOAT64_ARRAY || type == PACKED_INT64_ARRAY || type == PACKED_BYTE_ARRAY) {
+ Vector<int> addr = operator Vector<int>();
+ if (addr.size() == 4) {
+ return IP_Address(addr.get(0), addr.get(1), addr.get(2), addr.get(3));
+ }
+ }
+
+ return IP_Address(operator String());
+}
+
+Variant::Variant(bool p_bool) {
+ type = BOOL;
+ _data._bool = p_bool;
+}
+
+Variant::Variant(signed int p_int) {
+ type = INT;
+ _data._int = p_int;
+}
+
+Variant::Variant(unsigned int p_int) {
+ type = INT;
+ _data._int = p_int;
+}
+
+#ifdef NEED_LONG_INT
+
+Variant::Variant(signed long p_int) {
+ type = INT;
+ _data._int = p_int;
+}
+
+Variant::Variant(unsigned long p_int) {
+ type = INT;
+ _data._int = p_int;
+}
+#endif
+
+Variant::Variant(int64_t p_int) {
+ type = INT;
+ _data._int = p_int;
+}
+
+Variant::Variant(uint64_t p_int) {
+ type = INT;
+ _data._int = p_int;
+}
+
+Variant::Variant(signed short p_short) {
+ type = INT;
+ _data._int = p_short;
+}
+
+Variant::Variant(unsigned short p_short) {
+ type = INT;
+ _data._int = p_short;
+}
+
+Variant::Variant(signed char p_char) {
+ type = INT;
+ _data._int = p_char;
+}
+
+Variant::Variant(unsigned char p_char) {
+ type = INT;
+ _data._int = p_char;
+}
+
+Variant::Variant(float p_float) {
+ type = FLOAT;
+ _data._float = p_float;
+}
+
+Variant::Variant(double p_double) {
+ type = FLOAT;
+ _data._float = p_double;
+}
+
+Variant::Variant(const ObjectID &p_id) {
+ type = INT;
+ _data._int = p_id;
+}
+
+Variant::Variant(const StringName &p_string) {
+ type = STRING_NAME;
+ memnew_placement(_data._mem, StringName(p_string));
+}
+
+Variant::Variant(const String &p_string) {
+ type = STRING;
+ memnew_placement(_data._mem, String(p_string));
+}
+
+Variant::Variant(const char *const p_cstring) {
+ type = STRING;
+ memnew_placement(_data._mem, String((const char *)p_cstring));
+}
+
+Variant::Variant(const char32_t *p_wstring) {
+ type = STRING;
+ memnew_placement(_data._mem, String(p_wstring));
+}
+
+Variant::Variant(const Vector3 &p_vector3) {
+ type = VECTOR3;
+ memnew_placement(_data._mem, Vector3(p_vector3));
+}
+
+Variant::Variant(const Vector3i &p_vector3i) {
+ type = VECTOR3I;
+ memnew_placement(_data._mem, Vector3i(p_vector3i));
+}
+
+Variant::Variant(const Vector2 &p_vector2) {
+ type = VECTOR2;
+ memnew_placement(_data._mem, Vector2(p_vector2));
+}
+
+Variant::Variant(const Vector2i &p_vector2i) {
+ type = VECTOR2I;
+ memnew_placement(_data._mem, Vector2i(p_vector2i));
+}
+
+Variant::Variant(const Rect2 &p_rect2) {
+ type = RECT2;
+ memnew_placement(_data._mem, Rect2(p_rect2));
+}
+
+Variant::Variant(const Rect2i &p_rect2i) {
+ type = RECT2I;
+ memnew_placement(_data._mem, Rect2i(p_rect2i));
+}
+
+Variant::Variant(const Plane &p_plane) {
+ type = PLANE;
+ memnew_placement(_data._mem, Plane(p_plane));
+}
+
+Variant::Variant(const ::AABB &p_aabb) {
+ type = AABB;
+ _data._aabb = memnew(::AABB(p_aabb));
+}
+
+Variant::Variant(const Basis &p_matrix) {
+ type = BASIS;
+ _data._basis = memnew(Basis(p_matrix));
+}
+
+Variant::Variant(const Quat &p_quat) {
+ type = QUAT;
+ memnew_placement(_data._mem, Quat(p_quat));
+}
+
+Variant::Variant(const Transform &p_transform) {
+ type = TRANSFORM;
+ _data._transform = memnew(Transform(p_transform));
+}
+
+Variant::Variant(const Transform2D &p_transform) {
+ type = TRANSFORM2D;
+ _data._transform2d = memnew(Transform2D(p_transform));
+}
+
+Variant::Variant(const Color &p_color) {
+ type = COLOR;
+ memnew_placement(_data._mem, Color(p_color));
+}
+
+Variant::Variant(const NodePath &p_node_path) {
+ type = NODE_PATH;
+ memnew_placement(_data._mem, NodePath(p_node_path));
+}
+
+Variant::Variant(const RID &p_rid) {
+ type = _RID;
+ memnew_placement(_data._mem, RID(p_rid));
+}
+
+Variant::Variant(const Object *p_object) {
+ type = OBJECT;
+
+ memnew_placement(_data._mem, ObjData);
+
+ if (p_object) {
+ if (p_object->is_reference()) {
+ Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(p_object));
+ if (!reference->init_ref()) {
+ _get_obj().obj = nullptr;
+ _get_obj().id = ObjectID();
+ return;
+ }
+ }
+
+ _get_obj().obj = const_cast<Object *>(p_object);
+ _get_obj().id = p_object->get_instance_id();
+ } else {
+ _get_obj().obj = nullptr;
+ _get_obj().id = ObjectID();
+ }
+}
+
+Variant::Variant(const Callable &p_callable) {
+ type = CALLABLE;
+ memnew_placement(_data._mem, Callable(p_callable));
+}
+
+Variant::Variant(const Signal &p_callable) {
+ type = SIGNAL;
+ memnew_placement(_data._mem, Signal(p_callable));
+}
+
+Variant::Variant(const Dictionary &p_dictionary) {
+ type = DICTIONARY;
+ memnew_placement(_data._mem, Dictionary(p_dictionary));
+}
+
+Variant::Variant(const Array &p_array) {
+ type = ARRAY;
+ memnew_placement(_data._mem, Array(p_array));
+}
+
+Variant::Variant(const Vector<Plane> &p_array) {
+ type = ARRAY;
+
+ Array *plane_array = memnew_placement(_data._mem, Array);
+
+ plane_array->resize(p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+ plane_array->operator[](i) = Variant(p_array[i]);
+ }
+}
+
+Variant::Variant(const Vector<RID> &p_array) {
+ type = ARRAY;
+
+ Array *rid_array = memnew_placement(_data._mem, Array);
+
+ rid_array->resize(p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+ rid_array->set(i, Variant(p_array[i]));
+ }
+}
+
+Variant::Variant(const Vector<uint8_t> &p_byte_array) {
+ type = PACKED_BYTE_ARRAY;
+
+ _data.packed_array = PackedArrayRef<uint8_t>::create(p_byte_array);
+}
+
+Variant::Variant(const Vector<int32_t> &p_int32_array) {
+ type = PACKED_INT32_ARRAY;
+ _data.packed_array = PackedArrayRef<int32_t>::create(p_int32_array);
+}
+
+Variant::Variant(const Vector<int64_t> &p_int64_array) {
+ type = PACKED_INT64_ARRAY;
+ _data.packed_array = PackedArrayRef<int64_t>::create(p_int64_array);
+}
+
+Variant::Variant(const Vector<float> &p_float32_array) {
+ type = PACKED_FLOAT32_ARRAY;
+ _data.packed_array = PackedArrayRef<float>::create(p_float32_array);
+}
+
+Variant::Variant(const Vector<double> &p_float64_array) {
+ type = PACKED_FLOAT64_ARRAY;
+ _data.packed_array = PackedArrayRef<double>::create(p_float64_array);
+}
+
+Variant::Variant(const Vector<String> &p_string_array) {
+ type = PACKED_STRING_ARRAY;
+ _data.packed_array = PackedArrayRef<String>::create(p_string_array);
+}
+
+Variant::Variant(const Vector<Vector3> &p_vector3_array) {
+ type = PACKED_VECTOR3_ARRAY;
+ _data.packed_array = PackedArrayRef<Vector3>::create(p_vector3_array);
+}
+
+Variant::Variant(const Vector<Vector2> &p_vector2_array) {
+ type = PACKED_VECTOR2_ARRAY;
+ _data.packed_array = PackedArrayRef<Vector2>::create(p_vector2_array);
+}
+
+Variant::Variant(const Vector<Color> &p_color_array) {
+ type = PACKED_COLOR_ARRAY;
+ _data.packed_array = PackedArrayRef<Color>::create(p_color_array);
+}
+
+Variant::Variant(const Vector<Face3> &p_face_array) {
+ Vector<Vector3> vertices;
+ int face_count = p_face_array.size();
+ vertices.resize(face_count * 3);
+
+ if (face_count) {
+ const Face3 *r = p_face_array.ptr();
+ Vector3 *w = vertices.ptrw();
+
+ for (int i = 0; i < face_count; i++) {
+ for (int j = 0; j < 3; j++) {
+ w[i * 3 + j] = r[i].vertex[j];
+ }
+ }
+ }
+
+ type = NIL;
+
+ *this = vertices;
+}
+
+/* helpers */
+Variant::Variant(const Vector<Variant> &p_array) {
+ type = NIL;
+ Array arr;
+ arr.resize(p_array.size());
+ for (int i = 0; i < p_array.size(); i++) {
+ arr[i] = p_array[i];
+ }
+ *this = arr;
+}
+
+Variant::Variant(const Vector<StringName> &p_array) {
+ type = NIL;
+ Vector<String> v;
+ int len = p_array.size();
+ v.resize(len);
+ for (int i = 0; i < len; i++) {
+ v.set(i, p_array[i]);
+ }
+ *this = v;
+}
+
+void Variant::operator=(const Variant &p_variant) {
+ if (unlikely(this == &p_variant)) {
+ return;
+ }
+
+ if (unlikely(type != p_variant.type)) {
+ reference(p_variant);
+ return;
+ }
+
+ switch (p_variant.type) {
+ case NIL: {
+ // none
+ } break;
+
+ // atomic types
+ case BOOL: {
+ _data._bool = p_variant._data._bool;
+ } break;
+ case INT: {
+ _data._int = p_variant._data._int;
+ } break;
+ case FLOAT: {
+ _data._float = p_variant._data._float;
+ } break;
+ case STRING: {
+ *reinterpret_cast<String *>(_data._mem) = *reinterpret_cast<const String *>(p_variant._data._mem);
+ } break;
+
+ // math types
+ case VECTOR2: {
+ *reinterpret_cast<Vector2 *>(_data._mem) = *reinterpret_cast<const Vector2 *>(p_variant._data._mem);
+ } break;
+ case VECTOR2I: {
+ *reinterpret_cast<Vector2i *>(_data._mem) = *reinterpret_cast<const Vector2i *>(p_variant._data._mem);
+ } break;
+ case RECT2: {
+ *reinterpret_cast<Rect2 *>(_data._mem) = *reinterpret_cast<const Rect2 *>(p_variant._data._mem);
+ } break;
+ case RECT2I: {
+ *reinterpret_cast<Rect2i *>(_data._mem) = *reinterpret_cast<const Rect2i *>(p_variant._data._mem);
+ } break;
+ case TRANSFORM2D: {
+ *_data._transform2d = *(p_variant._data._transform2d);
+ } break;
+ case VECTOR3: {
+ *reinterpret_cast<Vector3 *>(_data._mem) = *reinterpret_cast<const Vector3 *>(p_variant._data._mem);
+ } break;
+ case VECTOR3I: {
+ *reinterpret_cast<Vector3i *>(_data._mem) = *reinterpret_cast<const Vector3i *>(p_variant._data._mem);
+ } break;
+ case PLANE: {
+ *reinterpret_cast<Plane *>(_data._mem) = *reinterpret_cast<const Plane *>(p_variant._data._mem);
+ } break;
+
+ case AABB: {
+ *_data._aabb = *(p_variant._data._aabb);
+ } break;
+ case QUAT: {
+ *reinterpret_cast<Quat *>(_data._mem) = *reinterpret_cast<const Quat *>(p_variant._data._mem);
+ } break;
+ case BASIS: {
+ *_data._basis = *(p_variant._data._basis);
+ } break;
+ case TRANSFORM: {
+ *_data._transform = *(p_variant._data._transform);
+ } break;
+
+ // misc types
+ case COLOR: {
+ *reinterpret_cast<Color *>(_data._mem) = *reinterpret_cast<const Color *>(p_variant._data._mem);
+ } break;
+ case _RID: {
+ *reinterpret_cast<RID *>(_data._mem) = *reinterpret_cast<const RID *>(p_variant._data._mem);
+ } break;
+ case OBJECT: {
+ if (_get_obj().id.is_reference()) {
+ //we are safe that there is a reference here
+ Reference *reference = static_cast<Reference *>(_get_obj().obj);
+ if (reference->unreference()) {
+ memdelete(reference);
+ }
+ }
+
+ if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) {
+ Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj);
+ if (!reference->reference()) {
+ _get_obj().obj = nullptr;
+ _get_obj().id = ObjectID();
+ break;
+ }
+ }
+
+ _get_obj().obj = const_cast<Object *>(p_variant._get_obj().obj);
+ _get_obj().id = p_variant._get_obj().id;
+
+ } break;
+ case CALLABLE: {
+ *reinterpret_cast<Callable *>(_data._mem) = *reinterpret_cast<const Callable *>(p_variant._data._mem);
+ } break;
+ case SIGNAL: {
+ *reinterpret_cast<Signal *>(_data._mem) = *reinterpret_cast<const Signal *>(p_variant._data._mem);
+ } break;
+
+ case STRING_NAME: {
+ *reinterpret_cast<StringName *>(_data._mem) = *reinterpret_cast<const StringName *>(p_variant._data._mem);
+ } break;
+ case NODE_PATH: {
+ *reinterpret_cast<NodePath *>(_data._mem) = *reinterpret_cast<const NodePath *>(p_variant._data._mem);
+ } break;
+ case DICTIONARY: {
+ *reinterpret_cast<Dictionary *>(_data._mem) = *reinterpret_cast<const Dictionary *>(p_variant._data._mem);
+ } break;
+ case ARRAY: {
+ *reinterpret_cast<Array *>(_data._mem) = *reinterpret_cast<const Array *>(p_variant._data._mem);
+ } break;
+
+ // arrays
+ case PACKED_BYTE_ARRAY: {
+ _data.packed_array = PackedArrayRef<uint8_t>::reference_from(_data.packed_array, p_variant._data.packed_array);
+ } break;
+ case PACKED_INT32_ARRAY: {
+ _data.packed_array = PackedArrayRef<int32_t>::reference_from(_data.packed_array, p_variant._data.packed_array);
+ } break;
+ case PACKED_INT64_ARRAY: {
+ _data.packed_array = PackedArrayRef<int64_t>::reference_from(_data.packed_array, p_variant._data.packed_array);
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ _data.packed_array = PackedArrayRef<float>::reference_from(_data.packed_array, p_variant._data.packed_array);
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ _data.packed_array = PackedArrayRef<double>::reference_from(_data.packed_array, p_variant._data.packed_array);
+ } break;
+ case PACKED_STRING_ARRAY: {
+ _data.packed_array = PackedArrayRef<String>::reference_from(_data.packed_array, p_variant._data.packed_array);
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ _data.packed_array = PackedArrayRef<Vector2>::reference_from(_data.packed_array, p_variant._data.packed_array);
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ _data.packed_array = PackedArrayRef<Vector3>::reference_from(_data.packed_array, p_variant._data.packed_array);
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ _data.packed_array = PackedArrayRef<Color>::reference_from(_data.packed_array, p_variant._data.packed_array);
+ } break;
+ default: {
+ }
+ }
+}
+
+Variant::Variant(const IP_Address &p_address) {
+ type = STRING;
+ memnew_placement(_data._mem, String(p_address));
+}
+
+Variant::Variant(const Variant &p_variant) {
+ reference(p_variant);
+}
+
+uint32_t Variant::hash() const {
+ switch (type) {
+ case NIL: {
+ return 0;
+ } break;
+ case BOOL: {
+ return _data._bool ? 1 : 0;
+ } break;
+ case INT: {
+ return _data._int;
+ } break;
+ case FLOAT: {
+ return hash_djb2_one_float(_data._float);
+ } break;
+ case STRING: {
+ return reinterpret_cast<const String *>(_data._mem)->hash();
+ } break;
+
+ // math types
+ case VECTOR2: {
+ uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Vector2 *>(_data._mem)->x);
+ return hash_djb2_one_float(reinterpret_cast<const Vector2 *>(_data._mem)->y, hash);
+ } break;
+ case VECTOR2I: {
+ uint32_t hash = hash_djb2_one_32(reinterpret_cast<const Vector2i *>(_data._mem)->x);
+ return hash_djb2_one_32(reinterpret_cast<const Vector2i *>(_data._mem)->y, hash);
+ } break;
+ case RECT2: {
+ uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->position.x);
+ hash = hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->position.y, hash);
+ hash = hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->size.x, hash);
+ return hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->size.y, hash);
+ } break;
+ case RECT2I: {
+ uint32_t hash = hash_djb2_one_32(reinterpret_cast<const Rect2i *>(_data._mem)->position.x);
+ hash = hash_djb2_one_32(reinterpret_cast<const Rect2i *>(_data._mem)->position.y, hash);
+ hash = hash_djb2_one_32(reinterpret_cast<const Rect2i *>(_data._mem)->size.x, hash);
+ return hash_djb2_one_32(reinterpret_cast<const Rect2i *>(_data._mem)->size.y, hash);
+ } break;
+ case TRANSFORM2D: {
+ uint32_t hash = 5831;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 2; j++) {
+ hash = hash_djb2_one_float(_data._transform2d->elements[i][j], hash);
+ }
+ }
+
+ return hash;
+ } break;
+ case VECTOR3: {
+ uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Vector3 *>(_data._mem)->x);
+ hash = hash_djb2_one_float(reinterpret_cast<const Vector3 *>(_data._mem)->y, hash);
+ return hash_djb2_one_float(reinterpret_cast<const Vector3 *>(_data._mem)->z, hash);
+ } break;
+ case VECTOR3I: {
+ uint32_t hash = hash_djb2_one_32(reinterpret_cast<const Vector3i *>(_data._mem)->x);
+ hash = hash_djb2_one_32(reinterpret_cast<const Vector3i *>(_data._mem)->y, hash);
+ return hash_djb2_one_32(reinterpret_cast<const Vector3i *>(_data._mem)->z, hash);
+ } break;
+ case PLANE: {
+ uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->normal.x);
+ hash = hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->normal.y, hash);
+ hash = hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->normal.z, hash);
+ return hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->d, hash);
+
+ } break;
+ case AABB: {
+ uint32_t hash = 5831;
+ for (int i = 0; i < 3; i++) {
+ hash = hash_djb2_one_float(_data._aabb->position[i], hash);
+ hash = hash_djb2_one_float(_data._aabb->size[i], hash);
+ }
+
+ return hash;
+
+ } break;
+ case QUAT: {
+ uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->x);
+ hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->y, hash);
+ hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->z, hash);
+ return hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->w, hash);
+
+ } break;
+ case BASIS: {
+ uint32_t hash = 5831;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ hash = hash_djb2_one_float(_data._basis->elements[i][j], hash);
+ }
+ }
+
+ return hash;
+
+ } break;
+ case TRANSFORM: {
+ uint32_t hash = 5831;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ hash = hash_djb2_one_float(_data._transform->basis.elements[i][j], hash);
+ }
+ hash = hash_djb2_one_float(_data._transform->origin[i], hash);
+ }
+
+ return hash;
+
+ } break;
+
+ // misc types
+ case COLOR: {
+ uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Color *>(_data._mem)->r);
+ hash = hash_djb2_one_float(reinterpret_cast<const Color *>(_data._mem)->g, hash);
+ hash = hash_djb2_one_float(reinterpret_cast<const Color *>(_data._mem)->b, hash);
+ return hash_djb2_one_float(reinterpret_cast<const Color *>(_data._mem)->a, hash);
+
+ } break;
+ case _RID: {
+ return hash_djb2_one_64(reinterpret_cast<const RID *>(_data._mem)->get_id());
+ } break;
+ case OBJECT: {
+ return hash_djb2_one_64(make_uint64_t(_get_obj().obj));
+ } break;
+ case STRING_NAME: {
+ return reinterpret_cast<const StringName *>(_data._mem)->hash();
+ } break;
+ case NODE_PATH: {
+ return reinterpret_cast<const NodePath *>(_data._mem)->hash();
+ } break;
+ case DICTIONARY: {
+ return reinterpret_cast<const Dictionary *>(_data._mem)->hash();
+
+ } break;
+ case CALLABLE: {
+ return reinterpret_cast<const Callable *>(_data._mem)->hash();
+
+ } break;
+ case SIGNAL: {
+ const Signal &s = *reinterpret_cast<const Signal *>(_data._mem);
+ uint32_t hash = s.get_name().hash();
+ return hash_djb2_one_64(s.get_object_id(), hash);
+ } break;
+ case ARRAY: {
+ const Array &arr = *reinterpret_cast<const Array *>(_data._mem);
+ return arr.hash();
+
+ } break;
+ case PACKED_BYTE_ARRAY: {
+ const Vector<uint8_t> &arr = PackedArrayRef<uint8_t>::get_array(_data.packed_array);
+ int len = arr.size();
+ if (likely(len)) {
+ const uint8_t *r = arr.ptr();
+ return hash_djb2_buffer((uint8_t *)&r[0], len);
+ } else {
+ return hash_djb2_one_64(0);
+ }
+
+ } break;
+ case PACKED_INT32_ARRAY: {
+ const Vector<int32_t> &arr = PackedArrayRef<int32_t>::get_array(_data.packed_array);
+ int len = arr.size();
+ if (likely(len)) {
+ const int32_t *r = arr.ptr();
+ return hash_djb2_buffer((uint8_t *)&r[0], len * sizeof(int32_t));
+ } else {
+ return hash_djb2_one_64(0);
+ }
+
+ } break;
+ case PACKED_INT64_ARRAY: {
+ const Vector<int64_t> &arr = PackedArrayRef<int64_t>::get_array(_data.packed_array);
+ int len = arr.size();
+ if (likely(len)) {
+ const int64_t *r = arr.ptr();
+ return hash_djb2_buffer((uint8_t *)&r[0], len * sizeof(int64_t));
+ } else {
+ return hash_djb2_one_64(0);
+ }
+
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ const Vector<float> &arr = PackedArrayRef<float>::get_array(_data.packed_array);
+ int len = arr.size();
+
+ if (likely(len)) {
+ const float *r = arr.ptr();
+ return hash_djb2_buffer((uint8_t *)&r[0], len * sizeof(float));
+ } else {
+ return hash_djb2_one_float(0.0);
+ }
+
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ const Vector<double> &arr = PackedArrayRef<double>::get_array(_data.packed_array);
+ int len = arr.size();
+
+ if (likely(len)) {
+ const double *r = arr.ptr();
+ return hash_djb2_buffer((uint8_t *)&r[0], len * sizeof(double));
+ } else {
+ return hash_djb2_one_float(0.0);
+ }
+
+ } break;
+ case PACKED_STRING_ARRAY: {
+ uint32_t hash = 5831;
+ const Vector<String> &arr = PackedArrayRef<String>::get_array(_data.packed_array);
+ int len = arr.size();
+
+ if (likely(len)) {
+ const String *r = arr.ptr();
+
+ for (int i = 0; i < len; i++) {
+ hash = hash_djb2_one_32(r[i].hash(), hash);
+ }
+ }
+
+ return hash;
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ uint32_t hash = 5831;
+ const Vector<Vector2> &arr = PackedArrayRef<Vector2>::get_array(_data.packed_array);
+ int len = arr.size();
+
+ if (likely(len)) {
+ const Vector2 *r = arr.ptr();
+
+ for (int i = 0; i < len; i++) {
+ hash = hash_djb2_one_float(r[i].x, hash);
+ hash = hash_djb2_one_float(r[i].y, hash);
+ }
+ }
+
+ return hash;
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ uint32_t hash = 5831;
+ const Vector<Vector3> &arr = PackedArrayRef<Vector3>::get_array(_data.packed_array);
+ int len = arr.size();
+
+ if (likely(len)) {
+ const Vector3 *r = arr.ptr();
+
+ for (int i = 0; i < len; i++) {
+ hash = hash_djb2_one_float(r[i].x, hash);
+ hash = hash_djb2_one_float(r[i].y, hash);
+ hash = hash_djb2_one_float(r[i].z, hash);
+ }
+ }
+
+ return hash;
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ uint32_t hash = 5831;
+ const Vector<Color> &arr = PackedArrayRef<Color>::get_array(_data.packed_array);
+ int len = arr.size();
+
+ if (likely(len)) {
+ const Color *r = arr.ptr();
+
+ for (int i = 0; i < len; i++) {
+ hash = hash_djb2_one_float(r[i].r, hash);
+ hash = hash_djb2_one_float(r[i].g, hash);
+ hash = hash_djb2_one_float(r[i].b, hash);
+ hash = hash_djb2_one_float(r[i].a, hash);
+ }
+ }
+
+ return hash;
+ } break;
+ default: {
+ }
+ }
+
+ return 0;
+}
+
+#define hash_compare_scalar(p_lhs, p_rhs) \
+ ((p_lhs) == (p_rhs)) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs))
+
+#define hash_compare_vector2(p_lhs, p_rhs) \
+ (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \
+ (hash_compare_scalar((p_lhs).y, (p_rhs).y))
+
+#define hash_compare_vector3(p_lhs, p_rhs) \
+ (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \
+ (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \
+ (hash_compare_scalar((p_lhs).z, (p_rhs).z))
+
+#define hash_compare_quat(p_lhs, p_rhs) \
+ (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \
+ (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \
+ (hash_compare_scalar((p_lhs).z, (p_rhs).z)) && \
+ (hash_compare_scalar((p_lhs).w, (p_rhs).w))
+
+#define hash_compare_color(p_lhs, p_rhs) \
+ (hash_compare_scalar((p_lhs).r, (p_rhs).r)) && \
+ (hash_compare_scalar((p_lhs).g, (p_rhs).g)) && \
+ (hash_compare_scalar((p_lhs).b, (p_rhs).b)) && \
+ (hash_compare_scalar((p_lhs).a, (p_rhs).a))
+
+#define hash_compare_packed_array(p_lhs, p_rhs, p_type, p_compare_func) \
+ const Vector<p_type> &l = PackedArrayRef<p_type>::get_array(p_lhs); \
+ const Vector<p_type> &r = PackedArrayRef<p_type>::get_array(p_rhs); \
+ \
+ if (l.size() != r.size()) \
+ return false; \
+ \
+ const p_type *lr = l.ptr(); \
+ const p_type *rr = r.ptr(); \
+ \
+ for (int i = 0; i < l.size(); ++i) { \
+ if (!p_compare_func((lr[i]), (rr[i]))) \
+ return false; \
+ } \
+ \
+ return true
+
+bool Variant::hash_compare(const Variant &p_variant) const {
+ if (type != p_variant.type) {
+ return false;
+ }
+
+ switch (type) {
+ case FLOAT: {
+ return hash_compare_scalar(_data._float, p_variant._data._float);
+ } break;
+
+ case VECTOR2: {
+ const Vector2 *l = reinterpret_cast<const Vector2 *>(_data._mem);
+ const Vector2 *r = reinterpret_cast<const Vector2 *>(p_variant._data._mem);
+
+ return hash_compare_vector2(*l, *r);
+ } break;
+ case VECTOR2I: {
+ const Vector2i *l = reinterpret_cast<const Vector2i *>(_data._mem);
+ const Vector2i *r = reinterpret_cast<const Vector2i *>(p_variant._data._mem);
+ return *l == *r;
+ } break;
+
+ case RECT2: {
+ const Rect2 *l = reinterpret_cast<const Rect2 *>(_data._mem);
+ 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));
+ } break;
+ case RECT2I: {
+ const Rect2i *l = reinterpret_cast<const Rect2i *>(_data._mem);
+ const Rect2i *r = reinterpret_cast<const Rect2i *>(p_variant._data._mem);
+
+ return *l == *r;
+ } break;
+
+ case TRANSFORM2D: {
+ Transform2D *l = _data._transform2d;
+ Transform2D *r = p_variant._data._transform2d;
+
+ for (int i = 0; i < 3; i++) {
+ if (!(hash_compare_vector2(l->elements[i], r->elements[i]))) {
+ return false;
+ }
+ }
+
+ return true;
+ } break;
+
+ case VECTOR3: {
+ const Vector3 *l = reinterpret_cast<const Vector3 *>(_data._mem);
+ const Vector3 *r = reinterpret_cast<const Vector3 *>(p_variant._data._mem);
+
+ return hash_compare_vector3(*l, *r);
+ } break;
+ case VECTOR3I: {
+ const Vector3i *l = reinterpret_cast<const Vector3i *>(_data._mem);
+ const Vector3i *r = reinterpret_cast<const Vector3i *>(p_variant._data._mem);
+
+ return *l == *r;
+ } break;
+
+ case PLANE: {
+ const Plane *l = reinterpret_cast<const Plane *>(_data._mem);
+ 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));
+ } break;
+
+ case AABB: {
+ const ::AABB *l = _data._aabb;
+ const ::AABB *r = p_variant._data._aabb;
+
+ return (hash_compare_vector3(l->position, r->position) &&
+ (hash_compare_vector3(l->size, r->size)));
+
+ } break;
+
+ case QUAT: {
+ const Quat *l = reinterpret_cast<const Quat *>(_data._mem);
+ const Quat *r = reinterpret_cast<const Quat *>(p_variant._data._mem);
+
+ return hash_compare_quat(*l, *r);
+ } break;
+
+ case BASIS: {
+ const Basis *l = _data._basis;
+ const Basis *r = p_variant._data._basis;
+
+ for (int i = 0; i < 3; i++) {
+ if (!(hash_compare_vector3(l->elements[i], r->elements[i]))) {
+ return false;
+ }
+ }
+
+ return true;
+ } break;
+
+ case TRANSFORM: {
+ const Transform *l = _data._transform;
+ const Transform *r = p_variant._data._transform;
+
+ for (int i = 0; i < 3; i++) {
+ if (!(hash_compare_vector3(l->basis.elements[i], r->basis.elements[i]))) {
+ return false;
+ }
+ }
+
+ return hash_compare_vector3(l->origin, r->origin);
+ } break;
+
+ case COLOR: {
+ const Color *l = reinterpret_cast<const Color *>(_data._mem);
+ const Color *r = reinterpret_cast<const Color *>(p_variant._data._mem);
+
+ return hash_compare_color(*l, *r);
+ } break;
+
+ case ARRAY: {
+ 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()) {
+ return false;
+ }
+
+ for (int i = 0; i < l.size(); ++i) {
+ if (!l[i].hash_compare(r[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ } break;
+
+ // This is for floating point comparisons only.
+ case PACKED_FLOAT32_ARRAY: {
+ hash_compare_packed_array(_data.packed_array, p_variant._data.packed_array, float, hash_compare_scalar);
+ } break;
+
+ case PACKED_FLOAT64_ARRAY: {
+ hash_compare_packed_array(_data.packed_array, p_variant._data.packed_array, double, hash_compare_scalar);
+ } break;
+
+ case PACKED_VECTOR2_ARRAY: {
+ hash_compare_packed_array(_data.packed_array, p_variant._data.packed_array, Vector2, hash_compare_vector2);
+ } break;
+
+ case PACKED_VECTOR3_ARRAY: {
+ hash_compare_packed_array(_data.packed_array, p_variant._data.packed_array, Vector3, hash_compare_vector3);
+ } break;
+
+ case PACKED_COLOR_ARRAY: {
+ hash_compare_packed_array(_data.packed_array, p_variant._data.packed_array, Color, hash_compare_color);
+ } break;
+
+ default:
+ bool v;
+ Variant r;
+ evaluate(OP_EQUAL, *this, p_variant, r, v);
+ return r;
+ }
+
+ return false;
+}
+
+bool Variant::is_ref() const {
+ return type == OBJECT && _get_obj().id.is_reference();
+}
+
+Vector<Variant> varray() {
+ return Vector<Variant>();
+}
+
+Vector<Variant> varray(const Variant &p_arg1) {
+ Vector<Variant> v;
+ v.push_back(p_arg1);
+ return v;
+}
+
+Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2) {
+ Vector<Variant> v;
+ v.push_back(p_arg1);
+ v.push_back(p_arg2);
+ return v;
+}
+
+Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3) {
+ Vector<Variant> v;
+ v.push_back(p_arg1);
+ v.push_back(p_arg2);
+ v.push_back(p_arg3);
+ return v;
+}
+
+Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4) {
+ Vector<Variant> v;
+ v.push_back(p_arg1);
+ v.push_back(p_arg2);
+ v.push_back(p_arg3);
+ v.push_back(p_arg4);
+ return v;
+}
+
+Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5) {
+ Vector<Variant> v;
+ v.push_back(p_arg1);
+ v.push_back(p_arg2);
+ v.push_back(p_arg3);
+ v.push_back(p_arg4);
+ v.push_back(p_arg5);
+ return v;
+}
+
+void Variant::static_assign(const Variant &p_variant) {
+}
+
+bool Variant::is_shared() const {
+ switch (type) {
+ case OBJECT:
+ return true;
+ case ARRAY:
+ return true;
+ case DICTIONARY:
+ return true;
+ default: {
+ }
+ }
+
+ 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, 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)) + "'.";
+ ERR_PRINT(err.utf8().get_data());
+
+ } break;
+ case Callable::CallError::CALL_ERROR_INVALID_METHOD: {
+ String err = "Invalid method '" + p_method + "' for type '" + Variant::get_type_name(type) + "'.";
+ ERR_PRINT(err.utf8().get_data());
+ } break;
+ case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: {
+ String err = "Too many arguments for method '" + p_method + "'";
+ ERR_PRINT(err.utf8().get_data());
+ } break;
+ default: {
+ }
+ }
+
+ return ret;
+}
+
+void Variant::construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct, void *p_construct_ud) {
+ r_value = Variant();
+}
+
+String Variant::get_construct_string() const {
+ String vars;
+ VariantWriter::write_to_string(*this, vars);
+
+ return vars;
+}
+
+String Variant::get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
+ String err_text;
+
+ if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+ int errorarg = ce.argument;
+ if (p_argptrs) {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ } else {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ }
+ } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ } else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+ err_text = "Method not found.";
+ } else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
+ err_text = "Instance is null";
+ } else if (ce.error == Callable::CallError::CALL_OK) {
+ return "Call OK";
+ }
+
+ String class_name = p_base->get_class();
+ Ref<Script> script = p_base->get_script();
+ if (script.is_valid() && script->get_path().is_resource_file()) {
+ class_name += "(" + script->get_path().get_file() + ")";
+ }
+ return "'" + class_name + "::" + String(p_method) + "': " + err_text;
+}
+
+String Variant::get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
+ String err_text;
+
+ if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+ int errorarg = ce.argument;
+ if (p_argptrs) {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ } else {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ }
+ } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ } else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+ err_text = "Method not found.";
+ } else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
+ err_text = "Instance is null";
+ } else if (ce.error == Callable::CallError::CALL_OK) {
+ return "Call OK";
+ }
+
+ return String(p_callable) + " : " + err_text;
+}
+
+String vformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
+ Array args;
+ if (p1.get_type() != Variant::NIL) {
+ args.push_back(p1);
+
+ if (p2.get_type() != Variant::NIL) {
+ args.push_back(p2);
+
+ if (p3.get_type() != Variant::NIL) {
+ args.push_back(p3);
+
+ if (p4.get_type() != Variant::NIL) {
+ args.push_back(p4);
+
+ if (p5.get_type() != Variant::NIL) {
+ args.push_back(p5);
+ }
+ }
+ }
+ }
+ }
+
+ bool error = false;
+ String fmt = p_text.sprintf(args, &error);
+
+ ERR_FAIL_COND_V_MSG(error, String(), fmt);
+
+ return fmt;
+}
diff --git a/core/variant/variant.h b/core/variant/variant.h
new file mode 100644
index 0000000000..c264bbcd48
--- /dev/null
+++ b/core/variant/variant.h
@@ -0,0 +1,613 @@
+/*************************************************************************/
+/* variant.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef VARIANT_H
+#define VARIANT_H
+
+#include "core/io/ip_address.h"
+#include "core/math/aabb.h"
+#include "core/math/basis.h"
+#include "core/math/color.h"
+#include "core/math/face3.h"
+#include "core/math/plane.h"
+#include "core/math/quat.h"
+#include "core/math/transform.h"
+#include "core/math/transform_2d.h"
+#include "core/math/vector3.h"
+#include "core/math/vector3i.h"
+#include "core/object/object_id.h"
+#include "core/string/node_path.h"
+#include "core/string/ustring.h"
+#include "core/templates/rid.h"
+#include "core/variant/array.h"
+#include "core/variant/callable.h"
+#include "core/variant/dictionary.h"
+
+class Object;
+class Node; // helper
+class Control; // helper
+
+struct PropertyInfo;
+struct MethodInfo;
+
+typedef Vector<uint8_t> PackedByteArray;
+typedef Vector<int32_t> PackedInt32Array;
+typedef Vector<int64_t> PackedInt64Array;
+typedef Vector<float> PackedFloat32Array;
+typedef Vector<double> PackedFloat64Array;
+typedef Vector<String> PackedStringArray;
+typedef Vector<Vector2> PackedVector2Array;
+typedef Vector<Vector3> PackedVector3Array;
+typedef Vector<Color> PackedColorArray;
+
+class Variant {
+public:
+ // If this changes the table in variant_op must be updated
+ enum Type {
+ NIL,
+
+ // atomic types
+ BOOL,
+ INT,
+ FLOAT,
+ STRING,
+
+ // math types
+ VECTOR2,
+ VECTOR2I,
+ RECT2,
+ RECT2I,
+ VECTOR3,
+ VECTOR3I,
+ TRANSFORM2D,
+ PLANE,
+ QUAT,
+ AABB,
+ BASIS,
+ TRANSFORM,
+
+ // misc types
+ COLOR,
+ STRING_NAME,
+ NODE_PATH,
+ _RID,
+ OBJECT,
+ CALLABLE,
+ SIGNAL,
+ DICTIONARY,
+ ARRAY,
+
+ // typed arrays
+ PACKED_BYTE_ARRAY,
+ PACKED_INT32_ARRAY,
+ PACKED_INT64_ARRAY,
+ PACKED_FLOAT32_ARRAY,
+ PACKED_FLOAT64_ARRAY,
+ PACKED_STRING_ARRAY,
+ PACKED_VECTOR2_ARRAY,
+ PACKED_VECTOR3_ARRAY,
+ PACKED_COLOR_ARRAY,
+
+ VARIANT_MAX
+ };
+
+private:
+ friend struct _VariantCall;
+ friend class VariantInternal;
+ // Variant takes 20 bytes when real_t is float, and 36 if double
+ // it only allocates extra memory for aabb/matrix.
+
+ Type type = NIL;
+
+ struct ObjData {
+ ObjectID id;
+ Object *obj;
+ };
+
+ /* array helpers */
+ struct PackedArrayRefBase {
+ SafeRefCount refcount;
+ _FORCE_INLINE_ PackedArrayRefBase *reference() {
+ if (this->refcount.ref()) {
+ return this;
+ } else {
+ return nullptr;
+ }
+ }
+ static _FORCE_INLINE_ PackedArrayRefBase *reference_from(PackedArrayRefBase *p_base, PackedArrayRefBase *p_from) {
+ if (p_base == p_from) {
+ return p_base; //same thing, do nothing
+ }
+
+ if (p_from->reference()) {
+ if (p_base->refcount.unref()) {
+ memdelete(p_base);
+ }
+ return p_from;
+ } else {
+ return p_base; //keep, could not reference new
+ }
+ }
+ static _FORCE_INLINE_ void destroy(PackedArrayRefBase *p_array) {
+ if (p_array->refcount.unref()) {
+ memdelete(p_array);
+ }
+ }
+ _FORCE_INLINE_ virtual ~PackedArrayRefBase() {} //needs virtual destructor, but make inline
+ };
+
+ template <class T>
+ struct PackedArrayRef : public PackedArrayRefBase {
+ Vector<T> array;
+ static _FORCE_INLINE_ PackedArrayRef<T> *create() {
+ return memnew(PackedArrayRef<T>);
+ }
+ static _FORCE_INLINE_ PackedArrayRef<T> *create(const Vector<T> &p_from) {
+ return memnew(PackedArrayRef<T>(p_from));
+ }
+
+ static _FORCE_INLINE_ const Vector<T> &get_array(PackedArrayRefBase *p_base) {
+ return static_cast<PackedArrayRef<T> *>(p_base)->array;
+ }
+ static _FORCE_INLINE_ Vector<T> *get_array_ptr(const PackedArrayRefBase *p_base) {
+ return &const_cast<PackedArrayRef<T> *>(static_cast<const PackedArrayRef<T> *>(p_base))->array;
+ }
+
+ _FORCE_INLINE_ PackedArrayRef(const Vector<T> &p_from) {
+ array = p_from;
+ refcount.init();
+ }
+ _FORCE_INLINE_ PackedArrayRef() {
+ refcount.init();
+ }
+ };
+
+ /* end of array helpers */
+ _ALWAYS_INLINE_ ObjData &_get_obj();
+ _ALWAYS_INLINE_ const ObjData &_get_obj() const;
+
+ union {
+ bool _bool;
+ int64_t _int;
+ double _float;
+ Transform2D *_transform2d;
+ ::AABB *_aabb;
+ Basis *_basis;
+ Transform *_transform;
+ PackedArrayRefBase *packed_array;
+ void *_ptr; //generic pointer
+ uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)];
+ } _data alignas(8);
+
+ void reference(const Variant &p_variant);
+ void clear();
+
+public:
+ _FORCE_INLINE_ Type get_type() const {
+ return type;
+ }
+ static String get_type_name(Variant::Type p_type);
+ 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;
+ _FORCE_INLINE_ bool is_num() const {
+ return type == INT || type == FLOAT;
+ }
+ _FORCE_INLINE_ bool is_array() const {
+ return type >= ARRAY;
+ }
+ bool is_shared() const;
+ bool is_zero() const;
+ bool is_one() const;
+ bool is_null() const;
+
+ operator bool() const;
+ operator signed int() const;
+ operator unsigned int() const; // this is the real one
+ operator signed short() const;
+ operator unsigned short() const;
+ operator signed char() const;
+ operator unsigned char() const;
+ //operator long unsigned int() const;
+ operator int64_t() const;
+ operator uint64_t() const;
+#ifdef NEED_LONG_INT
+ operator signed long() const;
+ operator unsigned long() const;
+#endif
+
+ operator ObjectID() const;
+
+ operator char32_t() const;
+ operator float() const;
+ operator double() const;
+ operator String() const;
+ operator StringName() const;
+ operator Vector2() const;
+ operator Vector2i() const;
+ operator Rect2() const;
+ operator Rect2i() const;
+ operator Vector3() const;
+ operator Vector3i() const;
+ operator Plane() const;
+ operator ::AABB() const;
+ operator Quat() const;
+ operator Basis() const;
+ operator Transform() const;
+ operator Transform2D() const;
+
+ operator Color() const;
+ operator NodePath() const;
+ operator RID() const;
+
+ operator Object *() const;
+ operator Node *() const;
+ operator Control *() const;
+
+ operator Callable() const;
+ operator Signal() const;
+
+ operator Dictionary() const;
+ operator Array() const;
+
+ operator Vector<uint8_t>() const;
+ operator Vector<int32_t>() const;
+ operator Vector<int64_t>() const;
+ operator Vector<float>() const;
+ operator Vector<double>() const;
+ operator Vector<String>() const;
+ operator Vector<Vector3>() const;
+ operator Vector<Color>() const;
+ operator Vector<Plane>() const;
+ operator Vector<Face3>() const;
+
+ operator Vector<Variant>() const;
+ operator Vector<StringName>() const;
+ operator Vector<RID>() const;
+ operator Vector<Vector2>() const;
+
+ // some core type enums to convert to
+ operator Margin() const;
+ operator Orientation() const;
+
+ operator IP_Address() const;
+
+ Object *get_validated_object() const;
+ Object *get_validated_object_with_check(bool &r_previously_freed) const;
+
+ Variant(bool p_bool);
+ Variant(signed int p_int); // real one
+ Variant(unsigned int p_int);
+#ifdef NEED_LONG_INT
+ Variant(signed long p_long); // real one
+ Variant(unsigned long p_long);
+//Variant(long unsigned int p_long);
+#endif
+ Variant(signed short p_short); // real one
+ Variant(unsigned short p_short);
+ Variant(signed char p_char); // real one
+ Variant(unsigned char p_char);
+ Variant(int64_t p_int); // real one
+ Variant(uint64_t p_int);
+ Variant(float p_float);
+ Variant(double p_double);
+ Variant(const ObjectID &p_id);
+ Variant(const String &p_string);
+ Variant(const StringName &p_string);
+ Variant(const char *const p_cstring);
+ Variant(const char32_t *p_wstring);
+ Variant(const Vector2 &p_vector2);
+ Variant(const Vector2i &p_vector2i);
+ Variant(const Rect2 &p_rect2);
+ Variant(const Rect2i &p_rect2i);
+ Variant(const Vector3 &p_vector3);
+ Variant(const Vector3i &p_vector3i);
+ Variant(const Plane &p_plane);
+ Variant(const ::AABB &p_aabb);
+ Variant(const Quat &p_quat);
+ Variant(const Basis &p_matrix);
+ Variant(const Transform2D &p_transform);
+ Variant(const Transform &p_transform);
+ Variant(const Color &p_color);
+ Variant(const NodePath &p_node_path);
+ Variant(const RID &p_rid);
+ Variant(const Object *p_object);
+ Variant(const Callable &p_callable);
+ Variant(const Signal &p_signal);
+ Variant(const Dictionary &p_dictionary);
+
+ Variant(const Array &p_array);
+ Variant(const Vector<Plane> &p_array); // helper
+ Variant(const Vector<uint8_t> &p_byte_array);
+ Variant(const Vector<int32_t> &p_int32_array);
+ Variant(const Vector<int64_t> &p_int64_array);
+ Variant(const Vector<float> &p_float32_array);
+ Variant(const Vector<double> &p_float64_array);
+ Variant(const Vector<String> &p_string_array);
+ Variant(const Vector<Vector3> &p_vector3_array);
+ Variant(const Vector<Color> &p_color_array);
+ Variant(const Vector<Face3> &p_face_array);
+
+ Variant(const Vector<Variant> &p_array);
+ Variant(const Vector<StringName> &p_array);
+ Variant(const Vector<RID> &p_array); // helper
+ Variant(const Vector<Vector2> &p_array); // helper
+
+ Variant(const IP_Address &p_address);
+
+ // If this changes the table in variant_op must be updated
+ enum Operator {
+
+ //comparison
+ OP_EQUAL,
+ OP_NOT_EQUAL,
+ OP_LESS,
+ OP_LESS_EQUAL,
+ OP_GREATER,
+ OP_GREATER_EQUAL,
+ //mathematic
+ OP_ADD,
+ OP_SUBTRACT,
+ OP_MULTIPLY,
+ OP_DIVIDE,
+ OP_NEGATE,
+ OP_POSITIVE,
+ OP_MODULE,
+ //bitwise
+ OP_SHIFT_LEFT,
+ OP_SHIFT_RIGHT,
+ OP_BIT_AND,
+ OP_BIT_OR,
+ OP_BIT_XOR,
+ OP_BIT_NEGATE,
+ //logic
+ OP_AND,
+ OP_OR,
+ OP_XOR,
+ OP_NOT,
+ //containment
+ OP_IN,
+ OP_MAX
+
+ };
+
+ static String get_operator_name(Operator p_op);
+ static void evaluate(const Operator &p_op, const Variant &p_a, const Variant &p_b, Variant &r_ret, bool &r_valid);
+ static _FORCE_INLINE_ Variant evaluate(const Operator &p_op, const Variant &p_a, const Variant &p_b) {
+ bool valid = true;
+ Variant res;
+ evaluate(p_op, p_a, p_b, res, valid);
+ return res;
+ }
+
+ Variant::Type get_operator_return_type(Operator p_operator, Type p_type_a, Type p_type_b);
+ typedef void (*ValidatedOperatorEvaluator)(const Variant *left, const Variant *right, Variant *r_ret);
+ static ValidatedOperatorEvaluator get_validated_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b);
+#ifdef PTRCALL_ENABLED
+ typedef void (*PTROperatorEvaluator)(const void *left, const void *right, void *r_ret);
+ static PTROperatorEvaluator get_ptr_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b);
+#endif
+
+ void zero();
+ Variant duplicate(bool deep = false) 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);
+
+ class InternalMethod {
+#ifdef DEBUG_ENABLED
+ protected:
+ StringName method_name;
+ Variant::Type base_type;
+#endif
+ public:
+ enum Flags {
+ FLAG_IS_CONST = 1,
+ FLAG_RETURNS_VARIANT = 2,
+ FLAG_NO_PTRCALL = 4,
+ FLAG_VARARGS = 8
+ };
+
+ virtual int get_argument_count() const = 0;
+ virtual Type get_argument_type(int p_arg) const = 0;
+ virtual Type get_return_type() const = 0;
+ virtual uint32_t get_flags() const = 0;
+
+#ifdef DEBUG_ENABLED
+ virtual String get_argument_name(int p_arg) const = 0;
+ StringName get_name() const {
+ return method_name;
+ }
+ Variant::Type get_base_type() const {
+ return base_type;
+ }
+#endif
+ virtual Vector<Variant> get_default_arguments() const = 0;
+ virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) = 0;
+ virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) = 0;
+#ifdef PTRCALL_ENABLED
+ virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) = 0;
+#endif
+ virtual ~InternalMethod() {}
+ };
+
+ static InternalMethod *get_internal_method(Type p_type, const StringName &p_method_name);
+
+ void call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, Callable::CallError &r_error);
+ Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant());
+
+ static String get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
+ static String get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
+
+ static Variant construct(const Variant::Type, const Variant **p_args, int p_argcount, Callable::CallError &r_error, bool p_strict = true);
+
+ void get_method_list(List<MethodInfo> *p_list) const;
+ bool has_method(const StringName &p_method) const;
+ static Vector<Variant::Type> get_method_argument_types(Variant::Type p_type, const StringName &p_method);
+ static Vector<Variant> get_method_default_arguments(Variant::Type p_type, const StringName &p_method);
+ static Variant::Type get_method_return_type(Variant::Type p_type, const StringName &p_method, bool *r_has_return = nullptr);
+ static Vector<StringName> get_method_argument_names(Variant::Type p_type, const StringName &p_method);
+ static bool is_method_const(Variant::Type p_type, const StringName &p_method);
+
+ void set_named(const StringName &p_member, const Variant &p_value, bool &r_valid);
+ Variant get_named(const StringName &p_member, bool &r_valid) const;
+
+ typedef void (*ValidatedSetter)(Variant *base, const Variant *value);
+ typedef void (*ValidatedGetter)(const Variant *base, Variant *value);
+
+ static bool has_member(Variant::Type p_type, const StringName &p_member);
+ static Variant::Type get_member_type(Variant::Type p_type, const StringName &p_member);
+ static void get_member_list(Type p_type, List<StringName> *r_members);
+
+ static ValidatedSetter get_member_validated_setter(Variant::Type p_type, const StringName &p_member);
+ static ValidatedGetter get_member_validated_getter(Variant::Type p_type, const StringName &p_member);
+
+ typedef void (*PTRSetter)(void *base, const void *value);
+ typedef void (*PTRGetter)(const void *base, void *value);
+
+ static PTRSetter get_member_ptr_setter(Variant::Type p_type, const StringName &p_member);
+ static PTRGetter get_member_ptr_getter(Variant::Type p_type, const StringName &p_member);
+
+ static bool has_indexing(Variant::Type p_type);
+ static Variant::Type get_indexed_element_type(Variant::Type p_type);
+
+ typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool &oob);
+ typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool &oob);
+
+ static ValidatedIndexedSetter get_member_validated_indexed_setter(Variant::Type p_type);
+ static ValidatedIndexedGetter get_member_validated_indexed_getter(Variant::Type p_type);
+
+ typedef void (*PTRIndexedSetter)(void *base, int64_t index, const void *value);
+ typedef void (*PTRIndexedGetter)(const void *base, int64_t index, void *value);
+
+ static PTRIndexedSetter get_member_ptr_indexed_setter(Variant::Type p_type);
+ static PTRIndexedGetter get_member_ptr_indexed_getter(Variant::Type p_type);
+
+ void set_indexed(int64_t p_index, const Variant &p_value, bool &r_valid, bool &r_oob);
+ Variant get_indexed(int64_t p_index, bool &r_valid, bool &r_oob) const;
+
+ uint64_t get_indexed_size() const;
+
+ static bool is_keyed(Variant::Type p_type);
+
+ typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value, bool &valid);
+ typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool &valid);
+ typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key, bool &valid);
+
+ static ValidatedKeyedSetter get_member_validated_keyed_setter(Variant::Type p_type);
+ static ValidatedKeyedGetter get_member_validated_keyed_getter(Variant::Type p_type);
+ static ValidatedKeyedChecker get_member_validated_keyed_checker(Variant::Type p_type);
+
+ typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value);
+ typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value);
+ typedef bool (*PTRKeyedChecker)(const void *base, const void *key);
+
+ static PTRKeyedSetter get_member_ptr_keyed_setter(Variant::Type p_type);
+ static PTRKeyedGetter get_member_ptr_keyed_getter(Variant::Type p_type);
+ static PTRKeyedChecker get_member_ptr_keyed_checker(Variant::Type p_type);
+
+ void set_keyed(const Variant &p_key, const Variant &p_value, bool &r_valid);
+ Variant get_keyed(const Variant &p_key, bool &r_valid) const;
+ bool has_key(const Variant &p_key, bool &r_valid) const;
+
+ void set(const Variant &p_index, const Variant &p_value, bool *r_valid = nullptr);
+ Variant get(const Variant &p_index, bool *r_valid = nullptr) const;
+ bool in(const Variant &p_index, bool *r_valid = nullptr) const;
+
+ bool iter_init(Variant &r_iter, bool &r_valid) const;
+ bool iter_next(Variant &r_iter, bool &r_valid) const;
+ Variant iter_get(const Variant &r_iter, bool &r_valid) const;
+
+ void get_property_list(List<PropertyInfo> *p_list) const;
+
+ //argsVariant call()
+
+ bool operator==(const Variant &p_variant) const;
+ bool operator!=(const Variant &p_variant) const;
+ bool operator<(const Variant &p_variant) const;
+ uint32_t hash() const;
+
+ bool hash_compare(const Variant &p_variant) const;
+ bool booleanize() const;
+ String stringify(List<const void *> &stack) const;
+
+ void static_assign(const Variant &p_variant);
+ static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list);
+ static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants);
+ static bool has_constant(Variant::Type p_type, const StringName &p_value);
+ static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = nullptr);
+
+ typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud);
+ typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value);
+
+ String get_construct_string() const;
+ static void construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct = nullptr, void *p_construct_ud = nullptr);
+
+ void operator=(const Variant &p_variant); // only this is enough for all the other types
+
+ Variant(const Variant &p_variant);
+ _FORCE_INLINE_ Variant() {}
+ _FORCE_INLINE_ ~Variant() {
+ if (type != Variant::NIL) {
+ clear();
+ }
+ }
+};
+
+//typedef Dictionary Dictionary; no
+//typedef Array Array;
+
+Vector<Variant> varray();
+Vector<Variant> varray(const Variant &p_arg1);
+Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2);
+Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3);
+Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4);
+Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5);
+
+struct VariantHasher {
+ static _FORCE_INLINE_ uint32_t hash(const Variant &p_variant) { return p_variant.hash(); }
+};
+
+struct VariantComparator {
+ static _FORCE_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) { return p_lhs.hash_compare(p_rhs); }
+};
+
+Variant::ObjData &Variant::_get_obj() {
+ return *reinterpret_cast<ObjData *>(&_data._mem[0]);
+}
+
+const Variant::ObjData &Variant::_get_obj() const {
+ return *reinterpret_cast<const ObjData *>(&_data._mem[0]);
+}
+
+String vformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
+
+#endif // VARIANT_H
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
new file mode 100644
index 0000000000..37424f5ff9
--- /dev/null
+++ b/core/variant/variant_call.cpp
@@ -0,0 +1,2089 @@
+/*************************************************************************/
+/* variant_call.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "variant.h"
+
+#include "core/core_string_names.h"
+#include "core/crypto/crypto_core.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/io/compression.h"
+#include "core/object/class_db.h"
+#include "core/os/os.h"
+#include "core/templates/oa_hash_map.h"
+
+_FORCE_INLINE_ void sarray_add_str(Vector<String> &arr) {
+}
+
+_FORCE_INLINE_ void sarray_add_str(Vector<String> &arr, const String &p_str) {
+ arr.push_back(p_str);
+}
+
+template <class... P>
+_FORCE_INLINE_ void sarray_add_str(Vector<String> &arr, const String &p_str, P... p_args) {
+ arr.push_back(p_str);
+ sarray_add_str(arr, p_args...);
+}
+
+template <class... P>
+_FORCE_INLINE_ Vector<String> sarray(P... p_args) {
+ Vector<String> arr;
+ sarray_add_str(arr, p_args...);
+ return arr;
+}
+
+typedef void (*VariantFunc)(Variant &r_ret, Variant &p_self, const Variant **p_args);
+typedef void (*VariantConstructFunc)(Variant &r_ret, const Variant **p_args);
+
+struct _VariantCall {
+ template <class T, class... P>
+ class InternalMethod : public Variant::InternalMethod {
+ public:
+ void (T::*method)(P...);
+ Vector<Variant> default_values;
+#ifdef DEBUG_ENABLED
+ Vector<String> argument_names;
+#endif
+
+ virtual int get_argument_count() const {
+ return sizeof...(P);
+ }
+ virtual Variant::Type get_argument_type(int p_arg) const {
+ return call_get_argument_type<P...>(p_arg);
+ }
+#ifdef DEBUG_ENABLED
+ virtual String get_argument_name(int p_arg) const {
+ ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String());
+ return argument_names[p_arg];
+ }
+#endif
+ virtual Vector<Variant> get_default_arguments() const {
+ return default_values;
+ }
+
+ virtual Variant::Type get_return_type() const {
+ return Variant::NIL;
+ }
+ virtual uint32_t get_flags() const {
+ return 0;
+ }
+
+ virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ call_with_variant_args_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, default_values);
+ }
+
+ virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args(base, method, p_args);
+ }
+
+#ifdef PTRCALL_ENABLED
+ virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args<T, P...>(reinterpret_cast<T *>(p_base), method, p_args);
+ }
+#endif
+ InternalMethod(void (T::*p_method)(P...), const Vector<Variant> &p_default_args
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type
+#endif
+ ) {
+ method = p_method;
+ default_values = p_default_args;
+#ifdef DEBUG_ENABLED
+ argument_names = p_arg_names;
+ method_name = p_method_name;
+ base_type = p_base_type;
+#endif
+ }
+ };
+
+ template <class T, class R, class... P>
+ class InternalMethodR : public Variant::InternalMethod {
+ public:
+ R(T::*method)
+ (P...);
+ Vector<Variant> default_values;
+#ifdef DEBUG_ENABLED
+ Vector<String> argument_names;
+#endif
+
+ virtual int get_argument_count() const {
+ return sizeof...(P);
+ }
+ virtual Variant::Type get_argument_type(int p_arg) const {
+ return call_get_argument_type<P...>(p_arg);
+ return Variant::NIL;
+ }
+#ifdef DEBUG_ENABLED
+ virtual String get_argument_name(int p_arg) const {
+ ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String());
+ return argument_names[p_arg];
+ }
+#endif
+ virtual Vector<Variant> get_default_arguments() const {
+ return default_values;
+ }
+
+ virtual Variant::Type get_return_type() const {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+ }
+ virtual uint32_t get_flags() const {
+ uint32_t f = 0;
+ if (get_return_type() == Variant::NIL) {
+ f |= FLAG_RETURNS_VARIANT;
+ }
+ return f;
+ }
+
+ virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ call_with_variant_args_ret_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, default_values);
+ }
+
+ virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_ret(base, method, p_args, r_ret);
+ }
+#ifdef PTRCALL_ENABLED
+ virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_ret<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
+ }
+#endif
+ InternalMethodR(R (T::*p_method)(P...), const Vector<Variant> &p_default_args
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type
+#endif
+ ) {
+ method = p_method;
+ default_values = p_default_args;
+#ifdef DEBUG_ENABLED
+ argument_names = p_arg_names;
+ method_name = p_method_name;
+ base_type = p_base_type;
+#endif
+ }
+ };
+
+ template <class T, class R, class... P>
+ class InternalMethodRC : public Variant::InternalMethod {
+ public:
+ R(T::*method)
+ (P...) const;
+ Vector<Variant> default_values;
+#ifdef DEBUG_ENABLED
+ Vector<String> argument_names;
+#endif
+
+ virtual int get_argument_count() const {
+ return sizeof...(P);
+ }
+ virtual Variant::Type get_argument_type(int p_arg) const {
+ return call_get_argument_type<P...>(p_arg);
+ }
+#ifdef DEBUG_ENABLED
+ virtual String get_argument_name(int p_arg) const {
+ ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String());
+ return argument_names[p_arg];
+ }
+#endif
+ virtual Vector<Variant> get_default_arguments() const {
+ return default_values;
+ }
+
+ virtual Variant::Type get_return_type() const {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+ }
+ virtual uint32_t get_flags() const {
+ uint32_t f = FLAG_IS_CONST;
+ if (get_return_type() == Variant::NIL) {
+ f |= FLAG_RETURNS_VARIANT;
+ }
+ return f;
+ }
+
+ virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ call_with_variant_args_retc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, default_values);
+ }
+
+ virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_retc(base, method, p_args, r_ret);
+ }
+#ifdef PTRCALL_ENABLED
+ virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
+ }
+#endif
+ InternalMethodRC(R (T::*p_method)(P...) const, const Vector<Variant> &p_default_args
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type
+#endif
+ ) {
+ method = p_method;
+ default_values = p_default_args;
+#ifdef DEBUG_ENABLED
+ argument_names = p_arg_names;
+ method_name = p_method_name;
+ base_type = p_base_type;
+#endif
+ }
+ };
+
+ template <class T, class R, class... P>
+ class InternalMethodRS : public Variant::InternalMethod {
+ public:
+ R(*method)
+ (T *, P...);
+ Vector<Variant> default_values;
+#ifdef DEBUG_ENABLED
+ Vector<String> argument_names;
+#endif
+
+ virtual int get_argument_count() const {
+ return sizeof...(P);
+ }
+ virtual Variant::Type get_argument_type(int p_arg) const {
+ return call_get_argument_type<P...>(p_arg);
+ }
+#ifdef DEBUG_ENABLED
+ virtual String get_argument_name(int p_arg) const {
+ ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String());
+ return argument_names[p_arg];
+ }
+#endif
+ virtual Vector<Variant> get_default_arguments() const {
+ return default_values;
+ }
+
+ virtual Variant::Type get_return_type() const {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+ }
+ virtual uint32_t get_flags() const {
+ uint32_t f = 0;
+ if (get_return_type() == Variant::NIL) {
+ f |= FLAG_RETURNS_VARIANT;
+ }
+ return f;
+ }
+
+ virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ const Variant **args = p_args;
+#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);
+ return;
+ }
+#endif
+ if ((size_t)p_argcount < sizeof...(P)) {
+ size_t missing = sizeof...(P) - (size_t)p_argcount;
+ if (missing <= (size_t)default_values.size()) {
+ args = (const Variant **)alloca(sizeof...(P) * sizeof(const Variant *));
+ // GCC fails to see that `sizeof...(P)` cannot be 0 here given the previous
+ // conditions, so it raises a warning on the potential use of `i < 0` as the
+ // execution condition.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+ for (size_t i = 0; i < sizeof...(P); i++) {
+ if (i < (size_t)p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (default_values.size() - missing)];
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+ } else {
+#ifdef DEBUG_ENABLED
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+#endif
+ return;
+ }
+ }
+ call_with_variant_args_retc_static_helper(VariantGetInternalPtr<T>::get_ptr(base), method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+ }
+
+ virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_retc(base, method, p_args, r_ret);
+ }
+#ifdef PTRCALL_ENABLED
+ virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
+ }
+#endif
+ InternalMethodRS(R (*p_method)(T *, P...), const Vector<Variant> &p_default_args
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type
+#endif
+ ) {
+ method = p_method;
+ default_values = p_default_args;
+#ifdef DEBUG_ENABLED
+ argument_names = p_arg_names;
+ method_name = p_method_name;
+ base_type = p_base_type;
+#endif
+ }
+ };
+
+ class InternalMethodVC : public Variant::InternalMethod {
+ public:
+ typedef void (*MethodVC)(Variant *, const Variant **, int, Variant &r_ret, Callable::CallError &);
+ MethodVC methodvc = nullptr;
+ uint32_t base_flags = 0;
+ Vector<String> argument_names;
+ Vector<Variant::Type> argument_types;
+ Variant::Type return_type = Variant::NIL;
+
+ virtual int get_argument_count() const {
+ return argument_names.size();
+ }
+ virtual Variant::Type get_argument_type(int p_arg) const {
+ ERR_FAIL_INDEX_V(p_arg, argument_types.size(), Variant::NIL);
+ return argument_types[p_arg];
+ }
+#ifdef DEBUG_ENABLED
+ virtual String get_argument_name(int p_arg) const {
+ ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String());
+ return argument_names[p_arg];
+ }
+#endif
+ virtual Vector<Variant> get_default_arguments() const {
+ return Vector<Variant>();
+ }
+
+ virtual Variant::Type get_return_type() const {
+ return return_type;
+ }
+ virtual uint32_t get_flags() const {
+ return base_flags | FLAG_NO_PTRCALL;
+ }
+
+ virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ methodvc(base, p_args, p_argcount, r_ret, r_error);
+ }
+
+ virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) {
+ ERR_FAIL_MSG("No support for validated call");
+ }
+#ifdef PTRCALL_ENABLED
+ virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) {
+ ERR_FAIL_MSG("No support for ptrcall call");
+ }
+#endif
+ InternalMethodVC(MethodVC p_method, uint32_t p_flags, const Vector<Variant::Type> &p_argument_types, const Variant::Type &p_return_type
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type
+#endif
+ ) {
+ methodvc = p_method;
+ argument_types = p_argument_types;
+ return_type = p_return_type;
+ base_flags = p_flags;
+#ifdef DEBUG_ENABLED
+ argument_names = p_arg_names;
+ method_name = p_method_name;
+ base_type = p_base_type;
+#endif
+ }
+ };
+
+ typedef OAHashMap<StringName, Variant::InternalMethod *> MethodMap;
+ static MethodMap *type_internal_methods;
+ static List<StringName> *type_internal_method_names;
+
+ template <class T, class... P>
+ static void _bind_method(const StringName &p_name, void (T::*p_method)(P...), const Vector<Variant> &p_default_args = Vector<Variant>()
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_argument_names = Vector<String>()
+#endif
+ ) {
+
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(p_argument_names.size() != sizeof...(P), "Wrong argument name count supplied for method: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name));
+ ERR_FAIL_COND(type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].has(p_name));
+#endif
+#ifdef DEBUG_ENABLED
+ Variant::InternalMethod *m = memnew((InternalMethod<T, P...>)(p_method, p_default_args, p_argument_names, p_name, GetTypeInfo<T>::VARIANT_TYPE));
+#else
+ Variant::InternalMethod *m = memnew((InternalMethod<T, P...>)(p_method, p_default_args));
+#endif
+
+ type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].insert(p_name, m);
+ type_internal_method_names[GetTypeInfo<T>::VARIANT_TYPE].push_back(p_name);
+ }
+
+ template <class T, class R, class... P>
+ static void _bind_method(const StringName &p_name, R (T::*p_method)(P...) const, const Vector<Variant> &p_default_args = Vector<Variant>()
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_argument_names = Vector<String>()
+#endif
+ ) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(p_argument_names.size() != sizeof...(P), "Wrong argument name count supplied for method: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name));
+ ERR_FAIL_COND_MSG(type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].has(p_name), " Method already registered: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name));
+
+#endif
+#ifdef DEBUG_ENABLED
+ Variant::InternalMethod *m = memnew((InternalMethodRC<T, R, P...>)(p_method, p_default_args, p_argument_names, p_name, GetTypeInfo<T>::VARIANT_TYPE));
+#else
+ Variant::InternalMethod *m = memnew((InternalMethodRC<T, R, P...>)(p_method, p_default_args));
+#endif
+
+ type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].insert(p_name, m);
+ type_internal_method_names[GetTypeInfo<T>::VARIANT_TYPE].push_back(p_name);
+ }
+
+ template <class T, class R, class... P>
+ static void _bind_method(const StringName &p_name, R (T::*p_method)(P...), const Vector<Variant> &p_default_args = Vector<Variant>()
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_argument_names = Vector<String>()
+#endif
+ ) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(p_argument_names.size() != sizeof...(P), "Wrong argument name count supplied for method: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name));
+ ERR_FAIL_COND_MSG(type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].has(p_name), " Method already registered: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name));
+#endif
+
+#ifdef DEBUG_ENABLED
+ Variant::InternalMethod *m = memnew((InternalMethodR<T, R, P...>)(p_method, p_default_args, p_argument_names, p_name, GetTypeInfo<T>::VARIANT_TYPE));
+#else
+ Variant::InternalMethod *m = memnew((InternalMethodR<T, R, P...>)(p_method, p_default_args));
+#endif
+ type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].insert(p_name, m);
+ type_internal_method_names[GetTypeInfo<T>::VARIANT_TYPE].push_back(p_name);
+ }
+
+#ifdef DEBUG_ENABLED
+#define bind_method(m_type, m_method, m_arg_names, m_default_args) _VariantCall::_bind_method(#m_method, &m_type ::m_method, m_default_args, m_arg_names)
+#else
+#define bind_method(m_type, m_method, m_arg_names, m_default_args) _VariantCall::_bind_method(#m_method, &m_type ::m_method, m_default_args)
+#endif
+
+#ifdef DEBUG_ENABLED
+#define bind_methodv(m_name, m_method, m_arg_names, m_default_args) _VariantCall::_bind_method(#m_name, m_method, m_default_args, m_arg_names)
+#else
+#define bind_methodv(m_name, m_method, m_arg_names, m_default_args) _VariantCall::_bind_method(#m_name, m_method, m_default_args)
+#endif
+
+ template <class T, class R, class... P>
+ static void _bind_function(const StringName &p_name, R (*p_method)(T *, P...), const Vector<Variant> &p_default_args = Vector<Variant>()
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_argument_names = Vector<String>()
+#endif
+ ) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(p_argument_names.size() != sizeof...(P), "Wrong argument name count supplied for method: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name));
+ ERR_FAIL_COND_MSG(type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].has(p_name), " Method already registered: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name));
+#endif
+
+#ifdef DEBUG_ENABLED
+ Variant::InternalMethod *m = memnew((InternalMethodRS<T, R, P...>)(p_method, p_default_args, p_argument_names, p_name, GetTypeInfo<T>::VARIANT_TYPE));
+#else
+ Variant::InternalMethod *m = memnew((InternalMethodRS<T, R, P...>)(p_method, p_default_args));
+#endif
+
+ type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].insert(p_name, m);
+ type_internal_method_names[GetTypeInfo<T>::VARIANT_TYPE].push_back(p_name);
+ }
+
+#ifdef DEBUG_ENABLED
+#define bind_function(m_name, m_method, m_arg_names, m_default_args) _VariantCall::_bind_function(m_name, m_method, m_default_args, m_arg_names)
+#else
+#define bind_function(m_name, m_method, m_arg_names, m_default_args) _VariantCall::_bind_function(m_name, m_method, m_default_args)
+#endif
+
+ static void _bind_custom(Variant::Type p_type, const StringName &p_name, InternalMethodVC::MethodVC p_method, uint32_t p_flags, const Vector<Variant::Type> &p_argument_types, const Variant::Type &p_return_type
+#ifdef DEBUG_ENABLED
+ ,
+ const Vector<String> &p_argument_names = Vector<String>()
+#endif
+ ) {
+
+#ifdef DEBUG_ENABLED
+ Variant::InternalMethod *m = memnew(InternalMethodVC(p_method, p_flags, p_argument_types, p_return_type, p_argument_names, p_name, p_type));
+#else
+ Variant::InternalMethod *m = memnew(InternalMethodVC(p_method, p_flags, p_argument_types, p_return_type));
+#endif
+
+ type_internal_methods[p_type].insert(p_name, m);
+ type_internal_method_names[p_type].push_back(p_name);
+ }
+
+#ifdef DEBUG_ENABLED
+#define bind_custom(m_type, m_name, m_method, m_flags, m_arg_types, m_ret_type, m_arg_names) _VariantCall::_bind_custom(m_type, m_name, m_method, m_flags, m_arg_types, m_ret_type, m_arg_names)
+#else
+#define bind_custom(m_type, m_name, m_method, m_flags, m_arg_types, m_ret_type, m_arg_names) _VariantCall::_bind_custom(m_type, m_name, m_method, m_flags, m_arg_types, m_ret_type)
+#endif
+
+ static String func_PackedByteArray_get_string_from_ascii(PackedByteArray *p_instance) {
+ String s;
+ if (p_instance->size() > 0) {
+ const uint8_t *r = p_instance->ptr();
+ CharString cs;
+ cs.resize(p_instance->size() + 1);
+ copymem(cs.ptrw(), r, p_instance->size());
+ cs[p_instance->size()] = 0;
+
+ s = cs.get_data();
+ }
+ return s;
+ }
+
+ static String func_PackedByteArray_get_string_from_utf8(PackedByteArray *p_instance) {
+ String s;
+ if (p_instance->size() > 0) {
+ const uint8_t *r = p_instance->ptr();
+ s.parse_utf8((const char *)r, p_instance->size());
+ }
+ return s;
+ }
+
+ static String func_PackedByteArray_get_string_from_utf16(PackedByteArray *p_instance) {
+ String s;
+ if (p_instance->size() > 0) {
+ const uint8_t *r = p_instance->ptr();
+ s.parse_utf16((const char16_t *)r, p_instance->size() / 2);
+ }
+ return s;
+ }
+
+ static String func_PackedByteArray_get_string_from_utf32(PackedByteArray *p_instance) {
+ String s;
+ if (p_instance->size() > 0) {
+ const uint8_t *r = p_instance->ptr();
+ s = String((const char32_t *)r, p_instance->size() / 4);
+ }
+ return s;
+ }
+
+ static PackedByteArray func_PackedByteArray_compress(PackedByteArray *p_instance, int p_mode) {
+ PackedByteArray compressed;
+
+ if (p_instance->size() > 0) {
+ Compression::Mode mode = (Compression::Mode)(p_mode);
+ compressed.resize(Compression::get_max_compressed_buffer_size(p_instance->size(), mode));
+ int result = Compression::compress(compressed.ptrw(), p_instance->ptr(), p_instance->size(), mode);
+
+ result = result >= 0 ? result : 0;
+ compressed.resize(result);
+ }
+
+ return compressed;
+ }
+
+ static PackedByteArray func_PackedByteArray_decompress(PackedByteArray *p_instance, int64_t p_buffer_size, int p_mode) {
+ PackedByteArray decompressed;
+ Compression::Mode mode = (Compression::Mode)(p_mode);
+
+ int64_t buffer_size = p_buffer_size;
+
+ if (buffer_size <= 0) {
+ ERR_FAIL_V_MSG(decompressed, "Decompression buffer size must be greater than zero.");
+ }
+
+ decompressed.resize(buffer_size);
+ int result = Compression::decompress(decompressed.ptrw(), buffer_size, p_instance->ptr(), p_instance->size(), mode);
+
+ result = result >= 0 ? result : 0;
+ decompressed.resize(result);
+
+ return decompressed;
+ }
+
+ static PackedByteArray func_PackedByteArray_decompress_dynamic(PackedByteArray *p_instance, int64_t p_buffer_size, int p_mode) {
+ PackedByteArray decompressed;
+ int64_t max_output_size = p_buffer_size;
+ Compression::Mode mode = (Compression::Mode)(p_mode);
+
+ int result = Compression::decompress_dynamic(&decompressed, max_output_size, p_instance->ptr(), p_instance->size(), mode);
+
+ if (result == OK) {
+ return decompressed;
+ } else {
+ decompressed.clear();
+ ERR_FAIL_V_MSG(decompressed, "Decompression failed.");
+ }
+ }
+
+ static String func_PackedByteArray_hex_encode(PackedByteArray *p_instance) {
+ if (p_instance->size() == 0) {
+ return String();
+ }
+ const uint8_t *r = p_instance->ptr();
+ String s = String::hex_encode_buffer(&r[0], p_instance->size());
+ return s;
+ }
+
+ static void func_Callable_call(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->call(p_args, p_argcount, r_ret, r_error);
+ }
+
+ static void func_Callable_call_deferred(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->call_deferred(p_args, p_argcount);
+ }
+
+ static void func_Callable_bind(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ r_ret = callable->bind(p_args, p_argcount);
+ }
+
+ static void func_Signal_emit(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Signal *signal = VariantGetInternalPtr<Signal>::get_ptr(v);
+ signal->emit(p_args, p_argcount);
+ }
+
+ struct ConstructData {
+ int arg_count;
+ Vector<Variant::Type> arg_types;
+ Vector<String> arg_names;
+ VariantConstructFunc func;
+ };
+
+ struct ConstructFunc {
+ List<ConstructData> constructors;
+ };
+
+ static ConstructFunc *construct_funcs;
+
+ static void Vector2_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = Vector2(*p_args[0], *p_args[1]);
+ }
+
+ static void Vector2i_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = Vector2i(*p_args[0], *p_args[1]);
+ }
+
+ static void Rect2_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = Rect2(*p_args[0], *p_args[1]);
+ }
+
+ static void Rect2_init2(Variant &r_ret, const Variant **p_args) {
+ r_ret = Rect2(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
+ }
+
+ static void Rect2i_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = Rect2i(*p_args[0], *p_args[1]);
+ }
+
+ static void Rect2i_init2(Variant &r_ret, const Variant **p_args) {
+ r_ret = Rect2i(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
+ }
+
+ static void Transform2D_init2(Variant &r_ret, const Variant **p_args) {
+ Transform2D m(*p_args[0], *p_args[1]);
+ r_ret = m;
+ }
+
+ static void Transform2D_init3(Variant &r_ret, const Variant **p_args) {
+ Transform2D m;
+ m[0] = *p_args[0];
+ m[1] = *p_args[1];
+ m[2] = *p_args[2];
+ r_ret = m;
+ }
+
+ static void Vector3_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = Vector3(*p_args[0], *p_args[1], *p_args[2]);
+ }
+
+ static void Vector3i_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = Vector3i(*p_args[0], *p_args[1], *p_args[2]);
+ }
+
+ static void Plane_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = Plane(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
+ }
+
+ static void Plane_init2(Variant &r_ret, const Variant **p_args) {
+ r_ret = Plane(*p_args[0], *p_args[1], *p_args[2]);
+ }
+
+ static void Plane_init3(Variant &r_ret, const Variant **p_args) {
+ r_ret = Plane(p_args[0]->operator Vector3(), p_args[1]->operator real_t());
+ }
+ static void Plane_init4(Variant &r_ret, const Variant **p_args) {
+ r_ret = Plane(p_args[0]->operator Vector3(), p_args[1]->operator Vector3());
+ }
+
+ static void Quat_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = Quat(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
+ }
+
+ static void Quat_init2(Variant &r_ret, const Variant **p_args) {
+ r_ret = Quat(((Vector3)(*p_args[0])), ((real_t)(*p_args[1])));
+ }
+
+ static void Quat_init3(Variant &r_ret, const Variant **p_args) {
+ r_ret = Quat(((Vector3)(*p_args[0])));
+ }
+
+ static void Color_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = Color(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
+ }
+
+ static void Color_init2(Variant &r_ret, const Variant **p_args) {
+ r_ret = Color(*p_args[0], *p_args[1], *p_args[2]);
+ }
+
+ static void Color_init3(Variant &r_ret, const Variant **p_args) {
+ r_ret = Color::html(*p_args[0]);
+ }
+
+ static void Color_init4(Variant &r_ret, const Variant **p_args) {
+ r_ret = Color::hex(*p_args[0]);
+ }
+
+ static void Color_init5(Variant &r_ret, const Variant **p_args) {
+ r_ret = Color(((Color)(*p_args[0])), *p_args[1]);
+ }
+
+ static void AABB_init1(Variant &r_ret, const Variant **p_args) {
+ r_ret = ::AABB(*p_args[0], *p_args[1]);
+ }
+
+ static void Basis_init1(Variant &r_ret, const Variant **p_args) {
+ Basis m;
+ m.set_axis(0, *p_args[0]);
+ m.set_axis(1, *p_args[1]);
+ m.set_axis(2, *p_args[2]);
+ r_ret = m;
+ }
+
+ static void Basis_init2(Variant &r_ret, const Variant **p_args) {
+ r_ret = Basis(p_args[0]->operator Vector3(), p_args[1]->operator real_t());
+ }
+
+ static void Transform_init1(Variant &r_ret, const Variant **p_args) {
+ Transform t;
+ t.basis.set_axis(0, *p_args[0]);
+ t.basis.set_axis(1, *p_args[1]);
+ t.basis.set_axis(2, *p_args[2]);
+ t.origin = *p_args[3];
+ r_ret = t;
+ }
+
+ static void Transform_init2(Variant &r_ret, const Variant **p_args) {
+ r_ret = Transform(p_args[0]->operator Basis(), p_args[1]->operator Vector3());
+ }
+
+ static void Callable_init2(Variant &r_ret, const Variant **p_args) {
+ r_ret = Callable(p_args[0]->operator ObjectID(), p_args[1]->operator String());
+ }
+
+ static void Signal_init2(Variant &r_ret, const Variant **p_args) {
+ r_ret = Signal(p_args[0]->operator ObjectID(), p_args[1]->operator String());
+ }
+
+ static void add_constructor(VariantConstructFunc p_func, const Variant::Type p_type,
+ const String &p_name1 = "", const Variant::Type p_type1 = Variant::NIL,
+ const String &p_name2 = "", const Variant::Type p_type2 = Variant::NIL,
+ const String &p_name3 = "", const Variant::Type p_type3 = Variant::NIL,
+ const String &p_name4 = "", const Variant::Type p_type4 = Variant::NIL) {
+ ConstructData cd;
+ cd.func = p_func;
+ cd.arg_count = 0;
+
+ if (p_name1 == "") {
+ goto end;
+ }
+ cd.arg_count++;
+ cd.arg_names.push_back(p_name1);
+ cd.arg_types.push_back(p_type1);
+
+ if (p_name2 == "") {
+ goto end;
+ }
+ cd.arg_count++;
+ cd.arg_names.push_back(p_name2);
+ cd.arg_types.push_back(p_type2);
+
+ if (p_name3 == "") {
+ goto end;
+ }
+ cd.arg_count++;
+ cd.arg_names.push_back(p_name3);
+ cd.arg_types.push_back(p_type3);
+
+ if (p_name4 == "") {
+ goto end;
+ }
+ cd.arg_count++;
+ cd.arg_names.push_back(p_name4);
+ cd.arg_types.push_back(p_type4);
+
+ end:
+
+ construct_funcs[p_type].constructors.push_back(cd);
+ }
+
+ struct ConstantData {
+ Map<StringName, int> value;
+#ifdef DEBUG_ENABLED
+ List<StringName> value_ordered;
+#endif
+ Map<StringName, Variant> variant_value;
+#ifdef DEBUG_ENABLED
+ List<StringName> variant_value_ordered;
+#endif
+ };
+
+ static ConstantData *constant_data;
+
+ static void add_constant(int p_type, StringName p_constant_name, int p_constant_value) {
+ constant_data[p_type].value[p_constant_name] = p_constant_value;
+#ifdef DEBUG_ENABLED
+ constant_data[p_type].value_ordered.push_back(p_constant_name);
+#endif
+ }
+
+ static void add_variant_constant(int p_type, StringName p_constant_name, const Variant &p_constant_value) {
+ constant_data[p_type].variant_value[p_constant_name] = p_constant_value;
+#ifdef DEBUG_ENABLED
+ constant_data[p_type].variant_value_ordered.push_back(p_constant_name);
+#endif
+ }
+};
+
+_VariantCall::ConstructFunc *_VariantCall::construct_funcs = nullptr;
+_VariantCall::ConstantData *_VariantCall::constant_data = nullptr;
+_VariantCall::MethodMap *_VariantCall::type_internal_methods = nullptr;
+List<StringName> *_VariantCall::type_internal_method_names = nullptr;
+
+Variant Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ Variant ret;
+ call_ptr(p_method, p_args, p_argcount, &ret, r_error);
+ return ret;
+}
+
+void Variant::call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, Callable::CallError &r_error) {
+ Variant ret;
+
+ if (type == Variant::OBJECT) {
+ //call object
+ Object *obj = _get_obj().obj;
+ if (!obj) {
+ r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+#ifdef DEBUG_ENABLED
+ if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+
+#endif
+ ret = _get_obj().obj->call(p_method, p_args, p_argcount, r_error);
+
+ //else if (type==Variant::METHOD) {
+
+ } else {
+ r_error.error = Callable::CallError::CALL_OK;
+
+ Variant::InternalMethod **m = _VariantCall::type_internal_methods[type].lookup_ptr(p_method);
+
+ if (m) {
+ (*m)->call((Variant *)this, p_args, p_argcount, ret, r_error);
+ } else {
+ //ok fail because not found
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return;
+ }
+ }
+
+ if (r_error.error == Callable::CallError::CALL_OK && r_ret) {
+ *r_ret = ret;
+ }
+}
+
+#define VCALL(m_type, m_method) _VariantCall::_call_##m_type##_##m_method
+
+Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, int p_argcount, Callable::CallError &r_error, bool p_strict) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, Variant());
+
+ r_error.error = Callable::CallError::CALL_OK;
+ if (p_argcount == 0) { //generic construct
+
+ switch (p_type) {
+ case NIL:
+ return Variant();
+
+ // atomic types
+ case BOOL:
+ return Variant(false);
+ case INT:
+ return 0;
+ case FLOAT:
+ return 0.0f;
+ case STRING:
+ return String();
+
+ // math types
+ case VECTOR2:
+ return Vector2();
+ case VECTOR2I:
+ return Vector2i();
+ case RECT2:
+ return Rect2();
+ case RECT2I:
+ return Rect2i();
+ case VECTOR3:
+ return Vector3();
+ case VECTOR3I:
+ return Vector3i();
+ case TRANSFORM2D:
+ return Transform2D();
+ case PLANE:
+ return Plane();
+ case QUAT:
+ return Quat();
+ case AABB:
+ return ::AABB();
+ case BASIS:
+ return Basis();
+ case TRANSFORM:
+ return Transform();
+
+ // misc types
+ case COLOR:
+ return Color();
+ case STRING_NAME:
+ return StringName();
+ case NODE_PATH:
+ return NodePath();
+ case _RID:
+ return RID();
+ case OBJECT:
+ return (Object *)nullptr;
+ case CALLABLE:
+ return Callable();
+ case SIGNAL:
+ return Signal();
+ case DICTIONARY:
+ return Dictionary();
+ case ARRAY:
+ return Array();
+ case PACKED_BYTE_ARRAY:
+ return PackedByteArray();
+ case PACKED_INT32_ARRAY:
+ return PackedInt32Array();
+ case PACKED_INT64_ARRAY:
+ return PackedInt64Array();
+ case PACKED_FLOAT32_ARRAY:
+ return PackedFloat32Array();
+ case PACKED_FLOAT64_ARRAY:
+ return PackedFloat64Array();
+ case PACKED_STRING_ARRAY:
+ return PackedStringArray();
+ case PACKED_VECTOR2_ARRAY:
+ return PackedVector2Array();
+ case PACKED_VECTOR3_ARRAY:
+ return PackedVector3Array();
+ case PACKED_COLOR_ARRAY:
+ return PackedColorArray();
+ default:
+ return Variant();
+ }
+
+ } else if (p_argcount == 1 && p_args[0]->type == p_type) {
+ return *p_args[0]; //copy construct
+ } else if (p_argcount == 1 && (!p_strict || Variant::can_convert(p_args[0]->type, p_type))) {
+ //near match construct
+
+ switch (p_type) {
+ case NIL: {
+ return Variant();
+ } break;
+ case BOOL: {
+ return Variant(bool(*p_args[0]));
+ }
+ case INT: {
+ return (int64_t(*p_args[0]));
+ }
+ case FLOAT: {
+ return double(*p_args[0]);
+ }
+ case STRING: {
+ return String(*p_args[0]);
+ }
+ case VECTOR2: {
+ return Vector2(*p_args[0]);
+ }
+ case VECTOR2I: {
+ return Vector2i(*p_args[0]);
+ }
+ case RECT2:
+ return (Rect2(*p_args[0]));
+ case RECT2I:
+ return (Rect2i(*p_args[0]));
+ case VECTOR3:
+ return (Vector3(*p_args[0]));
+ case VECTOR3I:
+ return (Vector3i(*p_args[0]));
+ case TRANSFORM2D:
+ return (Transform2D(p_args[0]->operator Transform2D()));
+ case PLANE:
+ return (Plane(*p_args[0]));
+ case QUAT:
+ return (p_args[0]->operator Quat());
+ case AABB:
+ return (::AABB(*p_args[0]));
+ case BASIS:
+ return (Basis(p_args[0]->operator Basis()));
+ case TRANSFORM:
+ return (Transform(p_args[0]->operator Transform()));
+
+ // misc types
+ case COLOR:
+ return p_args[0]->type == Variant::STRING ? Color::html(*p_args[0]) : Color::hex(*p_args[0]);
+ case STRING_NAME:
+ return (StringName(p_args[0]->operator StringName()));
+ case NODE_PATH:
+ return (NodePath(p_args[0]->operator NodePath()));
+ case _RID:
+ return (RID(*p_args[0]));
+ case OBJECT:
+ return ((Object *)(p_args[0]->operator Object *()));
+ case CALLABLE:
+ return ((Callable)(p_args[0]->operator Callable()));
+ case SIGNAL:
+ return ((Signal)(p_args[0]->operator Signal()));
+ case DICTIONARY:
+ return p_args[0]->operator Dictionary();
+ case ARRAY:
+ return p_args[0]->operator Array();
+
+ // arrays
+ case PACKED_BYTE_ARRAY:
+ return (PackedByteArray(*p_args[0]));
+ case PACKED_INT32_ARRAY:
+ return (PackedInt32Array(*p_args[0]));
+ case PACKED_INT64_ARRAY:
+ return (PackedInt64Array(*p_args[0]));
+ case PACKED_FLOAT32_ARRAY:
+ return (PackedFloat32Array(*p_args[0]));
+ case PACKED_FLOAT64_ARRAY:
+ return (PackedFloat64Array(*p_args[0]));
+ case PACKED_STRING_ARRAY:
+ return (PackedStringArray(*p_args[0]));
+ case PACKED_VECTOR2_ARRAY:
+ return (PackedVector2Array(*p_args[0]));
+ case PACKED_VECTOR3_ARRAY:
+ return (PackedVector3Array(*p_args[0]));
+ case PACKED_COLOR_ARRAY:
+ return (PackedColorArray(*p_args[0]));
+ default:
+ return Variant();
+ }
+ } else if (p_argcount >= 1) {
+ _VariantCall::ConstructFunc &c = _VariantCall::construct_funcs[p_type];
+
+ for (List<_VariantCall::ConstructData>::Element *E = c.constructors.front(); E; E = E->next()) {
+ const _VariantCall::ConstructData &cd = E->get();
+
+ if (cd.arg_count != p_argcount) {
+ continue;
+ }
+
+ //validate parameters
+ for (int i = 0; i < cd.arg_count; i++) {
+ if (!Variant::can_convert(p_args[i]->type, cd.arg_types[i])) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; //no such constructor
+ r_error.argument = i;
+ r_error.expected = cd.arg_types[i];
+ return Variant();
+ }
+ }
+
+ Variant v;
+ cd.func(v, p_args);
+ return v;
+ }
+ }
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; //no such constructor
+ return Variant();
+}
+
+bool Variant::has_method(const StringName &p_method) const {
+ if (type == OBJECT) {
+ Object *obj = get_validated_object();
+ if (!obj) {
+ return false;
+ }
+
+ return obj->has_method(p_method);
+ }
+
+ return _VariantCall::type_internal_methods[type].has(p_method);
+}
+
+Vector<Variant::Type> Variant::get_method_argument_types(Variant::Type p_type, const StringName &p_method) {
+ Vector<Variant::Type> types;
+
+ Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method);
+ if (*m) {
+ types.resize((*m)->get_argument_count());
+ for (int i = 0; i < (*m)->get_argument_count(); i++) {
+ types.write[i] = (*m)->get_argument_type(i);
+ }
+ }
+
+ return types;
+}
+
+bool Variant::is_method_const(Variant::Type p_type, const StringName &p_method) {
+ Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method);
+ if (*m) {
+ return (*m)->get_flags() & Variant::InternalMethod::FLAG_IS_CONST;
+ }
+ return false;
+}
+
+Vector<StringName> Variant::get_method_argument_names(Variant::Type p_type, const StringName &p_method) {
+ Vector<StringName> argnames;
+
+#ifdef DEBUG_ENABLED
+ Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method);
+ if (*m) {
+ argnames.resize((*m)->get_argument_count());
+ for (int i = 0; i < (*m)->get_argument_count(); i++) {
+ argnames.write[i] = (*m)->get_argument_name(i);
+ }
+ }
+#endif
+ return argnames;
+}
+
+Variant::Type Variant::get_method_return_type(Variant::Type p_type, const StringName &p_method, bool *r_has_return) {
+ Variant::Type rt = Variant::NIL;
+ Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method);
+ if (*m) {
+ rt = (*m)->get_return_type();
+ if (r_has_return) {
+ *r_has_return = ((*m)->get_flags() & Variant::InternalMethod::FLAG_RETURNS_VARIANT) || rt != Variant::NIL;
+ }
+ }
+ return rt;
+}
+
+Vector<Variant> Variant::get_method_default_arguments(Variant::Type p_type, const StringName &p_method) {
+ Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method);
+ if (*m) {
+ return (*m)->get_default_arguments();
+ }
+ return Vector<Variant>();
+}
+
+void Variant::get_method_list(List<MethodInfo> *p_list) const {
+ for (List<StringName>::Element *E = _VariantCall::type_internal_method_names[type].front(); E; E = E->next()) {
+ Variant::InternalMethod **m = _VariantCall::type_internal_methods[type].lookup_ptr(E->get());
+ ERR_CONTINUE(!*m);
+
+ MethodInfo mi;
+ mi.name = E->get();
+ mi.return_val.type = (*m)->get_return_type();
+ if ((*m)->get_flags() & Variant::InternalMethod::FLAG_RETURNS_VARIANT) {
+ mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+ if ((*m)->get_flags() & Variant::InternalMethod::FLAG_IS_CONST) {
+ mi.flags |= METHOD_FLAG_CONST;
+ }
+ if ((*m)->get_flags() & Variant::InternalMethod::FLAG_VARARGS) {
+ mi.flags |= METHOD_FLAG_VARARG;
+ }
+
+ for (int i = 0; i < (*m)->get_argument_count(); i++) {
+ PropertyInfo arg;
+#ifdef DEBUG_ENABLED
+ arg.name = (*m)->get_argument_name(i);
+#else
+ arg.name = "arg" + itos(i + 1);
+#endif
+ arg.type = (*m)->get_argument_type(i);
+ mi.arguments.push_back(arg);
+ }
+
+ mi.default_arguments = (*m)->get_default_arguments();
+ p_list->push_back(mi);
+ }
+}
+
+void Variant::get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list) {
+ ERR_FAIL_INDEX(p_type, VARIANT_MAX);
+
+ //custom constructors
+ for (const List<_VariantCall::ConstructData>::Element *E = _VariantCall::construct_funcs[p_type].constructors.front(); E; E = E->next()) {
+ const _VariantCall::ConstructData &cd = E->get();
+ MethodInfo mi;
+ mi.name = Variant::get_type_name(p_type);
+ mi.return_val.type = p_type;
+ for (int i = 0; i < cd.arg_count; i++) {
+ PropertyInfo pi;
+ pi.name = cd.arg_names[i];
+ pi.type = cd.arg_types[i];
+ mi.arguments.push_back(pi);
+ }
+ p_list->push_back(mi);
+ }
+ //default constructors
+ for (int i = 0; i < VARIANT_MAX; i++) {
+ if (i == p_type) {
+ continue;
+ }
+ if (!Variant::can_convert(Variant::Type(i), p_type)) {
+ continue;
+ }
+
+ MethodInfo mi;
+ mi.name = Variant::get_type_name(p_type);
+ PropertyInfo pi;
+ pi.name = "from";
+ pi.type = Variant::Type(i);
+ mi.arguments.push_back(pi);
+ mi.return_val.type = p_type;
+ p_list->push_back(mi);
+ }
+}
+
+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];
+
+#ifdef DEBUG_ENABLED
+ for (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());
+#endif
+ }
+
+#ifdef DEBUG_ENABLED
+ for (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());
+#endif
+ }
+}
+
+bool Variant::has_constant(Variant::Type p_type, const StringName &p_value) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
+ return cd.value.has(p_value) || cd.variant_value.has(p_value);
+}
+
+Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid) {
+ if (r_valid) {
+ *r_valid = false;
+ }
+
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0);
+ _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
+
+ Map<StringName, int>::Element *E = cd.value.find(p_value);
+ if (!E) {
+ Map<StringName, Variant>::Element *F = cd.variant_value.find(p_value);
+ if (F) {
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return F->get();
+ } else {
+ return -1;
+ }
+ }
+ if (r_valid) {
+ *r_valid = true;
+ }
+
+ return E->get();
+}
+
+Variant::InternalMethod *Variant::get_internal_method(Type p_type, const StringName &p_method_name) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+
+ Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method_name);
+ if (*m) {
+ return *m;
+ }
+ return nullptr;
+}
+
+void register_variant_methods() {
+ _VariantCall::type_internal_methods = memnew_arr(_VariantCall::MethodMap, Variant::VARIANT_MAX);
+ _VariantCall::type_internal_method_names = memnew_arr(List<StringName>, Variant::VARIANT_MAX);
+ _VariantCall::construct_funcs = memnew_arr(_VariantCall::ConstructFunc, Variant::VARIANT_MAX);
+ _VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX);
+
+ /* String */
+
+ bind_method(String, casecmp_to, sarray("to"), varray());
+ bind_method(String, nocasecmp_to, sarray("to"), varray());
+ bind_method(String, naturalnocasecmp_to, sarray("to"), varray());
+ bind_method(String, length, sarray(), varray());
+ bind_method(String, substr, sarray("from", "len"), varray(-1));
+ bind_methodv(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));
+ bind_method(String, findn, sarray("what", "from"), varray(0));
+ bind_method(String, rfind, sarray("what", "from"), varray(-1));
+ bind_method(String, rfindn, sarray("what", "from"), varray(-1));
+ bind_method(String, match, sarray("expr"), varray());
+ bind_method(String, matchn, sarray("expr"), varray());
+ bind_methodv(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, bigrams, sarray(), varray());
+ bind_method(String, similarity, sarray("text"), varray());
+
+ bind_method(String, format, sarray("values", "placeholder"), varray("{_}"));
+ bind_methodv(replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray());
+ bind_method(String, replacen, sarray("what", "forwhat"), varray());
+ bind_method(String, repeat, sarray("count"), varray());
+ bind_method(String, insert, sarray("position", "what"), varray());
+ bind_method(String, capitalize, sarray(), varray());
+ bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
+ bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
+ bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true));
+ bind_method(String, join, sarray("parts"), varray());
+
+ bind_method(String, to_upper, sarray(), varray());
+ bind_method(String, to_lower, sarray(), varray());
+
+ bind_method(String, left, sarray("position"), varray());
+ bind_method(String, right, sarray("position"), varray());
+
+ bind_method(String, strip_edges, sarray("left", "right"), varray(true, true));
+ bind_method(String, strip_escapes, sarray(), varray());
+ bind_method(String, lstrip, sarray("chars"), varray());
+ bind_method(String, rstrip, sarray("chars"), varray());
+ bind_method(String, get_extension, sarray(), varray());
+ bind_method(String, get_basename, sarray(), varray());
+ bind_method(String, plus_file, sarray("file"), varray());
+ bind_method(String, ord_at, sarray("at"), 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());
+ bind_method(String, sha256_text, sarray(), varray());
+ bind_method(String, md5_buffer, sarray(), varray());
+ bind_method(String, sha1_buffer, sarray(), varray());
+ bind_method(String, sha256_buffer, sarray(), varray());
+ bind_method(String, empty, sarray(), varray());
+ // FIXME: Static function, not sure how to bind
+ //bind_method(String, humanize_size, sarray("size"), varray());
+
+ bind_method(String, is_abs_path, sarray(), varray());
+ bind_method(String, is_rel_path, sarray(), varray());
+ bind_method(String, get_base_dir, sarray(), varray());
+ bind_method(String, get_file, sarray(), varray());
+ bind_method(String, xml_escape, sarray("escape_quotes"), varray(false));
+ bind_method(String, xml_unescape, sarray(), varray());
+ bind_method(String, http_escape, sarray(), varray());
+ bind_method(String, http_unescape, sarray(), varray());
+ bind_method(String, c_escape, sarray(), varray());
+ bind_method(String, c_unescape, sarray(), varray());
+ bind_method(String, json_escape, sarray(), varray());
+ bind_method(String, percent_encode, sarray(), varray());
+ bind_method(String, percent_decode, sarray(), varray());
+
+ bind_method(String, is_valid_identifier, sarray(), varray());
+ bind_method(String, is_valid_integer, sarray(), varray());
+ bind_method(String, is_valid_float, sarray(), varray());
+ bind_method(String, is_valid_hex_number, sarray("with_prefix"), varray(false));
+ bind_method(String, is_valid_html_color, sarray(), varray());
+ bind_method(String, is_valid_ip_address, sarray(), varray());
+ bind_method(String, is_valid_filename, sarray(), varray());
+
+ bind_method(String, to_int, sarray(), varray());
+ bind_method(String, to_float, sarray(), varray());
+ bind_method(String, hex_to_int, sarray("with_prefix"), varray(true));
+ bind_method(String, bin_to_int, sarray("with_prefix"), varray(true));
+
+ bind_method(String, lpad, sarray("min_length", "character"), varray(" "));
+ bind_method(String, rpad, sarray("min_length", "character"), varray(" "));
+ bind_method(String, pad_decimals, sarray("digits"), varray());
+ bind_method(String, pad_zeros, sarray("digits"), varray());
+ bind_method(String, trim_prefix, sarray("prefix"), varray());
+ bind_method(String, trim_suffix, sarray("suffix"), varray());
+
+ bind_method(String, to_ascii_buffer, sarray(), varray());
+ bind_method(String, to_utf8_buffer, sarray(), varray());
+ bind_method(String, to_utf16_buffer, sarray(), varray());
+ bind_method(String, to_utf32_buffer, sarray(), varray());
+
+ /* Vector2 */
+
+ 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, distance_to, sarray("to"), varray());
+ bind_method(Vector2, distance_squared_to, sarray("to"), varray());
+ bind_method(Vector2, length, sarray(), varray());
+ bind_method(Vector2, length_squared, sarray(), varray());
+ bind_method(Vector2, normalized, sarray(), varray());
+ bind_method(Vector2, is_normalized, sarray(), varray());
+ bind_method(Vector2, is_equal_approx, sarray("to"), varray());
+ bind_method(Vector2, posmod, sarray("mod"), varray());
+ bind_method(Vector2, posmodv, sarray("modv"), varray());
+ bind_method(Vector2, project, sarray("b"), varray());
+ bind_method(Vector2, lerp, sarray("with", "t"), varray());
+ bind_method(Vector2, slerp, sarray("with", "t"), varray());
+ bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "t"), varray());
+ bind_method(Vector2, move_toward, sarray("to", "delta"), varray());
+ bind_method(Vector2, rotated, sarray("phi"), varray());
+ bind_method(Vector2, tangent, sarray(), varray());
+ bind_method(Vector2, floor, sarray(), varray());
+ bind_method(Vector2, ceil, sarray(), varray());
+ bind_method(Vector2, round, sarray(), varray());
+ bind_method(Vector2, aspect, sarray(), varray());
+ bind_method(Vector2, dot, sarray("with"), varray());
+ bind_method(Vector2, slide, sarray("n"), varray());
+ bind_method(Vector2, bounce, sarray("n"), varray());
+ bind_method(Vector2, reflect, sarray("n"), varray());
+ bind_method(Vector2, cross, sarray("with"), varray());
+ bind_method(Vector2, abs, sarray(), varray());
+ bind_method(Vector2, sign, sarray(), varray());
+ bind_method(Vector2, snapped, sarray("by"), varray());
+ bind_method(Vector2, clamped, sarray("length"), varray());
+
+ /* Vector2i */
+
+ bind_method(Vector2i, aspect, sarray(), varray());
+ bind_method(Vector2i, sign, sarray(), varray());
+ bind_method(Vector2i, abs, sarray(), varray());
+
+ /* Rect2 */
+
+ bind_method(Rect2, get_area, sarray(), varray());
+ bind_method(Rect2, has_no_area, sarray(), varray());
+ bind_method(Rect2, has_point, sarray("point"), varray());
+ bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
+ bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
+ bind_method(Rect2, encloses, sarray("b"), varray());
+ bind_method(Rect2, clip, sarray("b"), varray());
+ bind_method(Rect2, merge, sarray("b"), varray());
+ bind_method(Rect2, expand, sarray("to"), varray());
+ bind_method(Rect2, grow, sarray("by"), varray());
+ bind_methodv(grow_margin, &Rect2::grow_margin_bind, sarray("margin", "by"), varray());
+ bind_method(Rect2, grow_individual, sarray("left", "top", "right", "bottom"), varray());
+ bind_method(Rect2, abs, sarray(), varray());
+
+ /* Rect2i */
+
+ bind_method(Rect2i, get_area, sarray(), varray());
+ bind_method(Rect2i, has_no_area, sarray(), varray());
+ bind_method(Rect2i, has_point, sarray("point"), varray());
+ bind_method(Rect2i, intersects, sarray("b"), varray());
+ bind_method(Rect2i, encloses, sarray("b"), varray());
+ bind_method(Rect2i, clip, sarray("b"), varray());
+ bind_method(Rect2i, merge, sarray("b"), varray());
+ bind_method(Rect2i, expand, sarray("to"), varray());
+ bind_method(Rect2i, grow, sarray("by"), varray());
+ bind_methodv(grow_margin, &Rect2i::grow_margin_bind, sarray("margin", "by"), varray());
+ bind_method(Rect2i, grow_individual, sarray("left", "top", "right", "bottom"), varray());
+ bind_method(Rect2i, abs, sarray(), varray());
+
+ /* Vector3 */
+
+ bind_method(Vector3, min_axis, sarray(), varray());
+ bind_method(Vector3, max_axis, sarray(), varray());
+ bind_method(Vector3, angle_to, sarray("to"), 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, length, sarray(), varray());
+ bind_method(Vector3, length_squared, sarray(), varray());
+ bind_method(Vector3, normalized, sarray(), varray());
+ bind_method(Vector3, is_normalized, sarray(), varray());
+ bind_method(Vector3, is_equal_approx, sarray("to"), varray());
+ bind_method(Vector3, inverse, sarray(), varray());
+ bind_method(Vector3, snapped, sarray("by"), varray());
+ bind_method(Vector3, rotated, sarray("by_axis", "phi"), varray());
+ bind_method(Vector3, lerp, sarray("b", "t"), varray());
+ bind_method(Vector3, slerp, sarray("b", "t"), varray());
+ bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "t"), varray());
+ bind_method(Vector3, move_toward, sarray("to", "delta"), varray());
+ bind_method(Vector3, dot, sarray("with"), varray());
+ bind_method(Vector3, cross, sarray("with"), varray());
+ bind_method(Vector3, outer, sarray("with"), varray());
+ bind_method(Vector3, to_diagonal_matrix, sarray(), varray());
+ bind_method(Vector3, abs, sarray(), varray());
+ bind_method(Vector3, floor, sarray(), varray());
+ bind_method(Vector3, ceil, sarray(), varray());
+ bind_method(Vector3, round, sarray(), varray());
+ bind_method(Vector3, posmod, sarray("mod"), varray());
+ bind_method(Vector3, posmodv, sarray("modv"), varray());
+ bind_method(Vector3, project, sarray("b"), varray());
+ bind_method(Vector3, slide, sarray("n"), varray());
+ bind_method(Vector3, bounce, sarray("n"), varray());
+ bind_method(Vector3, reflect, sarray("n"), varray());
+ bind_method(Vector3, sign, sarray(), varray());
+
+ /* Vector3i */
+
+ bind_method(Vector3i, min_axis, sarray(), varray());
+ bind_method(Vector3i, max_axis, sarray(), varray());
+ bind_method(Vector3i, sign, sarray(), varray());
+ bind_method(Vector3i, abs, sarray(), varray());
+
+ /* Plane */
+
+ bind_method(Plane, normalized, sarray(), varray());
+ bind_method(Plane, center, sarray(), varray());
+ bind_method(Plane, is_equal_approx, sarray("to_plane"), varray());
+ bind_method(Plane, is_point_over, sarray("plane"), varray());
+ bind_method(Plane, distance_to, sarray("point"), varray());
+ bind_method(Plane, has_point, sarray("point", "epsilon"), varray(CMP_EPSILON));
+ bind_method(Plane, project, sarray("point"), varray());
+ bind_methodv(intersect_3, &Plane::intersect_3_bind, sarray("b", "c"), varray());
+ bind_methodv(intersects_ray, &Plane::intersects_ray_bind, sarray("from", "dir"), varray());
+ bind_methodv(intersects_segment, &Plane::intersects_segment_bind, sarray("from", "to"), varray());
+
+ /* Quat */
+
+ bind_method(Quat, length, sarray(), varray());
+ bind_method(Quat, length_squared, sarray(), varray());
+ bind_method(Quat, normalized, sarray(), varray());
+ bind_method(Quat, is_normalized, sarray(), varray());
+ bind_method(Quat, is_equal_approx, sarray("to"), varray());
+ bind_method(Quat, inverse, sarray(), varray());
+ bind_method(Quat, dot, sarray("with"), varray());
+ bind_method(Quat, slerp, sarray("b", "t"), varray());
+ bind_method(Quat, slerpni, sarray("b", "t"), varray());
+ bind_method(Quat, cubic_slerp, sarray("b", "pre_a", "post_b", "t"), varray());
+ bind_method(Quat, get_euler, sarray(), varray());
+
+ // FIXME: Quat is atomic, this should be done via construcror
+ //ADDFUNC1(QUAT, NIL, Quat, set_euler, VECTOR3, "euler", varray());
+ //ADDFUNC2(QUAT, NIL, Quat, set_axis_angle, VECTOR3, "axis", FLOAT, "angle", varray());
+
+ /* Color */
+
+ bind_method(Color, to_argb32, sarray(), varray());
+ bind_method(Color, to_abgr32, sarray(), varray());
+ bind_method(Color, to_rgba32, sarray(), varray());
+ bind_method(Color, to_argb64, sarray(), varray());
+ bind_method(Color, to_abgr64, sarray(), varray());
+ bind_method(Color, to_rgba64, sarray(), varray());
+
+ bind_method(Color, inverted, sarray(), varray());
+ bind_method(Color, lerp, sarray("b", "t"), 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());
+
+ // 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());
+
+ /* RID */
+
+ bind_method(RID, get_id, sarray(), varray());
+
+ /* NodePath */
+
+ bind_method(NodePath, is_absolute, sarray(), varray());
+ bind_method(NodePath, get_name_count, sarray(), varray());
+ bind_method(NodePath, get_name, sarray("idx"), varray());
+ bind_method(NodePath, get_subname_count, sarray(), varray());
+ bind_method(NodePath, get_subname, sarray("idx"), varray());
+ bind_method(NodePath, get_concatenated_subnames, sarray(), varray());
+ bind_method(NodePath, get_as_property_path, sarray(), varray());
+ bind_method(NodePath, is_empty, sarray(), varray());
+
+ /* Callable */
+
+ bind_method(Callable, is_null, sarray(), varray());
+ bind_method(Callable, is_custom, sarray(), varray());
+ bind_method(Callable, is_standard, sarray(), varray());
+ bind_method(Callable, get_object, sarray(), varray());
+ bind_method(Callable, get_object_id, sarray(), varray());
+ bind_method(Callable, get_method, sarray(), varray());
+ bind_method(Callable, hash, sarray(), varray());
+ bind_method(Callable, unbind, sarray("argcount"), varray());
+
+ bind_custom(Variant::CALLABLE, "call", _VariantCall::func_Callable_call, Variant::InternalMethod::FLAG_VARARGS | Variant::InternalMethod::FLAG_RETURNS_VARIANT, Vector<Variant::Type>(), Variant::NIL, sarray());
+ bind_custom(Variant::CALLABLE, "call_deferred", _VariantCall::func_Callable_call_deferred, Variant::InternalMethod::FLAG_VARARGS, Vector<Variant::Type>(), Variant::NIL, sarray());
+ bind_custom(Variant::CALLABLE, "bind", _VariantCall::func_Callable_bind, Variant::InternalMethod::FLAG_VARARGS, Vector<Variant::Type>(), Variant::CALLABLE, sarray());
+
+ /* Signal */
+
+ bind_method(Signal, is_null, sarray(), varray());
+ bind_method(Signal, get_object, sarray(), varray());
+ 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, disconnect, sarray("callable"), varray());
+ bind_method(Signal, is_connected, sarray("callable"), varray());
+ bind_method(Signal, get_connections, sarray(), varray());
+
+ bind_custom(Variant::SIGNAL, "emit", _VariantCall::func_Signal_emit, Variant::InternalMethod::FLAG_VARARGS, Vector<Variant::Type>(), Variant::NIL, sarray());
+
+ /* Transform2D */
+
+ bind_method(Transform2D, inverse, sarray(), varray());
+ bind_method(Transform2D, affine_inverse, sarray(), varray());
+ bind_method(Transform2D, get_rotation, sarray(), varray());
+ bind_method(Transform2D, get_origin, sarray(), varray());
+ bind_method(Transform2D, get_scale, sarray(), varray());
+ bind_method(Transform2D, orthonormalized, sarray(), varray());
+ bind_method(Transform2D, rotated, sarray("phi"), varray());
+ bind_method(Transform2D, scaled, sarray("scale"), varray());
+ bind_method(Transform2D, translated, sarray("offset"), varray());
+ bind_method(Transform2D, basis_xform, sarray("v"), varray());
+ bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
+ bind_method(Transform2D, interpolate_with, sarray("xform", "t"), varray());
+ bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
+
+ /* Basis */
+
+ bind_method(Basis, inverse, sarray(), varray());
+ bind_method(Basis, transposed, sarray(), varray());
+ bind_method(Basis, orthonormalized, sarray(), varray());
+ bind_method(Basis, determinant, sarray(), varray());
+ bind_methodv(rotated, static_cast<Basis (Basis::*)(const Vector3 &, float) 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, tdotx, sarray("with"), varray());
+ bind_method(Basis, tdoty, sarray("with"), varray());
+ bind_method(Basis, tdotz, sarray("with"), varray());
+ bind_method(Basis, get_orthogonal_index, sarray(), varray());
+ bind_method(Basis, slerp, sarray("b", "t"), varray());
+ bind_method(Basis, is_equal_approx, sarray("b"), varray());
+ bind_method(Basis, get_rotation_quat, sarray(), varray());
+
+ /* 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, has_no_surface, sarray(), varray());
+ bind_method(::AABB, has_point, sarray("point"), varray());
+ bind_method(::AABB, is_equal_approx, sarray("aabb"), varray());
+ bind_method(::AABB, intersects, sarray("with"), varray());
+ bind_method(::AABB, encloses, sarray("with"), varray());
+ bind_method(::AABB, intersects_plane, sarray("plane"), varray());
+ bind_method(::AABB, intersection, sarray("with"), varray());
+ bind_method(::AABB, merge, sarray("with"), varray());
+ bind_method(::AABB, expand, sarray("to_point"), varray());
+ bind_method(::AABB, grow, sarray("by"), varray());
+ bind_method(::AABB, get_support, sarray("dir"), varray());
+ bind_method(::AABB, get_longest_axis, sarray(), varray());
+ bind_method(::AABB, get_longest_axis_index, sarray(), varray());
+ bind_method(::AABB, get_longest_axis_size, sarray(), varray());
+ bind_method(::AABB, get_shortest_axis, sarray(), varray());
+ bind_method(::AABB, get_shortest_axis_index, sarray(), varray());
+ bind_method(::AABB, get_shortest_axis_size, sarray(), varray());
+ bind_method(::AABB, get_endpoint, sarray("idx"), varray());
+ bind_methodv(intersects_segment, &AABB::intersects_segment_bind, sarray("from", "to"), varray());
+ bind_methodv(intersects_ray, &AABB::intersects_ray_bind, sarray("from", "dir"), varray());
+
+ /* Transform */
+
+ bind_method(Transform, inverse, sarray(), varray());
+ bind_method(Transform, affine_inverse, sarray(), varray());
+ bind_method(Transform, orthonormalized, sarray(), varray());
+ bind_method(Transform, rotated, sarray("axis", "phi"), varray());
+ bind_method(Transform, scaled, sarray("scale"), varray());
+ bind_method(Transform, translated, sarray("offset"), varray());
+ bind_method(Transform, looking_at, sarray("target", "up"), varray());
+ bind_method(Transform, interpolate_with, sarray("xform", "weight"), varray());
+ bind_method(Transform, is_equal_approx, sarray("xform"), varray());
+
+ /* Dictionary */
+
+ bind_method(Dictionary, size, sarray(), varray());
+ bind_method(Dictionary, empty, sarray(), varray());
+ bind_method(Dictionary, clear, sarray(), varray());
+ bind_method(Dictionary, has, sarray("key"), varray());
+ bind_method(Dictionary, has_all, sarray("keys"), varray());
+ bind_method(Dictionary, erase, sarray("key"), varray());
+ bind_method(Dictionary, hash, sarray(), varray());
+ bind_method(Dictionary, keys, sarray(), varray());
+ bind_method(Dictionary, values, sarray(), varray());
+ bind_method(Dictionary, duplicate, sarray("deep"), varray(false));
+ bind_method(Dictionary, get, sarray("key", "default"), varray(Variant()));
+
+ /* Array */
+
+ bind_method(Array, size, sarray(), varray());
+ bind_method(Array, empty, sarray(), varray());
+ bind_method(Array, clear, sarray(), varray());
+ bind_method(Array, hash, sarray(), varray());
+ bind_method(Array, push_back, sarray("value"), varray());
+ bind_method(Array, push_front, sarray("value"), varray());
+ bind_method(Array, append, sarray("value"), 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, erase, sarray("value"), varray());
+ bind_method(Array, front, sarray(), varray());
+ bind_method(Array, back, sarray(), varray());
+ bind_method(Array, find, sarray("what", "from"), varray(0));
+ bind_method(Array, rfind, sarray("what", "from"), varray(-1));
+ bind_method(Array, find_last, sarray("value"), varray());
+ bind_method(Array, count, sarray("value"), varray());
+ bind_method(Array, has, sarray("value"), varray());
+ bind_method(Array, pop_back, sarray(), varray());
+ bind_method(Array, pop_front, sarray(), varray());
+ bind_method(Array, sort, sarray(), varray());
+ bind_method(Array, sort_custom, sarray("obj", "func"), varray());
+ bind_method(Array, shuffle, sarray(), varray());
+ bind_method(Array, bsearch, sarray("value", "before"), varray(true));
+ bind_method(Array, bsearch_custom, sarray("value", "obj", "func", "before"), varray(true));
+ bind_method(Array, invert, 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, max, sarray(), varray());
+ bind_method(Array, min, sarray(), varray());
+
+ /* Byte Array */
+ bind_method(PackedByteArray, size, sarray(), varray());
+ bind_method(PackedByteArray, empty, sarray(), varray());
+ bind_method(PackedByteArray, set, sarray("index", "value"), varray());
+ 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, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedByteArray, resize, sarray("new_size"), varray());
+ bind_method(PackedByteArray, has, sarray("value"), varray());
+ bind_method(PackedByteArray, invert, sarray(), varray());
+ bind_method(PackedByteArray, subarray, sarray("from", "to"), varray());
+ bind_method(PackedByteArray, sort, sarray(), varray());
+
+ bind_function("get_string_from_ascii", _VariantCall::func_PackedByteArray_get_string_from_ascii, sarray(), varray());
+ bind_function("get_string_from_utf8", _VariantCall::func_PackedByteArray_get_string_from_utf8, sarray(), varray());
+ bind_function("get_string_from_utf16", _VariantCall::func_PackedByteArray_get_string_from_utf16, sarray(), varray());
+ bind_function("get_string_from_utf32", _VariantCall::func_PackedByteArray_get_string_from_utf32, sarray(), varray());
+ bind_function("hex_encode", _VariantCall::func_PackedByteArray_hex_encode, sarray(), varray());
+ bind_function("compress", _VariantCall::func_PackedByteArray_compress, sarray("compression_mode"), varray(0));
+ bind_function("decompress", _VariantCall::func_PackedByteArray_decompress, sarray("buffer_size", "compression_mode"), varray(0));
+ bind_function("decompress_dynamic", _VariantCall::func_PackedByteArray_decompress_dynamic, sarray("max_output_size", "compression_mode"), varray(0));
+
+ /* Int32 Array */
+
+ bind_method(PackedInt32Array, size, sarray(), varray());
+ bind_method(PackedInt32Array, empty, sarray(), varray());
+ bind_method(PackedInt32Array, set, sarray("index", "value"), varray());
+ 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, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedInt32Array, resize, sarray("new_size"), varray());
+ bind_method(PackedInt32Array, has, sarray("value"), varray());
+ bind_method(PackedInt32Array, invert, sarray(), varray());
+ bind_method(PackedInt32Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedInt32Array, to_byte_array, sarray(), varray());
+ bind_method(PackedInt32Array, sort, sarray(), varray());
+
+ /* Int64 Array */
+
+ bind_method(PackedInt64Array, size, sarray(), varray());
+ bind_method(PackedInt64Array, empty, sarray(), varray());
+ bind_method(PackedInt64Array, set, sarray("index", "value"), varray());
+ 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, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedInt64Array, resize, sarray("new_size"), varray());
+ bind_method(PackedInt64Array, has, sarray("value"), varray());
+ bind_method(PackedInt64Array, invert, sarray(), varray());
+ bind_method(PackedInt64Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedInt64Array, to_byte_array, sarray(), varray());
+ bind_method(PackedInt64Array, sort, sarray(), varray());
+
+ /* Float32 Array */
+
+ bind_method(PackedFloat32Array, size, sarray(), varray());
+ bind_method(PackedFloat32Array, empty, sarray(), varray());
+ bind_method(PackedFloat32Array, set, sarray("index", "value"), varray());
+ 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, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedFloat32Array, resize, sarray("new_size"), varray());
+ bind_method(PackedFloat32Array, has, sarray("value"), varray());
+ bind_method(PackedFloat32Array, invert, sarray(), varray());
+ bind_method(PackedFloat32Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedFloat32Array, to_byte_array, sarray(), varray());
+ bind_method(PackedFloat32Array, sort, sarray(), varray());
+
+ /* Float64 Array */
+
+ bind_method(PackedFloat64Array, size, sarray(), varray());
+ bind_method(PackedFloat64Array, empty, sarray(), varray());
+ bind_method(PackedFloat64Array, set, sarray("index", "value"), varray());
+ 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, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedFloat64Array, resize, sarray("new_size"), varray());
+ bind_method(PackedFloat64Array, has, sarray("value"), varray());
+ bind_method(PackedFloat64Array, invert, sarray(), varray());
+ bind_method(PackedFloat64Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedFloat64Array, to_byte_array, sarray(), varray());
+ bind_method(PackedFloat64Array, sort, sarray(), varray());
+
+ /* String Array */
+
+ bind_method(PackedStringArray, size, sarray(), varray());
+ bind_method(PackedStringArray, empty, sarray(), varray());
+ bind_method(PackedStringArray, set, sarray("index", "value"), varray());
+ 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, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedStringArray, resize, sarray("new_size"), varray());
+ bind_method(PackedStringArray, has, sarray("value"), varray());
+ bind_method(PackedStringArray, invert, sarray(), varray());
+ bind_method(PackedStringArray, subarray, sarray("from", "to"), varray());
+ bind_method(PackedStringArray, to_byte_array, sarray(), varray());
+ bind_method(PackedStringArray, sort, sarray(), varray());
+
+ /* Vector2 Array */
+
+ bind_method(PackedVector2Array, size, sarray(), varray());
+ bind_method(PackedVector2Array, empty, sarray(), varray());
+ bind_method(PackedVector2Array, set, sarray("index", "value"), varray());
+ 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, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedVector2Array, resize, sarray("new_size"), varray());
+ bind_method(PackedVector2Array, has, sarray("value"), varray());
+ bind_method(PackedVector2Array, invert, sarray(), varray());
+ bind_method(PackedVector2Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedVector2Array, to_byte_array, sarray(), varray());
+ bind_method(PackedVector2Array, sort, sarray(), varray());
+
+ /* Vector3 Array */
+
+ bind_method(PackedVector3Array, size, sarray(), varray());
+ bind_method(PackedVector3Array, empty, sarray(), varray());
+ bind_method(PackedVector3Array, set, sarray("index", "value"), varray());
+ 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, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedVector3Array, resize, sarray("new_size"), varray());
+ bind_method(PackedVector3Array, has, sarray("value"), varray());
+ bind_method(PackedVector3Array, invert, sarray(), varray());
+ bind_method(PackedVector3Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedVector3Array, to_byte_array, sarray(), varray());
+ bind_method(PackedVector3Array, sort, sarray(), varray());
+
+ /* Color Array */
+
+ bind_method(PackedColorArray, size, sarray(), varray());
+ bind_method(PackedColorArray, empty, sarray(), varray());
+ bind_method(PackedColorArray, set, sarray("index", "value"), varray());
+ 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, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedColorArray, resize, sarray("new_size"), varray());
+ bind_method(PackedColorArray, has, sarray("value"), varray());
+ bind_method(PackedColorArray, invert, sarray(), varray());
+ bind_method(PackedColorArray, subarray, sarray("from", "to"), varray());
+ bind_method(PackedColorArray, to_byte_array, sarray(), varray());
+ bind_method(PackedColorArray, sort, sarray(), varray());
+
+ /* Register constructors */
+
+ _VariantCall::add_constructor(_VariantCall::Vector2_init1, Variant::VECTOR2, "x", Variant::FLOAT, "y", Variant::FLOAT);
+ _VariantCall::add_constructor(_VariantCall::Vector2i_init1, Variant::VECTOR2I, "x", Variant::INT, "y", Variant::INT);
+
+ _VariantCall::add_constructor(_VariantCall::Rect2_init1, Variant::RECT2, "position", Variant::VECTOR2, "size", Variant::VECTOR2);
+ _VariantCall::add_constructor(_VariantCall::Rect2_init2, Variant::RECT2, "x", Variant::FLOAT, "y", Variant::FLOAT, "width", Variant::FLOAT, "height", Variant::FLOAT);
+
+ _VariantCall::add_constructor(_VariantCall::Rect2i_init1, Variant::RECT2I, "position", Variant::VECTOR2I, "size", Variant::VECTOR2I);
+ _VariantCall::add_constructor(_VariantCall::Rect2i_init2, Variant::RECT2I, "x", Variant::INT, "y", Variant::INT, "width", Variant::INT, "height", Variant::INT);
+
+ _VariantCall::add_constructor(_VariantCall::Transform2D_init2, Variant::TRANSFORM2D, "rotation", Variant::FLOAT, "position", Variant::VECTOR2);
+ _VariantCall::add_constructor(_VariantCall::Transform2D_init3, Variant::TRANSFORM2D, "x_axis", Variant::VECTOR2, "y_axis", Variant::VECTOR2, "origin", Variant::VECTOR2);
+
+ _VariantCall::add_constructor(_VariantCall::Vector3_init1, Variant::VECTOR3, "x", Variant::FLOAT, "y", Variant::FLOAT, "z", Variant::FLOAT);
+ _VariantCall::add_constructor(_VariantCall::Vector3i_init1, Variant::VECTOR3I, "x", Variant::INT, "y", Variant::INT, "z", Variant::INT);
+
+ _VariantCall::add_constructor(_VariantCall::Plane_init1, Variant::PLANE, "a", Variant::FLOAT, "b", Variant::FLOAT, "c", Variant::FLOAT, "d", Variant::FLOAT);
+ _VariantCall::add_constructor(_VariantCall::Plane_init2, Variant::PLANE, "v1", Variant::VECTOR3, "v2", Variant::VECTOR3, "v3", Variant::VECTOR3);
+ _VariantCall::add_constructor(_VariantCall::Plane_init3, Variant::PLANE, "normal", Variant::VECTOR3, "d", Variant::FLOAT);
+
+ _VariantCall::add_constructor(_VariantCall::Quat_init1, Variant::QUAT, "x", Variant::FLOAT, "y", Variant::FLOAT, "z", Variant::FLOAT, "w", Variant::FLOAT);
+ _VariantCall::add_constructor(_VariantCall::Quat_init2, Variant::QUAT, "axis", Variant::VECTOR3, "angle", Variant::FLOAT);
+ _VariantCall::add_constructor(_VariantCall::Quat_init3, Variant::QUAT, "euler", Variant::VECTOR3);
+
+ _VariantCall::add_constructor(_VariantCall::Color_init1, Variant::COLOR, "r", Variant::FLOAT, "g", Variant::FLOAT, "b", Variant::FLOAT, "a", Variant::FLOAT);
+ _VariantCall::add_constructor(_VariantCall::Color_init2, Variant::COLOR, "r", Variant::FLOAT, "g", Variant::FLOAT, "b", Variant::FLOAT);
+ // init3 and init4 are the constructors for HTML hex strings and integers respectively which don't need binding here, so we skip to init5.
+ _VariantCall::add_constructor(_VariantCall::Color_init5, Variant::COLOR, "c", Variant::COLOR, "a", Variant::FLOAT);
+
+ _VariantCall::add_constructor(_VariantCall::AABB_init1, Variant::AABB, "position", Variant::VECTOR3, "size", Variant::VECTOR3);
+
+ _VariantCall::add_constructor(_VariantCall::Basis_init1, Variant::BASIS, "x_axis", Variant::VECTOR3, "y_axis", Variant::VECTOR3, "z_axis", Variant::VECTOR3);
+ _VariantCall::add_constructor(_VariantCall::Basis_init2, Variant::BASIS, "axis", Variant::VECTOR3, "phi", Variant::FLOAT);
+
+ _VariantCall::add_constructor(_VariantCall::Transform_init1, Variant::TRANSFORM, "x_axis", Variant::VECTOR3, "y_axis", Variant::VECTOR3, "z_axis", Variant::VECTOR3, "origin", Variant::VECTOR3);
+ _VariantCall::add_constructor(_VariantCall::Transform_init2, Variant::TRANSFORM, "basis", Variant::BASIS, "origin", Variant::VECTOR3);
+
+ _VariantCall::add_constructor(_VariantCall::Callable_init2, Variant::CALLABLE, "object", Variant::OBJECT, "method_name", Variant::STRING_NAME);
+ _VariantCall::add_constructor(_VariantCall::Signal_init2, Variant::SIGNAL, "object", Variant::OBJECT, "signal_name", Variant::STRING_NAME);
+
+ /* Register constants */
+
+ int ncc = Color::get_named_color_count();
+ for (int i = 0; i < ncc; i++) {
+ _VariantCall::add_variant_constant(Variant::COLOR, Color::get_named_color_name(i), Color::get_named_color(i));
+ }
+
+ _VariantCall::add_constant(Variant::VECTOR3, "AXIS_X", Vector3::AXIS_X);
+ _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Y", Vector3::AXIS_Y);
+ _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z);
+
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "ZERO", Vector3(0, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "ONE", Vector3(1, 1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "INF", Vector3(Math_INF, Math_INF, Math_INF));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "LEFT", Vector3(-1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "RIGHT", Vector3(1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "UP", Vector3(0, 1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "DOWN", Vector3(0, -1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1));
+
+ _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3i::AXIS_X);
+ _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3i::AXIS_Y);
+ _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3i::AXIS_Z);
+
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "ZERO", Vector3i(0, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "ONE", Vector3i(1, 1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "LEFT", Vector3i(-1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "RIGHT", Vector3i(1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "UP", Vector3i(0, 1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "DOWN", Vector3i(0, -1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "FORWARD", Vector3i(0, 0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "BACK", Vector3i(0, 0, 1));
+
+ _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X);
+ _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y);
+
+ _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2i::AXIS_X);
+ _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2i::AXIS_Y);
+
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(Math_INF, Math_INF));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "LEFT", Vector2(-1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "RIGHT", Vector2(1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "UP", Vector2(0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "DOWN", Vector2(0, 1));
+
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "ZERO", Vector2i(0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "ONE", Vector2i(1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "LEFT", Vector2i(-1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "RIGHT", Vector2i(1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "DOWN", Vector2i(0, 1));
+
+ _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D());
+ _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0));
+
+ Transform identity_transform = Transform();
+ Transform flip_x_transform = Transform(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
+ Transform flip_y_transform = Transform(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
+ Transform flip_z_transform = Transform(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", flip_x_transform);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", flip_y_transform);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", flip_z_transform);
+
+ Basis identity_basis = Basis();
+ Basis flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1);
+ Basis flip_y_basis = Basis(1, 0, 0, 0, -1, 0, 0, 0, 1);
+ Basis flip_z_basis = Basis(1, 0, 0, 0, 1, 0, 0, 0, -1);
+ _VariantCall::add_variant_constant(Variant::BASIS, "IDENTITY", identity_basis);
+ _VariantCall::add_variant_constant(Variant::BASIS, "FLIP_X", flip_x_basis);
+ _VariantCall::add_variant_constant(Variant::BASIS, "FLIP_Y", flip_y_basis);
+ _VariantCall::add_variant_constant(Variant::BASIS, "FLIP_Z", flip_z_basis);
+
+ _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_YZ", Plane(Vector3(1, 0, 0), 0));
+ _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XZ", Plane(Vector3(0, 1, 0), 0));
+ _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XY", Plane(Vector3(0, 0, 1), 0));
+
+ _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1));
+}
+
+void unregister_variant_methods() {
+ //clear methods
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ for (List<StringName>::Element *E = _VariantCall::type_internal_method_names[i].front(); E; E = E->next()) {
+ Variant::InternalMethod **m = _VariantCall::type_internal_methods[i].lookup_ptr(E->get());
+ if (*m) {
+ memdelete(*m);
+ }
+ }
+ }
+
+ memdelete_arr(_VariantCall::type_internal_methods);
+ memdelete_arr(_VariantCall::type_internal_method_names);
+ memdelete_arr(_VariantCall::construct_funcs);
+ memdelete_arr(_VariantCall::constant_data);
+}
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
new file mode 100644
index 0000000000..7893c6d382
--- /dev/null
+++ b/core/variant/variant_internal.h
@@ -0,0 +1,652 @@
+/*************************************************************************/
+/* variant_internal.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef VARIANT_INTERNAL_H
+#define VARIANT_INTERNAL_H
+
+#include "variant.h"
+
+// For use when you want to access the internal pointer of a Variant directly.
+// Use with caution. You need to be sure that the type is correct.
+class VariantInternal {
+public:
+ // Set type.
+ _FORCE_INLINE_ static void initialize(Variant *v, Variant::Type p_type) { v->type = p_type; }
+
+ // 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; }
+ _FORCE_INLINE_ static int64_t *get_int(Variant *v) { return &v->_data._int; }
+ _FORCE_INLINE_ static const int64_t *get_int(const Variant *v) { return &v->_data._int; }
+ _FORCE_INLINE_ static double *get_float(Variant *v) { return &v->_data._float; }
+ _FORCE_INLINE_ static const double *get_float(const Variant *v) { return &v->_data._float; }
+ _FORCE_INLINE_ static String *get_string(Variant *v) { return reinterpret_cast<String *>(v->_data._mem); }
+ _FORCE_INLINE_ static const String *get_string(const Variant *v) { return reinterpret_cast<const String *>(v->_data._mem); }
+
+ // Math types.
+ _FORCE_INLINE_ static Vector2 *get_vector2(Variant *v) { return reinterpret_cast<Vector2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector2 *get_vector2(const Variant *v) { return reinterpret_cast<const Vector2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static Vector2i *get_vector2i(Variant *v) { return reinterpret_cast<Vector2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector2i *get_vector2i(const Variant *v) { return reinterpret_cast<const Vector2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static Rect2 *get_rect2(Variant *v) { return reinterpret_cast<Rect2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Rect2 *get_rect2(const Variant *v) { return reinterpret_cast<const Rect2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static Rect2i *get_rect2i(Variant *v) { return reinterpret_cast<Rect2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Rect2i *get_rect2i(const Variant *v) { return reinterpret_cast<const Rect2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static Vector3 *get_vector3(Variant *v) { return reinterpret_cast<Vector3 *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector3 *get_vector3(const Variant *v) { return reinterpret_cast<const Vector3 *>(v->_data._mem); }
+ _FORCE_INLINE_ static Vector3i *get_vector3i(Variant *v) { return reinterpret_cast<Vector3i *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector3i *get_vector3i(const Variant *v) { return reinterpret_cast<const Vector3i *>(v->_data._mem); }
+ _FORCE_INLINE_ static Transform2D *get_transform2d(Variant *v) { return v->_data._transform2d; }
+ _FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return v->_data._transform2d; }
+ _FORCE_INLINE_ static Plane *get_plane(Variant *v) { return reinterpret_cast<Plane *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return reinterpret_cast<const Plane *>(v->_data._mem); }
+ _FORCE_INLINE_ static Quat *get_quat(Variant *v) { return reinterpret_cast<Quat *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Quat *get_quat(const Variant *v) { return reinterpret_cast<const Quat *>(v->_data._mem); }
+ _FORCE_INLINE_ static ::AABB *get_aabb(Variant *v) { return v->_data._aabb; }
+ _FORCE_INLINE_ static const ::AABB *get_aabb(const Variant *v) { return v->_data._aabb; }
+ _FORCE_INLINE_ static Basis *get_basis(Variant *v) { return v->_data._basis; }
+ _FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return v->_data._basis; }
+ _FORCE_INLINE_ static Transform *get_transform(Variant *v) { return v->_data._transform; }
+ _FORCE_INLINE_ static const Transform *get_transform(const Variant *v) { return v->_data._transform; }
+
+ // Misc types.
+ _FORCE_INLINE_ static Color *get_color(Variant *v) { return reinterpret_cast<Color *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Color *get_color(const Variant *v) { return reinterpret_cast<const Color *>(v->_data._mem); }
+ _FORCE_INLINE_ static StringName *get_string_name(Variant *v) { return reinterpret_cast<StringName *>(v->_data._mem); }
+ _FORCE_INLINE_ static const StringName *get_string_name(const Variant *v) { return reinterpret_cast<const StringName *>(v->_data._mem); }
+ _FORCE_INLINE_ static NodePath *get_node_path(Variant *v) { return reinterpret_cast<NodePath *>(v->_data._mem); }
+ _FORCE_INLINE_ static const NodePath *get_node_path(const Variant *v) { return reinterpret_cast<const NodePath *>(v->_data._mem); }
+ _FORCE_INLINE_ static RID *get_rid(Variant *v) { return reinterpret_cast<RID *>(v->_data._mem); }
+ _FORCE_INLINE_ static const RID *get_rid(const Variant *v) { return reinterpret_cast<const RID *>(v->_data._mem); }
+ _FORCE_INLINE_ static Callable *get_callable(Variant *v) { return reinterpret_cast<Callable *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Callable *get_callable(const Variant *v) { return reinterpret_cast<const Callable *>(v->_data._mem); }
+ _FORCE_INLINE_ static Signal *get_signal(Variant *v) { return reinterpret_cast<Signal *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Signal *get_signal(const Variant *v) { return reinterpret_cast<const Signal *>(v->_data._mem); }
+ _FORCE_INLINE_ static Dictionary *get_dictionary(Variant *v) { return reinterpret_cast<Dictionary *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Dictionary *get_dictionary(const Variant *v) { return reinterpret_cast<const Dictionary *>(v->_data._mem); }
+ _FORCE_INLINE_ static Array *get_array(Variant *v) { return reinterpret_cast<Array *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Array *get_array(const Variant *v) { return reinterpret_cast<const Array *>(v->_data._mem); }
+
+ // Typed arrays.
+ _FORCE_INLINE_ static PackedByteArray *get_byte_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<uint8_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedByteArray *get_byte_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<uint8_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedInt32Array *get_int32_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<int32_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedInt32Array *get_int32_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<int32_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedInt64Array *get_int64_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<int64_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedInt64Array *get_int64_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<int64_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedFloat32Array *get_float32_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<float> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedFloat32Array *get_float32_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<float> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedFloat64Array *get_float64_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<double> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedFloat64Array *get_float64_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<double> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedStringArray *get_string_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<String> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedStringArray *get_string_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<String> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedVector2Array *get_vector2_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Vector2> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedVector2Array *get_vector2_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Vector2> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedVector3Array *get_vector3_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Vector3> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedVector3Array *get_vector3_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Vector3> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedColorArray *get_color_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Color> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedColorArray *get_color_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Color> *>(v->_data.packed_array)->array; }
+
+ _FORCE_INLINE_ static Object **get_object(Variant *v) { return (Object **)&v->_get_obj().obj; }
+ _FORCE_INLINE_ static const Object **get_object(const Variant *v) { return (const Object **)&v->_get_obj().obj; }
+};
+
+template <class T>
+struct VariantGetInternalPtr {
+};
+
+template <>
+struct VariantGetInternalPtr<bool> {
+ static bool *get_ptr(Variant *v) { return VariantInternal::get_bool(v); }
+ static const bool *get_ptr(const Variant *v) { return VariantInternal::get_bool(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<int8_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<uint8_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<int16_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<uint16_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<int32_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<uint32_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<int64_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<uint64_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<char32_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<ObjectID> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Error> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<float> {
+ static double *get_ptr(Variant *v) { return VariantInternal::get_float(v); }
+ static const double *get_ptr(const Variant *v) { return VariantInternal::get_float(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<double> {
+ static double *get_ptr(Variant *v) { return VariantInternal::get_float(v); }
+ static const double *get_ptr(const Variant *v) { return VariantInternal::get_float(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<String> {
+ static String *get_ptr(Variant *v) { return VariantInternal::get_string(v); }
+ static const String *get_ptr(const Variant *v) { return VariantInternal::get_string(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Vector2> {
+ static Vector2 *get_ptr(Variant *v) { return VariantInternal::get_vector2(v); }
+ static const Vector2 *get_ptr(const Variant *v) { return VariantInternal::get_vector2(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Vector2i> {
+ static Vector2i *get_ptr(Variant *v) { return VariantInternal::get_vector2i(v); }
+ static const Vector2i *get_ptr(const Variant *v) { return VariantInternal::get_vector2i(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Rect2> {
+ static Rect2 *get_ptr(Variant *v) { return VariantInternal::get_rect2(v); }
+ static const Rect2 *get_ptr(const Variant *v) { return VariantInternal::get_rect2(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Rect2i> {
+ static Rect2i *get_ptr(Variant *v) { return VariantInternal::get_rect2i(v); }
+ static const Rect2i *get_ptr(const Variant *v) { return VariantInternal::get_rect2i(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Vector3> {
+ static Vector3 *get_ptr(Variant *v) { return VariantInternal::get_vector3(v); }
+ static const Vector3 *get_ptr(const Variant *v) { return VariantInternal::get_vector3(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Vector3i> {
+ static Vector3i *get_ptr(Variant *v) { return VariantInternal::get_vector3i(v); }
+ static const Vector3i *get_ptr(const Variant *v) { return VariantInternal::get_vector3i(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Transform2D> {
+ static Transform2D *get_ptr(Variant *v) { return VariantInternal::get_transform2d(v); }
+ static const Transform2D *get_ptr(const Variant *v) { return VariantInternal::get_transform2d(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Transform> {
+ static Transform *get_ptr(Variant *v) { return VariantInternal::get_transform(v); }
+ static const Transform *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Plane> {
+ static Plane *get_ptr(Variant *v) { return VariantInternal::get_plane(v); }
+ static const Plane *get_ptr(const Variant *v) { return VariantInternal::get_plane(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Quat> {
+ static Quat *get_ptr(Variant *v) { return VariantInternal::get_quat(v); }
+ static const Quat *get_ptr(const Variant *v) { return VariantInternal::get_quat(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<::AABB> {
+ static ::AABB *get_ptr(Variant *v) { return VariantInternal::get_aabb(v); }
+ static const ::AABB *get_ptr(const Variant *v) { return VariantInternal::get_aabb(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Basis> {
+ static Basis *get_ptr(Variant *v) { return VariantInternal::get_basis(v); }
+ static const Basis *get_ptr(const Variant *v) { return VariantInternal::get_basis(v); }
+};
+
+//
+
+template <>
+struct VariantGetInternalPtr<Color> {
+ static Color *get_ptr(Variant *v) { return VariantInternal::get_color(v); }
+ static const Color *get_ptr(const Variant *v) { return VariantInternal::get_color(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<StringName> {
+ static StringName *get_ptr(Variant *v) { return VariantInternal::get_string_name(v); }
+ static const StringName *get_ptr(const Variant *v) { return VariantInternal::get_string_name(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<NodePath> {
+ static NodePath *get_ptr(Variant *v) { return VariantInternal::get_node_path(v); }
+ static const NodePath *get_ptr(const Variant *v) { return VariantInternal::get_node_path(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<RID> {
+ static RID *get_ptr(Variant *v) { return VariantInternal::get_rid(v); }
+ static const RID *get_ptr(const Variant *v) { return VariantInternal::get_rid(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Callable> {
+ static Callable *get_ptr(Variant *v) { return VariantInternal::get_callable(v); }
+ static const Callable *get_ptr(const Variant *v) { return VariantInternal::get_callable(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Signal> {
+ static Signal *get_ptr(Variant *v) { return VariantInternal::get_signal(v); }
+ static const Signal *get_ptr(const Variant *v) { return VariantInternal::get_signal(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Dictionary> {
+ static Dictionary *get_ptr(Variant *v) { return VariantInternal::get_dictionary(v); }
+ static const Dictionary *get_ptr(const Variant *v) { return VariantInternal::get_dictionary(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Array> {
+ static Array *get_ptr(Variant *v) { return VariantInternal::get_array(v); }
+ static const Array *get_ptr(const Variant *v) { return VariantInternal::get_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedByteArray> {
+ static PackedByteArray *get_ptr(Variant *v) { return VariantInternal::get_byte_array(v); }
+ static const PackedByteArray *get_ptr(const Variant *v) { return VariantInternal::get_byte_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedInt32Array> {
+ static PackedInt32Array *get_ptr(Variant *v) { return VariantInternal::get_int32_array(v); }
+ static const PackedInt32Array *get_ptr(const Variant *v) { return VariantInternal::get_int32_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedInt64Array> {
+ static PackedInt64Array *get_ptr(Variant *v) { return VariantInternal::get_int64_array(v); }
+ static const PackedInt64Array *get_ptr(const Variant *v) { return VariantInternal::get_int64_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedFloat32Array> {
+ static PackedFloat32Array *get_ptr(Variant *v) { return VariantInternal::get_float32_array(v); }
+ static const PackedFloat32Array *get_ptr(const Variant *v) { return VariantInternal::get_float32_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedFloat64Array> {
+ static PackedFloat64Array *get_ptr(Variant *v) { return VariantInternal::get_float64_array(v); }
+ static const PackedFloat64Array *get_ptr(const Variant *v) { return VariantInternal::get_float64_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedStringArray> {
+ static PackedStringArray *get_ptr(Variant *v) { return VariantInternal::get_string_array(v); }
+ static const PackedStringArray *get_ptr(const Variant *v) { return VariantInternal::get_string_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedVector2Array> {
+ static PackedVector2Array *get_ptr(Variant *v) { return VariantInternal::get_vector2_array(v); }
+ static const PackedVector2Array *get_ptr(const Variant *v) { return VariantInternal::get_vector2_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedVector3Array> {
+ static PackedVector3Array *get_ptr(Variant *v) { return VariantInternal::get_vector3_array(v); }
+ static const PackedVector3Array *get_ptr(const Variant *v) { return VariantInternal::get_vector3_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedColorArray> {
+ static PackedColorArray *get_ptr(Variant *v) { return VariantInternal::get_color_array(v); }
+ static const PackedColorArray *get_ptr(const Variant *v) { return VariantInternal::get_color_array(v); }
+};
+
+template <class T>
+struct VariantInternalAccessor {
+};
+
+template <>
+struct VariantInternalAccessor<bool> {
+ static _FORCE_INLINE_ bool get(const Variant *v) { return *VariantInternal::get_bool(v); }
+ static _FORCE_INLINE_ void set(Variant *v, bool p_value) { *VariantInternal::get_bool(v) = p_value; }
+};
+
+#define VARIANT_ACCESSOR_NUMBER(m_type) \
+ template <> \
+ struct VariantInternalAccessor<m_type> { \
+ static _FORCE_INLINE_ m_type get(const Variant *v) { return (m_type)*VariantInternal::get_int(v); } \
+ static _FORCE_INLINE_ void set(Variant *v, m_type p_value) { *VariantInternal::get_int(v) = p_value; } \
+ };
+
+VARIANT_ACCESSOR_NUMBER(int8_t)
+VARIANT_ACCESSOR_NUMBER(uint8_t)
+VARIANT_ACCESSOR_NUMBER(int16_t)
+VARIANT_ACCESSOR_NUMBER(uint16_t)
+VARIANT_ACCESSOR_NUMBER(int32_t)
+VARIANT_ACCESSOR_NUMBER(uint32_t)
+VARIANT_ACCESSOR_NUMBER(int64_t)
+VARIANT_ACCESSOR_NUMBER(uint64_t)
+VARIANT_ACCESSOR_NUMBER(char32_t)
+VARIANT_ACCESSOR_NUMBER(Error)
+VARIANT_ACCESSOR_NUMBER(Margin)
+
+template <>
+struct VariantInternalAccessor<ObjectID> {
+ static _FORCE_INLINE_ ObjectID get(const Variant *v) { return ObjectID(*VariantInternal::get_int(v)); }
+ static _FORCE_INLINE_ void set(Variant *v, ObjectID p_value) { *VariantInternal::get_int(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<float> {
+ static _FORCE_INLINE_ float get(const Variant *v) { return *VariantInternal::get_float(v); }
+ static _FORCE_INLINE_ void set(Variant *v, float p_value) { *VariantInternal::get_float(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<double> {
+ static _FORCE_INLINE_ double get(const Variant *v) { return *VariantInternal::get_float(v); }
+ static _FORCE_INLINE_ void set(Variant *v, double p_value) { *VariantInternal::get_float(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<String> {
+ static _FORCE_INLINE_ const String &get(const Variant *v) { return *VariantInternal::get_string(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const String &p_value) { *VariantInternal::get_string(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector2> {
+ static _FORCE_INLINE_ const Vector2 &get(const Variant *v) { return *VariantInternal::get_vector2(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector2 &p_value) { *VariantInternal::get_vector2(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector2i> {
+ static _FORCE_INLINE_ const Vector2i &get(const Variant *v) { return *VariantInternal::get_vector2i(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector2i &p_value) { *VariantInternal::get_vector2i(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Rect2> {
+ static _FORCE_INLINE_ const Rect2 &get(const Variant *v) { return *VariantInternal::get_rect2(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Rect2 &p_value) { *VariantInternal::get_rect2(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Rect2i> {
+ static _FORCE_INLINE_ const Rect2i &get(const Variant *v) { return *VariantInternal::get_rect2i(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Rect2i &p_value) { *VariantInternal::get_rect2i(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector3> {
+ static _FORCE_INLINE_ const Vector3 &get(const Variant *v) { return *VariantInternal::get_vector3(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector3 &p_value) { *VariantInternal::get_vector3(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector3i> {
+ static _FORCE_INLINE_ const Vector3i &get(const Variant *v) { return *VariantInternal::get_vector3i(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector3i &p_value) { *VariantInternal::get_vector3i(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Transform2D> {
+ static _FORCE_INLINE_ const Transform2D &get(const Variant *v) { return *VariantInternal::get_transform2d(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Transform2D &p_value) { *VariantInternal::get_transform2d(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Transform> {
+ static _FORCE_INLINE_ const Transform &get(const Variant *v) { return *VariantInternal::get_transform(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Transform &p_value) { *VariantInternal::get_transform(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Plane> {
+ static _FORCE_INLINE_ const Plane &get(const Variant *v) { return *VariantInternal::get_plane(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Plane &p_value) { *VariantInternal::get_plane(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Quat> {
+ static _FORCE_INLINE_ const Quat &get(const Variant *v) { return *VariantInternal::get_quat(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Quat &p_value) { *VariantInternal::get_quat(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<AABB> {
+ static _FORCE_INLINE_ const AABB &get(const Variant *v) { return *VariantInternal::get_aabb(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const AABB &p_value) { *VariantInternal::get_aabb(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Basis> {
+ static _FORCE_INLINE_ const Basis &get(const Variant *v) { return *VariantInternal::get_basis(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Basis &p_value) { *VariantInternal::get_basis(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Color> {
+ static _FORCE_INLINE_ const Color &get(const Variant *v) { return *VariantInternal::get_color(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Color &p_value) { *VariantInternal::get_color(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<StringName> {
+ static _FORCE_INLINE_ const StringName &get(const Variant *v) { return *VariantInternal::get_string_name(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const StringName &p_value) { *VariantInternal::get_string_name(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<NodePath> {
+ static _FORCE_INLINE_ const NodePath &get(const Variant *v) { return *VariantInternal::get_node_path(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const NodePath &p_value) { *VariantInternal::get_node_path(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<RID> {
+ static _FORCE_INLINE_ const RID &get(const Variant *v) { return *VariantInternal::get_rid(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const RID &p_value) { *VariantInternal::get_rid(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Callable> {
+ static _FORCE_INLINE_ const Callable &get(const Variant *v) { return *VariantInternal::get_callable(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Callable &p_value) { *VariantInternal::get_callable(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Signal> {
+ static _FORCE_INLINE_ const Signal &get(const Variant *v) { return *VariantInternal::get_signal(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Signal &p_value) { *VariantInternal::get_signal(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Dictionary> {
+ static _FORCE_INLINE_ const Dictionary &get(const Variant *v) { return *VariantInternal::get_dictionary(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Dictionary &p_value) { *VariantInternal::get_dictionary(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Array> {
+ static _FORCE_INLINE_ const Array &get(const Variant *v) { return *VariantInternal::get_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Array &p_value) { *VariantInternal::get_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedByteArray> {
+ static _FORCE_INLINE_ const PackedByteArray &get(const Variant *v) { return *VariantInternal::get_byte_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedByteArray &p_value) { *VariantInternal::get_byte_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedInt32Array> {
+ static _FORCE_INLINE_ const PackedInt32Array &get(const Variant *v) { return *VariantInternal::get_int32_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedInt32Array &p_value) { *VariantInternal::get_int32_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedInt64Array> {
+ static _FORCE_INLINE_ const PackedInt64Array &get(const Variant *v) { return *VariantInternal::get_int64_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedInt64Array &p_value) { *VariantInternal::get_int64_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedFloat32Array> {
+ static _FORCE_INLINE_ const PackedFloat32Array &get(const Variant *v) { return *VariantInternal::get_float32_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedFloat32Array &p_value) { *VariantInternal::get_float32_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedFloat64Array> {
+ static _FORCE_INLINE_ const PackedFloat64Array &get(const Variant *v) { return *VariantInternal::get_float64_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedFloat64Array &p_value) { *VariantInternal::get_float64_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedStringArray> {
+ static _FORCE_INLINE_ const PackedStringArray &get(const Variant *v) { return *VariantInternal::get_string_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedStringArray &p_value) { *VariantInternal::get_string_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedVector2Array> {
+ static _FORCE_INLINE_ const PackedVector2Array &get(const Variant *v) { return *VariantInternal::get_vector2_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedVector2Array &p_value) { *VariantInternal::get_vector2_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedVector3Array> {
+ static _FORCE_INLINE_ const PackedVector3Array &get(const Variant *v) { return *VariantInternal::get_vector3_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedVector3Array &p_value) { *VariantInternal::get_vector3_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedColorArray> {
+ static _FORCE_INLINE_ const PackedColorArray &get(const Variant *v) { return *VariantInternal::get_color_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedColorArray &p_value) { *VariantInternal::get_color_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Object *> {
+ static _FORCE_INLINE_ Object *get(const Variant *v) { return const_cast<Object *>(*VariantInternal::get_object(v)); }
+ static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { *VariantInternal::get_object(v) = const_cast<Object *>(p_value); }
+};
+
+template <>
+struct VariantInternalAccessor<Variant> {
+ static _FORCE_INLINE_ Variant &get(Variant *v) { return *v; }
+ static _FORCE_INLINE_ const Variant &get(const Variant *v) { return *v; }
+ static _FORCE_INLINE_ void set(Variant *v, const Variant &p_value) { *v = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector<Variant>> {
+ static _FORCE_INLINE_ Vector<Variant> get(const Variant *v) {
+ Vector<Variant> ret;
+ int s = VariantInternal::get_array(v)->size();
+ ret.resize(s);
+ for (int i = 0; i < s; i++) {
+ ret.write[i] = VariantInternal::get_array(v)->get(i);
+ }
+
+ return ret;
+ }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector<Variant> &p_value) {
+ int s = p_value.size();
+ VariantInternal::get_array(v)->resize(s);
+ for (int i = 0; i < s; i++) {
+ VariantInternal::get_array(v)->set(i, p_value[i]);
+ }
+ }
+};
+
+#endif // VARIANT_INTERNAL_H
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
new file mode 100644
index 0000000000..25ba66c9de
--- /dev/null
+++ b/core/variant/variant_op.cpp
@@ -0,0 +1,2135 @@
+/*************************************************************************/
+/* variant_op.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "variant.h"
+
+#include "core/core_string_names.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/object/class_db.h"
+
+template <class R, class A, class B>
+class OperatorEvaluatorAdd {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a + b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) + *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) + PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorSub {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a - b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) - *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) - PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorMul {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a * b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) * *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) * PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorXForm {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a.xform(b);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<A>::get_ptr(left)->xform(*VariantGetInternalPtr<B>::get_ptr(right));
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left).xform(PtrToArg<B>::convert(right)), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorXFormInv {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = b.xform_inv(a);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<B>::get_ptr(right)->xform_inv(*VariantGetInternalPtr<A>::get_ptr(left));
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<B>::convert(right).xform_inv(PtrToArg<A>::convert(left)), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorDiv {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a / b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorDivNZ {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ if (b == 0) {
+ r_valid = false;
+ *r_ret = "Division by zero error";
+ return;
+ }
+ *r_ret = a / b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorMod {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a % b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorModNZ {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ if (b == 0) {
+ r_valid = false;
+ *r_ret = "Module by zero error";
+ return;
+ }
+ *r_ret = a % b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A>
+class OperatorEvaluatorNeg {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ *r_ret = -a;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = -*VariantGetInternalPtr<A>::get_ptr(left);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(-PtrToArg<A>::convert(left), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A>
+class OperatorEvaluatorPos {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ *r_ret = a;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorShiftLeft {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a << b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) << *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) << PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorShiftRight {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a >> b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >> *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) >> PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorBitOr {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a | b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) | *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) | PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorBitAnd {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a & b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) & *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) & PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorBitXor {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a ^ b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) ^ *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) ^ PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A>
+class OperatorEvaluatorBitNeg {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ *r_ret = ~a;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = ~*VariantGetInternalPtr<A>::get_ptr(left);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(~PtrToArg<A>::convert(left), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorEqual {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a == b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+//equalobject
+class OperatorEvaluatorEqualObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Object *a = p_left.get_validated_object();
+ const Object *b = p_right.get_validated_object();
+ *r_ret = a == b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Object *a = left->get_validated_object();
+ const Object *b = right->get_validated_object();
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == b;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == PtrToArg<Object *>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorEqualObjectNil {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Object *a = p_left.get_validated_object();
+ *r_ret = a == nullptr;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Object *a = left->get_validated_object();
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == nullptr;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorEqualNilObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Object *b = p_right.get_validated_object();
+ *r_ret = nullptr == b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Object *b = right->get_validated_object();
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr == b;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(nullptr == PtrToArg<Object *>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorNotEqual {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a != b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) != *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) != PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotEqualObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *a = p_left.get_validated_object();
+ Object *b = p_right.get_validated_object();
+ *r_ret = a != b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *a = left->get_validated_object();
+ Object *b = right->get_validated_object();
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != b;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != PtrToArg<Object *>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotEqualObjectNil {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *a = p_left.get_validated_object();
+ *r_ret = a != nullptr;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *a = left->get_validated_object();
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != nullptr;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != nullptr, r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotEqualNilObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *b = p_right.get_validated_object();
+ *r_ret = nullptr != b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *b = right->get_validated_object();
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr != b;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(nullptr != PtrToArg<Object *>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorLess {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a < b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) < *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) < PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorLessEqual {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a <= b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) <= *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) <= PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorGreater {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a > b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) > *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) > PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorGreaterEqual {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a >= b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >= *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) >= PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorAnd {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a && b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) && *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) && PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorOr {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a || b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) || *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) || PtrToArg<B>::convert(right), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+#define XOR_OP(m_a, m_b) (((m_a) || (m_b)) && !((m_a) && (m_b)))
+template <class A, class B>
+class OperatorEvaluatorXor {
+public:
+ _FORCE_INLINE_ static bool xor_op(const A &a, const B &b) {
+ return ((a) || (b)) && !((a) && (b));
+ }
+
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = xor_op(a, b);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = xor_op(*VariantGetInternalPtr<A>::get_ptr(left), *VariantGetInternalPtr<B>::get_ptr(right));
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(xor_op(PtrToArg<A>::convert(left), PtrToArg<B>::convert(right)), r_ret);
+ }
+#endif
+
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A>
+class OperatorEvaluatorNot {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ *r_ret = !a;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(!PtrToArg<A>::convert(left));
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+//// CUSTOM ////
+
+class OperatorEvaluatorAddArray {
+public:
+ _FORCE_INLINE_ static void _add_arrays(Array &sum, const Array &array_a, const Array &array_b) {
+ int asize = array_a.size();
+ int bsize = array_b.size();
+ sum.resize(asize + bsize);
+ for (int i = 0; i < asize; i++) {
+ sum[i] = array_a[i];
+ }
+ for (int i = 0; i < bsize; i++) {
+ sum[i + asize] = array_b[i];
+ }
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Array &array_a = *VariantGetInternalPtr<Array>::get_ptr(&p_left);
+ const Array &array_b = *VariantGetInternalPtr<Array>::get_ptr(&p_right);
+ Array sum;
+ _add_arrays(sum, array_a, array_b);
+ *r_ret = sum;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ _add_arrays(*VariantGetInternalPtr<Array>::get_ptr(r_ret), *VariantGetInternalPtr<Array>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right));
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ Array ret;
+ _add_arrays(ret, PtrToArg<Array>::convert(left), PtrToArg<Array>::convert(right));
+ PtrToArg<Array>::encode(ret, r_ret);
+ }
+#endif
+
+ static Variant::Type get_return_type() { return Variant::ARRAY; }
+};
+
+template <class T>
+class OperatorEvaluatorAppendArray {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Vector<T> &array_a = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_left);
+ const Vector<T> &array_b = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_right);
+ Vector<T> sum = array_a;
+ sum.append_array(array_b);
+ *r_ret = sum;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret) = *VariantGetInternalPtr<Vector<T>>::get_ptr(left);
+ VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret)->append_array(*VariantGetInternalPtr<Vector<T>>::get_ptr(right));
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ Vector<T> sum = PtrToArg<Vector<T>>::convert(left);
+ sum.append_array(PtrToArg<Vector<T>>::convert(right));
+ PtrToArg<Vector<T>>::encode(sum, r_ret);
+ }
+#endif
+
+ static Variant::Type get_return_type() { return GetTypeInfo<Vector<T>>::VARIANT_TYPE; }
+};
+
+class OperatorEvaluatorStringModNil {
+public:
+ _FORCE_INLINE_ static String do_mod(const String &s, bool *r_valid) {
+ Array values;
+ values.push_back(Variant());
+
+ String a = s.sprintf(values, r_valid);
+ if (r_valid) {
+ *r_valid = !*r_valid;
+ }
+ return a;
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+ *r_ret = do_mod(a, &r_valid);
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), nullptr);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), nullptr), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::STRING; }
+};
+
+class OperatorEvaluatorStringModArray {
+public:
+ _FORCE_INLINE_ static String do_mod(const String &s, const Array &p_values, bool *r_valid) {
+ String a = s.sprintf(p_values, r_valid);
+ if (r_valid) {
+ *r_valid = !*r_valid;
+ }
+ return a;
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+ *r_ret = do_mod(a, *VariantGetInternalPtr<Array>::get_ptr(&p_right), &r_valid);
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), nullptr);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Array>::convert(right), nullptr), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::STRING; }
+};
+
+class OperatorEvaluatorStringModObject {
+public:
+ _FORCE_INLINE_ static String do_mod(const String &s, const Object *p_object, bool *r_valid) {
+ Array values;
+ values.push_back(p_object);
+ String a = s.sprintf(values, r_valid);
+ if (r_valid) {
+ *r_valid = !*r_valid;
+ }
+
+ return a;
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+ *r_ret = do_mod(a, p_right.get_validated_object(), &r_valid);
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), right->get_validated_object(), nullptr);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Object *>::convert(right), nullptr), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::STRING; }
+};
+
+template <class T>
+class OperatorEvaluatorStringModT {
+public:
+ _FORCE_INLINE_ static String do_mod(const String &s, const T &p_value, bool *r_valid) {
+ Array values;
+ values.push_back(p_value);
+ String a = s.sprintf(values, r_valid);
+ if (r_valid) {
+ *r_valid = !*r_valid;
+ }
+ return a;
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+ *r_ret = do_mod(a, *VariantGetInternalPtr<T>::get_ptr(&p_right), &r_valid);
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), nullptr);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<T>::convert(right), nullptr), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::STRING; }
+};
+
+template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right>
+class OperatorEvaluatorAlwaysTrue {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = true;
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = true;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(true, r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right>
+class OperatorEvaluatorAlwaysFalse {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = false;
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = false;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(false, r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+///// OR ///////
+
+_FORCE_INLINE_ static bool _operate_or(bool p_left, bool p_right) {
+ return p_left || p_right;
+}
+_FORCE_INLINE_ static bool _operate_and(bool p_left, bool p_right) {
+ return p_left && p_right;
+}
+_FORCE_INLINE_ static bool _operate_xor(bool p_left, bool p_right) {
+ return (p_left || p_right) && !(p_left && p_right);
+}
+
+_FORCE_INLINE_ static bool _operate_get_nil(const Variant *p_ptr) {
+ return p_ptr->get_validated_object() != nullptr;
+}
+
+_FORCE_INLINE_ static bool _operate_get_bool(const Variant *p_ptr) {
+ return *VariantGetInternalPtr<bool>::get_ptr(p_ptr);
+}
+
+_FORCE_INLINE_ static bool _operate_get_int(const Variant *p_ptr) {
+ return *VariantGetInternalPtr<int64_t>::get_ptr(p_ptr) != 0;
+}
+
+_FORCE_INLINE_ static bool _operate_get_float(const Variant *p_ptr) {
+ return *VariantGetInternalPtr<double>::get_ptr(p_ptr) != 0.0;
+}
+
+_FORCE_INLINE_ static bool _operate_get_object(const Variant *p_ptr) {
+ return p_ptr->get_validated_object() != nullptr;
+}
+
+#ifndef PTRCALL_ENABLED
+
+#define OP_EVALUATOR(m_class_name, m_left, m_right, m_op) \
+ class m_class_name { \
+ public: \
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { \
+ *r_ret = m_op(_operate_get_##m_left(&p_left), _operate_get_##m_right(&p_right)); \
+ r_valid = true; \
+ } \
+ \
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { \
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = m_op(_operate_get_##m_left(left), _operate_get_##m_right(right)); \
+ } \
+ \
+ static Variant::Type \
+ get_return_type() { \
+ return Variant::BOOL; \
+ } \
+ };
+
+#else
+
+_FORCE_INLINE_ static bool _operate_get_ptr_nil(const void *p_ptr) {
+ return false;
+}
+
+_FORCE_INLINE_ static bool _operate_get_ptr_bool(const void *p_ptr) {
+ return PtrToArg<bool>::convert(p_ptr);
+}
+
+_FORCE_INLINE_ static bool _operate_get_ptr_int(const void *p_ptr) {
+ return PtrToArg<int64_t>::convert(p_ptr) != 0;
+}
+
+_FORCE_INLINE_ static bool _operate_get_ptr_float(const void *p_ptr) {
+ return PtrToArg<double>::convert(p_ptr) != 0.0;
+}
+
+_FORCE_INLINE_ static bool _operate_get_ptr_object(const void *p_ptr) {
+ return PtrToArg<Object *>::convert(p_ptr) != nullptr;
+}
+
+#define OP_EVALUATOR(m_class_name, m_left, m_right, m_op) \
+ class m_class_name { \
+ public: \
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { \
+ *r_ret = m_op(_operate_get_##m_left(&p_left), _operate_get_##m_right(&p_right)); \
+ r_valid = true; \
+ } \
+ \
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { \
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = m_op(_operate_get_##m_left(left), _operate_get_##m_right(right)); \
+ } \
+ \
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) { \
+ PtrToArg<bool>::encode(m_op(_operate_get_ptr_##m_left(left), _operate_get_ptr_##m_right(right)), r_ret); \
+ } \
+ \
+ static Variant::Type get_return_type() { \
+ return Variant::BOOL; \
+ } \
+ };
+
+#endif
+
+// OR
+
+//nil
+OP_EVALUATOR(OperatorEvaluatorNilXBoolOr, nil, bool, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorBoolXNilOr, bool, nil, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorNilXIntOr, nil, int, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorIntXNilOr, int, nil, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorNilXFloatOr, nil, float, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorFloatXNilOr, float, nil, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorObjectXNilOr, object, nil, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorNilXObjectOr, nil, object, _operate_or)
+
+//bool
+OP_EVALUATOR(OperatorEvaluatorBoolXBoolOr, bool, bool, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXIntOr, bool, int, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorIntXBoolOr, int, bool, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXFloatOr, bool, float, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorFloatXBoolOr, float, bool, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXObjectOr, bool, object, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorObjectXBoolOr, object, bool, _operate_or)
+
+//int
+
+OP_EVALUATOR(OperatorEvaluatorIntXIntOr, int, int, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorIntXFloatOr, int, float, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorFloatXIntOr, float, int, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorIntXObjectOr, int, object, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorObjectXIntOr, object, int, _operate_or)
+
+//float
+
+OP_EVALUATOR(OperatorEvaluatorFloatXFloatOr, float, float, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorFloatXObjectOr, float, object, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorObjectXFloatOr, object, float, _operate_or)
+
+//object
+
+OP_EVALUATOR(OperatorEvaluatorObjectXObjectOr, object, object, _operate_or)
+
+// AND
+
+//nil
+OP_EVALUATOR(OperatorEvaluatorNilXBoolAnd, nil, bool, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorBoolXNilAnd, bool, nil, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorNilXIntAnd, nil, int, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorIntXNilAnd, int, nil, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorNilXFloatAnd, nil, float, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorFloatXNilAnd, float, nil, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorObjectXNilAnd, object, nil, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorNilXObjectAnd, nil, object, _operate_and)
+
+//bool
+OP_EVALUATOR(OperatorEvaluatorBoolXBoolAnd, bool, bool, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXIntAnd, bool, int, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorIntXBoolAnd, int, bool, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXFloatAnd, bool, float, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorFloatXBoolAnd, float, bool, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXObjectAnd, bool, object, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorObjectXBoolAnd, object, bool, _operate_and)
+
+//int
+
+OP_EVALUATOR(OperatorEvaluatorIntXIntAnd, int, int, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorIntXFloatAnd, int, float, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorFloatXIntAnd, float, int, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorIntXObjectAnd, int, object, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorObjectXIntAnd, object, int, _operate_and)
+
+//float
+
+OP_EVALUATOR(OperatorEvaluatorFloatXFloatAnd, float, float, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorFloatXObjectAnd, float, object, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorObjectXFloatAnd, object, float, _operate_and)
+
+//object
+
+OP_EVALUATOR(OperatorEvaluatorObjectXObjectAnd, object, object, _operate_and)
+
+// XOR
+
+//nil
+OP_EVALUATOR(OperatorEvaluatorNilXBoolXor, nil, bool, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorBoolXNilXor, bool, nil, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorNilXIntXor, nil, int, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorIntXNilXor, int, nil, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorNilXFloatXor, nil, float, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorFloatXNilXor, float, nil, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorObjectXNilXor, object, nil, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorNilXObjectXor, nil, object, _operate_xor)
+
+//bool
+OP_EVALUATOR(OperatorEvaluatorBoolXBoolXor, bool, bool, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXIntXor, bool, int, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorIntXBoolXor, int, bool, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXFloatXor, bool, float, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorFloatXBoolXor, float, bool, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXObjectXor, bool, object, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorObjectXBoolXor, object, bool, _operate_xor)
+
+//int
+
+OP_EVALUATOR(OperatorEvaluatorIntXIntXor, int, int, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorIntXFloatXor, int, float, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorFloatXIntXor, float, int, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorIntXObjectXor, int, object, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorObjectXIntXor, object, int, _operate_xor)
+
+//float
+
+OP_EVALUATOR(OperatorEvaluatorFloatXFloatXor, float, float, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorFloatXObjectXor, float, object, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorObjectXFloatXor, object, float, _operate_xor)
+
+//object
+
+OP_EVALUATOR(OperatorEvaluatorObjectXObjectXor, object, object, _operate_xor)
+
+class OperatorEvaluatorNotBool {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = !*VariantGetInternalPtr<bool>::get_ptr(&p_left);
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<bool>::get_ptr(left);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(!PtrToArg<bool>::convert(left), r_ret);
+ }
+#endif
+
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotInt {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = !*VariantGetInternalPtr<int64_t>::get_ptr(&p_left);
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<int64_t>::get_ptr(left);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(!PtrToArg<int64_t>::convert(left), r_ret);
+ }
+#endif
+
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotFloat {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = !*VariantGetInternalPtr<double>::get_ptr(&p_left);
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<double>::get_ptr(left);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(!PtrToArg<double>::convert(left), r_ret);
+ }
+#endif
+
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = p_left.get_validated_object() == nullptr;
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = left->get_validated_object() == nullptr;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret);
+ }
+#endif
+
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+////
+
+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 String &str_b = *VariantGetInternalPtr<String>::get_ptr(&p_right);
+
+ *r_ret = str_b.find(str_a) != -1;
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const String &str_a = *VariantGetInternalPtr<String>::get_ptr(left);
+ const String &str_b = *VariantGetInternalPtr<String>::get_ptr(right);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1;
+ }
+#ifdef PTRCALL_ENABLED
+ 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);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorInArrayFind {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+
+ *r_ret = b.find(a) != -1;
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(right);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(a) != -1;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<B>::convert(right).find(PtrToArg<A>::convert(left)) != -1, r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorInArrayFindNil {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right);
+ *r_ret = b.find(Variant()) != -1;
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(Variant()) != -1;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(Variant()) != -1, r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorInArrayFindObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right);
+ *r_ret = b.find(p_left) != -1;
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(*left) != -1;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(PtrToArg<Object *>::convert(left)) != -1, r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A>
+class OperatorEvaluatorInDictionaryHas {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right);
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+
+ *r_ret = b.has(a);
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right);
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(left);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(a);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<A>::convert(left)), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorInDictionaryHasNil {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right);
+
+ *r_ret = b.has(Variant());
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(Variant());
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(Variant()), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorInDictionaryHasObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right);
+
+ *r_ret = b.has(p_left);
+ r_valid = true;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(*left);
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<Object *>::convert(left)), r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorObjectHasPropertyString {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *b = p_right.get_validated_object();
+ if (!b) {
+ *r_ret = "Invalid base object for 'in'";
+ r_valid = false;
+ return;
+ }
+
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+
+ b->get(a, &r_valid);
+ *r_ret = r_valid;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *l = right->get_validated_object();
+ ERR_FAIL_COND(l == nullptr);
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(left);
+
+ bool valid;
+ l->get(a, &valid);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ bool valid;
+ PtrToArg<Object *>::convert(right)->get(PtrToArg<String>::convert(left), &valid);
+ PtrToArg<bool>::encode(valid, r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorObjectHasPropertyStringName {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *b = p_right.get_validated_object();
+ if (!b) {
+ *r_ret = "Invalid base object for 'in'";
+ r_valid = false;
+ return;
+ }
+
+ const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(&p_left);
+
+ b->get(a, &r_valid);
+ *r_ret = r_valid;
+ }
+
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *l = right->get_validated_object();
+ ERR_FAIL_COND(l == nullptr);
+ const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(left);
+
+ bool valid;
+ l->get(a, &valid);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid;
+ }
+#ifdef PTRCALL_ENABLED
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ bool valid;
+ PtrToArg<Object *>::convert(right)->get(PtrToArg<StringName>::convert(left), &valid);
+ PtrToArg<bool>::encode(valid, r_ret);
+ }
+#endif
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+typedef void (*VariantEvaluatorFunction)(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid);
+
+static Variant::Type operator_return_type_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
+static VariantEvaluatorFunction operator_evaluator_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
+static Variant::ValidatedOperatorEvaluator validated_operator_evaluator_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
+#ifdef PTRCALL_ENABLED
+static Variant::PTROperatorEvaluator ptr_operator_evaluator_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
+#endif
+
+template <class T>
+void register_op(Variant::Operator p_op, Variant::Type p_type_a, Variant::Type p_type_b) {
+ operator_return_type_table[p_op][p_type_a][p_type_b] = T::get_return_type();
+ operator_evaluator_table[p_op][p_type_a][p_type_b] = T::evaluate;
+ validated_operator_evaluator_table[p_op][p_type_a][p_type_b] = T::validated_evaluate;
+#ifdef PTRCALL_ENABLED
+ ptr_operator_evaluator_table[p_op][p_type_a][p_type_b] = T::ptr_evaluate;
+#endif
+}
+
+void register_variant_operators() {
+ zeromem(operator_return_type_table, sizeof(operator_return_type_table));
+ zeromem(operator_evaluator_table, sizeof(operator_evaluator_table));
+ zeromem(validated_operator_evaluator_table, sizeof(validated_operator_evaluator_table));
+#ifdef PTRCALL_ENABLED
+ zeromem(ptr_operator_evaluator_table, sizeof(ptr_operator_evaluator_table));
+#endif
+
+ register_op<OperatorEvaluatorAdd<int64_t, int64_t, int64_t>>(Variant::OP_ADD, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorAdd<double, int64_t, double>>(Variant::OP_ADD, Variant::INT, Variant::FLOAT);
+ 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<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);
+ register_op<OperatorEvaluatorAdd<Vector3i, Vector3i, Vector3i>>(Variant::OP_ADD, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorAdd<Quat, Quat, Quat>>(Variant::OP_ADD, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorAdd<Color, Color, Color>>(Variant::OP_ADD, Variant::COLOR, Variant::COLOR);
+ register_op<OperatorEvaluatorAddArray>(Variant::OP_ADD, Variant::ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorAppendArray<uint8_t>>(Variant::OP_ADD, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<int32_t>>(Variant::OP_ADD, Variant::PACKED_INT32_ARRAY, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<int64_t>>(Variant::OP_ADD, Variant::PACKED_INT64_ARRAY, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<float>>(Variant::OP_ADD, Variant::PACKED_FLOAT32_ARRAY, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<double>>(Variant::OP_ADD, Variant::PACKED_FLOAT64_ARRAY, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<String>>(Variant::OP_ADD, Variant::PACKED_STRING_ARRAY, Variant::PACKED_STRING_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<Vector2>>(Variant::OP_ADD, Variant::PACKED_VECTOR2_ARRAY, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<Vector3>>(Variant::OP_ADD, Variant::PACKED_VECTOR3_ARRAY, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<Color>>(Variant::OP_ADD, Variant::PACKED_COLOR_ARRAY, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorSub<int64_t, int64_t, int64_t>>(Variant::OP_SUBTRACT, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorSub<double, int64_t, double>>(Variant::OP_SUBTRACT, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorSub<double, double, int64_t>>(Variant::OP_SUBTRACT, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorSub<double, double, double>>(Variant::OP_SUBTRACT, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorSub<Vector2, Vector2, Vector2>>(Variant::OP_SUBTRACT, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorSub<Vector2i, Vector2i, Vector2i>>(Variant::OP_SUBTRACT, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorSub<Vector3, Vector3, Vector3>>(Variant::OP_SUBTRACT, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorSub<Vector3i, Vector3i, Vector3i>>(Variant::OP_SUBTRACT, Variant::VECTOR3I, Variant::VECTOR3I);
+
+ register_op<OperatorEvaluatorMul<int64_t, int64_t, int64_t>>(Variant::OP_MULTIPLY, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorMul<double, int64_t, double>>(Variant::OP_MULTIPLY, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorMul<Vector2, int64_t, Vector2>>(Variant::OP_MULTIPLY, Variant::INT, Variant::VECTOR2);
+ register_op<OperatorEvaluatorMul<Vector2i, int64_t, Vector2i>>(Variant::OP_MULTIPLY, Variant::INT, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorMul<Vector3, int64_t, Vector3>>(Variant::OP_MULTIPLY, Variant::INT, Variant::VECTOR3);
+ register_op<OperatorEvaluatorMul<Vector3i, int64_t, Vector3i>>(Variant::OP_MULTIPLY, Variant::INT, Variant::VECTOR3I);
+
+ 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<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<Vector2, Vector2, Vector2>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorMul<Vector2, Vector2, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::INT);
+ register_op<OperatorEvaluatorMul<Vector2, Vector2, double>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::FLOAT);
+
+ 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<Vector3, Vector3, Vector3>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorMul<Vector3, Vector3, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::INT);
+ register_op<OperatorEvaluatorMul<Vector3, Vector3, double>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::FLOAT);
+
+ 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<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT);
+ register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR);
+ register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT);
+ register_op<OperatorEvaluatorMul<Color, Color, double>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorMul<Transform2D, Transform2D, Transform2D>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorXForm<Vector2, Transform2D, Vector2>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::VECTOR2);
+ register_op<OperatorEvaluatorXFormInv<Vector2, Vector2, Transform2D>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorXForm<Rect2, Transform2D, Rect2>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::RECT2);
+ register_op<OperatorEvaluatorXFormInv<Rect2, Rect2, Transform2D>>(Variant::OP_MULTIPLY, Variant::RECT2, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorXForm<Vector<Vector2>, Transform2D, Vector<Vector2>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorXFormInv<Vector<Vector2>, Vector<Vector2>, Transform2D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR2_ARRAY, Variant::TRANSFORM2D);
+
+ register_op<OperatorEvaluatorMul<Transform, Transform, Transform>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorXForm<Vector3, Transform, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::VECTOR3);
+ register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorXForm<AABB, Transform, AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::AABB);
+ register_op<OperatorEvaluatorXFormInv<AABB, AABB, Transform>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM);
+
+ register_op<OperatorEvaluatorMul<Basis, Basis, Basis>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::BASIS);
+ register_op<OperatorEvaluatorXForm<Vector3, Basis, Vector3>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::VECTOR3);
+ register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Basis>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::BASIS);
+
+ register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT);
+ register_op<OperatorEvaluatorMul<Quat, int64_t, Quat>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUAT);
+ register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorMul<Quat, double, Quat>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUAT);
+ register_op<OperatorEvaluatorXForm<Vector3, Quat, Vector3>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::VECTOR3);
+ register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quat>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUAT);
+
+ register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR);
+ register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT);
+ register_op<OperatorEvaluatorMul<Color, int64_t, Color>>(Variant::OP_MULTIPLY, Variant::INT, Variant::COLOR);
+ register_op<OperatorEvaluatorMul<Color, Color, double>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::FLOAT);
+ register_op<OperatorEvaluatorMul<Color, double, Color>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::COLOR);
+
+ register_op<OperatorEvaluatorDivNZ<int64_t, int64_t, int64_t>>(Variant::OP_DIVIDE, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorDiv<double, double, int64_t>>(Variant::OP_DIVIDE, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorDiv<double, int64_t, double>>(Variant::OP_DIVIDE, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<double, double, double>>(Variant::OP_DIVIDE, Variant::FLOAT, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, Vector2>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, double>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<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<Vector2i, Vector2i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, Vector2>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, double>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Vector3, Vector3, Vector3>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorDiv<Vector3, Vector3, double>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Vector3, Vector3, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<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<Vector3i, Vector3i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Quat, Quat, double>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Quat, Quat, int64_t>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Color, Color, Color>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::COLOR);
+ register_op<OperatorEvaluatorDiv<Color, Color, double>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Color, Color, int64_t>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::INT);
+
+ register_op<OperatorEvaluatorModNZ<int64_t, int64_t, int64_t>>(Variant::OP_MODULE, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorMod<Vector2i, Vector2i, Vector2i>>(Variant::OP_MODULE, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorModNZ<Vector2i, Vector2i, int64_t>>(Variant::OP_MODULE, Variant::VECTOR2I, Variant::INT);
+
+ register_op<OperatorEvaluatorMod<Vector3i, Vector3i, Vector3i>>(Variant::OP_MODULE, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorModNZ<Vector3i, Vector3i, int64_t>>(Variant::OP_MODULE, Variant::VECTOR3I, Variant::INT);
+
+ register_op<OperatorEvaluatorStringModNil>(Variant::OP_MODULE, Variant::STRING, Variant::NIL);
+
+ register_op<OperatorEvaluatorStringModT<bool>>(Variant::OP_MODULE, Variant::STRING, Variant::BOOL);
+ register_op<OperatorEvaluatorStringModT<int64_t>>(Variant::OP_MODULE, Variant::STRING, Variant::INT);
+ register_op<OperatorEvaluatorStringModT<double>>(Variant::OP_MODULE, Variant::STRING, Variant::FLOAT);
+ register_op<OperatorEvaluatorStringModT<String>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorStringModT<Vector2>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR2);
+ register_op<OperatorEvaluatorStringModT<Vector2i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorStringModT<Rect2>>(Variant::OP_MODULE, Variant::STRING, Variant::RECT2);
+ register_op<OperatorEvaluatorStringModT<Rect2i>>(Variant::OP_MODULE, Variant::STRING, Variant::RECT2I);
+ register_op<OperatorEvaluatorStringModT<Vector3>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3);
+ register_op<OperatorEvaluatorStringModT<Vector3i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorStringModT<Transform2D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorStringModT<Plane>>(Variant::OP_MODULE, Variant::STRING, Variant::PLANE);
+ register_op<OperatorEvaluatorStringModT<Quat>>(Variant::OP_MODULE, Variant::STRING, Variant::QUAT);
+ register_op<OperatorEvaluatorStringModT<AABB>>(Variant::OP_MODULE, Variant::STRING, Variant::AABB);
+ register_op<OperatorEvaluatorStringModT<Basis>>(Variant::OP_MODULE, Variant::STRING, Variant::BASIS);
+ register_op<OperatorEvaluatorStringModT<Transform>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM);
+
+ register_op<OperatorEvaluatorStringModT<Color>>(Variant::OP_MODULE, Variant::STRING, Variant::COLOR);
+ register_op<OperatorEvaluatorStringModT<StringName>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING_NAME);
+ register_op<OperatorEvaluatorStringModT<NodePath>>(Variant::OP_MODULE, Variant::STRING, Variant::NODE_PATH);
+ register_op<OperatorEvaluatorStringModObject>(Variant::OP_MODULE, Variant::STRING, Variant::OBJECT);
+ register_op<OperatorEvaluatorStringModT<Callable>>(Variant::OP_MODULE, Variant::STRING, Variant::CALLABLE);
+ register_op<OperatorEvaluatorStringModT<Signal>>(Variant::OP_MODULE, Variant::STRING, Variant::SIGNAL);
+ register_op<OperatorEvaluatorStringModT<Dictionary>>(Variant::OP_MODULE, Variant::STRING, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorStringModArray>(Variant::OP_MODULE, Variant::STRING, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorStringModT<PackedByteArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedInt32Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedInt64Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedFloat32Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedFloat64Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedStringArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_STRING_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedVector2Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedVector3Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedColorArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorNeg<int64_t, int64_t>>(Variant::OP_NEGATE, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<double, double>>(Variant::OP_NEGATE, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Vector2, Vector2>>(Variant::OP_NEGATE, Variant::VECTOR2, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Vector2i, Vector2i>>(Variant::OP_NEGATE, Variant::VECTOR2I, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Vector3, Vector3>>(Variant::OP_NEGATE, Variant::VECTOR3, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Vector3i, Vector3i>>(Variant::OP_NEGATE, Variant::VECTOR3I, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Quat, Quat>>(Variant::OP_NEGATE, Variant::QUAT, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Plane, Plane>>(Variant::OP_NEGATE, Variant::PLANE, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Color, Color>>(Variant::OP_NEGATE, Variant::COLOR, Variant::NIL);
+
+ register_op<OperatorEvaluatorPos<int64_t, int64_t>>(Variant::OP_POSITIVE, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorPos<double, double>>(Variant::OP_POSITIVE, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Vector2, Vector2>>(Variant::OP_POSITIVE, Variant::VECTOR2, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Vector2i, Vector2i>>(Variant::OP_POSITIVE, Variant::VECTOR2I, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Vector3, Vector3>>(Variant::OP_POSITIVE, Variant::VECTOR3, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Vector3i, Vector3i>>(Variant::OP_POSITIVE, Variant::VECTOR3I, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Quat, Quat>>(Variant::OP_POSITIVE, Variant::QUAT, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Plane, Plane>>(Variant::OP_POSITIVE, Variant::PLANE, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Color, Color>>(Variant::OP_POSITIVE, Variant::COLOR, Variant::NIL);
+
+ register_op<OperatorEvaluatorShiftLeft<int64_t, int64_t, int64_t>>(Variant::OP_SHIFT_LEFT, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorShiftRight<int64_t, int64_t, int64_t>>(Variant::OP_SHIFT_RIGHT, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorBitOr<int64_t, int64_t, int64_t>>(Variant::OP_BIT_OR, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorBitAnd<int64_t, int64_t, int64_t>>(Variant::OP_BIT_AND, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorBitXor<int64_t, int64_t, int64_t>>(Variant::OP_BIT_XOR, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
+
+ register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
+
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_EQUAL, Variant::NIL, Variant::NIL>>(Variant::OP_EQUAL, Variant::NIL, Variant::NIL);
+ register_op<OperatorEvaluatorEqual<bool, bool>>(Variant::OP_EQUAL, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorEqual<int64_t, int64_t>>(Variant::OP_EQUAL, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorEqual<int64_t, double>>(Variant::OP_EQUAL, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorEqual<double, int64_t>>(Variant::OP_EQUAL, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorEqual<double, double>>(Variant::OP_EQUAL, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorEqual<String, String>>(Variant::OP_EQUAL, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorEqual<Vector2, Vector2>>(Variant::OP_EQUAL, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorEqual<Vector2i, Vector2i>>(Variant::OP_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorEqual<Rect2, Rect2>>(Variant::OP_EQUAL, Variant::RECT2, Variant::RECT2);
+ register_op<OperatorEvaluatorEqual<Rect2i, Rect2i>>(Variant::OP_EQUAL, Variant::RECT2I, Variant::RECT2I);
+ register_op<OperatorEvaluatorEqual<Vector3, Vector3>>(Variant::OP_EQUAL, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorEqual<Vector3i, Vector3i>>(Variant::OP_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorEqual<Transform2D, Transform2D>>(Variant::OP_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorEqual<Plane, Plane>>(Variant::OP_EQUAL, Variant::PLANE, Variant::PLANE);
+ register_op<OperatorEvaluatorEqual<Quat, Quat>>(Variant::OP_EQUAL, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorEqual<AABB, AABB>>(Variant::OP_EQUAL, Variant::AABB, Variant::AABB);
+ register_op<OperatorEvaluatorEqual<Basis, Basis>>(Variant::OP_EQUAL, Variant::BASIS, Variant::BASIS);
+ register_op<OperatorEvaluatorEqual<Transform, Transform>>(Variant::OP_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorEqual<Color, Color>>(Variant::OP_EQUAL, Variant::COLOR, Variant::COLOR);
+
+ register_op<OperatorEvaluatorEqual<StringName, String>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING);
+ register_op<OperatorEvaluatorEqual<String, StringName>>(Variant::OP_EQUAL, Variant::STRING, Variant::STRING_NAME);
+ register_op<OperatorEvaluatorEqual<StringName, StringName>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME);
+
+ register_op<OperatorEvaluatorEqual<NodePath, NodePath>>(Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NODE_PATH);
+ register_op<OperatorEvaluatorEqual<RID, RID>>(Variant::OP_EQUAL, Variant::_RID, Variant::_RID);
+
+ register_op<OperatorEvaluatorEqualObject>(Variant::OP_EQUAL, Variant::OBJECT, Variant::OBJECT);
+ register_op<OperatorEvaluatorEqualObjectNil>(Variant::OP_EQUAL, Variant::OBJECT, Variant::NIL);
+ register_op<OperatorEvaluatorEqualNilObject>(Variant::OP_EQUAL, Variant::NIL, Variant::OBJECT);
+
+ register_op<OperatorEvaluatorEqual<Callable, Callable>>(Variant::OP_EQUAL, Variant::CALLABLE, Variant::CALLABLE);
+ register_op<OperatorEvaluatorEqual<Signal, Signal>>(Variant::OP_EQUAL, Variant::SIGNAL, Variant::SIGNAL);
+ register_op<OperatorEvaluatorEqual<Dictionary, Dictionary>>(Variant::OP_EQUAL, Variant::DICTIONARY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorEqual<Array, Array>>(Variant::OP_EQUAL, Variant::ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedByteArray, PackedByteArray>>(Variant::OP_EQUAL, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedInt32Array, PackedInt32Array>>(Variant::OP_EQUAL, Variant::PACKED_INT32_ARRAY, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedInt64Array, PackedInt64Array>>(Variant::OP_EQUAL, Variant::PACKED_INT64_ARRAY, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedFloat32Array, PackedFloat32Array>>(Variant::OP_EQUAL, Variant::PACKED_FLOAT32_ARRAY, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedFloat64Array, PackedFloat64Array>>(Variant::OP_EQUAL, Variant::PACKED_FLOAT64_ARRAY, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedStringArray, PackedStringArray>>(Variant::OP_EQUAL, Variant::PACKED_STRING_ARRAY, Variant::PACKED_STRING_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedVector2Array, PackedVector2Array>>(Variant::OP_EQUAL, Variant::PACKED_VECTOR2_ARRAY, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedVector3Array, PackedVector3Array>>(Variant::OP_EQUAL, Variant::PACKED_VECTOR3_ARRAY, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedColorArray, PackedColorArray>>(Variant::OP_EQUAL, Variant::PACKED_COLOR_ARRAY, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NIL);
+ register_op<OperatorEvaluatorNotEqual<bool, bool>>(Variant::OP_NOT_EQUAL, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorNotEqual<int64_t, int64_t>>(Variant::OP_NOT_EQUAL, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorNotEqual<int64_t, double>>(Variant::OP_NOT_EQUAL, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorNotEqual<double, int64_t>>(Variant::OP_NOT_EQUAL, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorNotEqual<double, double>>(Variant::OP_NOT_EQUAL, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorNotEqual<String, String>>(Variant::OP_NOT_EQUAL, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorNotEqual<Vector2, Vector2>>(Variant::OP_NOT_EQUAL, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorNotEqual<Vector2i, Vector2i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorNotEqual<Rect2, Rect2>>(Variant::OP_NOT_EQUAL, Variant::RECT2, Variant::RECT2);
+ register_op<OperatorEvaluatorNotEqual<Rect2i, Rect2i>>(Variant::OP_NOT_EQUAL, Variant::RECT2I, Variant::RECT2I);
+ register_op<OperatorEvaluatorNotEqual<Vector3, Vector3>>(Variant::OP_NOT_EQUAL, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorNotEqual<Vector3i, Vector3i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorNotEqual<Transform2D, Transform2D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorNotEqual<Plane, Plane>>(Variant::OP_NOT_EQUAL, Variant::PLANE, Variant::PLANE);
+ register_op<OperatorEvaluatorNotEqual<Quat, Quat>>(Variant::OP_NOT_EQUAL, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorNotEqual<AABB, AABB>>(Variant::OP_NOT_EQUAL, Variant::AABB, Variant::AABB);
+ register_op<OperatorEvaluatorNotEqual<Basis, Basis>>(Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::BASIS);
+ register_op<OperatorEvaluatorNotEqual<Transform, Transform>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorNotEqual<Color, Color>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::COLOR);
+
+ register_op<OperatorEvaluatorNotEqual<StringName, String>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING);
+ register_op<OperatorEvaluatorNotEqual<String, StringName>>(Variant::OP_NOT_EQUAL, Variant::STRING, Variant::STRING_NAME);
+ register_op<OperatorEvaluatorNotEqual<StringName, StringName>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME);
+
+ register_op<OperatorEvaluatorNotEqual<NodePath, NodePath>>(Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NODE_PATH);
+ register_op<OperatorEvaluatorNotEqual<RID, RID>>(Variant::OP_NOT_EQUAL, Variant::_RID, Variant::_RID);
+
+ register_op<OperatorEvaluatorNotEqualObject>(Variant::OP_NOT_EQUAL, Variant::OBJECT, Variant::OBJECT);
+ register_op<OperatorEvaluatorNotEqualObjectNil>(Variant::OP_NOT_EQUAL, Variant::OBJECT, Variant::NIL);
+ register_op<OperatorEvaluatorNotEqualNilObject>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::OBJECT);
+
+ register_op<OperatorEvaluatorNotEqual<Callable, Callable>>(Variant::OP_NOT_EQUAL, Variant::CALLABLE, Variant::CALLABLE);
+ register_op<OperatorEvaluatorNotEqual<Signal, Signal>>(Variant::OP_NOT_EQUAL, Variant::SIGNAL, Variant::SIGNAL);
+ register_op<OperatorEvaluatorNotEqual<Dictionary, Dictionary>>(Variant::OP_NOT_EQUAL, Variant::DICTIONARY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorNotEqual<Array, Array>>(Variant::OP_NOT_EQUAL, Variant::ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedByteArray, PackedByteArray>>(Variant::OP_NOT_EQUAL, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedInt32Array, PackedInt32Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_INT32_ARRAY, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedInt64Array, PackedInt64Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_INT64_ARRAY, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedFloat32Array, PackedFloat32Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_FLOAT32_ARRAY, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedFloat64Array, PackedFloat64Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_FLOAT64_ARRAY, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedStringArray, PackedStringArray>>(Variant::OP_NOT_EQUAL, Variant::PACKED_STRING_ARRAY, Variant::PACKED_STRING_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedVector2Array, PackedVector2Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_VECTOR2_ARRAY, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedVector3Array, PackedVector3Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_VECTOR3_ARRAY, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedColorArray, PackedColorArray>>(Variant::OP_NOT_EQUAL, Variant::PACKED_COLOR_ARRAY, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorLess<bool, bool>>(Variant::OP_LESS, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorLess<int64_t, int64_t>>(Variant::OP_LESS, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorLess<int64_t, double>>(Variant::OP_LESS, Variant::INT, Variant::FLOAT);
+ 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<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);
+ register_op<OperatorEvaluatorLess<Vector3i, Vector3i>>(Variant::OP_LESS, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorLess<RID, RID>>(Variant::OP_LESS, Variant::_RID, Variant::_RID);
+ register_op<OperatorEvaluatorLess<Array, Array>>(Variant::OP_LESS, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorLessEqual<int64_t, int64_t>>(Variant::OP_LESS_EQUAL, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorLessEqual<int64_t, double>>(Variant::OP_LESS_EQUAL, Variant::INT, Variant::FLOAT);
+ 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<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);
+ register_op<OperatorEvaluatorLessEqual<Vector3i, Vector3i>>(Variant::OP_LESS_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorLessEqual<RID, RID>>(Variant::OP_LESS_EQUAL, Variant::_RID, Variant::_RID);
+ register_op<OperatorEvaluatorLessEqual<Array, Array>>(Variant::OP_LESS_EQUAL, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorGreater<bool, bool>>(Variant::OP_GREATER, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorGreater<int64_t, int64_t>>(Variant::OP_GREATER, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorGreater<int64_t, double>>(Variant::OP_GREATER, Variant::INT, Variant::FLOAT);
+ 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<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);
+ register_op<OperatorEvaluatorGreater<Vector3i, Vector3i>>(Variant::OP_GREATER, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorGreater<RID, RID>>(Variant::OP_GREATER, Variant::_RID, Variant::_RID);
+ register_op<OperatorEvaluatorGreater<Array, Array>>(Variant::OP_GREATER, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorGreaterEqual<int64_t, int64_t>>(Variant::OP_GREATER_EQUAL, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorGreaterEqual<int64_t, double>>(Variant::OP_GREATER_EQUAL, Variant::INT, Variant::FLOAT);
+ 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<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);
+ register_op<OperatorEvaluatorGreaterEqual<Vector3i, Vector3i>>(Variant::OP_GREATER_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorGreaterEqual<RID, RID>>(Variant::OP_GREATER_EQUAL, Variant::_RID, Variant::_RID);
+ register_op<OperatorEvaluatorGreaterEqual<Array, Array>>(Variant::OP_GREATER_EQUAL, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_OR, Variant::NIL, Variant::NIL>>(Variant::OP_OR, Variant::NIL, Variant::NIL);
+
+ //OR
+ register_op<OperatorEvaluatorNilXBoolOr>(Variant::OP_OR, Variant::NIL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXNilOr>(Variant::OP_OR, Variant::BOOL, Variant::NIL);
+ register_op<OperatorEvaluatorNilXIntOr>(Variant::OP_OR, Variant::NIL, Variant::INT);
+ register_op<OperatorEvaluatorIntXNilOr>(Variant::OP_OR, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXFloatOr>(Variant::OP_OR, Variant::NIL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXNilOr>(Variant::OP_OR, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXObjectOr>(Variant::OP_OR, Variant::NIL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXNilOr>(Variant::OP_OR, Variant::OBJECT, Variant::NIL);
+
+ register_op<OperatorEvaluatorBoolXBoolOr>(Variant::OP_OR, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXIntOr>(Variant::OP_OR, Variant::BOOL, Variant::INT);
+ register_op<OperatorEvaluatorIntXBoolOr>(Variant::OP_OR, Variant::INT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXFloatOr>(Variant::OP_OR, Variant::BOOL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXBoolOr>(Variant::OP_OR, Variant::FLOAT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXObjectOr>(Variant::OP_OR, Variant::BOOL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXBoolOr>(Variant::OP_OR, Variant::OBJECT, Variant::BOOL);
+
+ register_op<OperatorEvaluatorIntXIntOr>(Variant::OP_OR, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorIntXFloatOr>(Variant::OP_OR, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXIntOr>(Variant::OP_OR, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorIntXObjectOr>(Variant::OP_OR, Variant::INT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXIntOr>(Variant::OP_OR, Variant::OBJECT, Variant::INT);
+
+ register_op<OperatorEvaluatorFloatXFloatOr>(Variant::OP_OR, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXObjectOr>(Variant::OP_OR, Variant::FLOAT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXFloatOr>(Variant::OP_OR, Variant::OBJECT, Variant::FLOAT);
+ register_op<OperatorEvaluatorObjectXObjectOr>(Variant::OP_OR, Variant::OBJECT, Variant::OBJECT);
+ //AND
+ register_op<OperatorEvaluatorNilXBoolAnd>(Variant::OP_AND, Variant::NIL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXNilAnd>(Variant::OP_AND, Variant::BOOL, Variant::NIL);
+ register_op<OperatorEvaluatorNilXIntAnd>(Variant::OP_AND, Variant::NIL, Variant::INT);
+ register_op<OperatorEvaluatorIntXNilAnd>(Variant::OP_AND, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXFloatAnd>(Variant::OP_AND, Variant::NIL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXNilAnd>(Variant::OP_AND, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXObjectAnd>(Variant::OP_AND, Variant::NIL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXNilAnd>(Variant::OP_AND, Variant::OBJECT, Variant::NIL);
+
+ register_op<OperatorEvaluatorBoolXBoolAnd>(Variant::OP_AND, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXIntAnd>(Variant::OP_AND, Variant::BOOL, Variant::INT);
+ register_op<OperatorEvaluatorIntXBoolAnd>(Variant::OP_AND, Variant::INT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXFloatAnd>(Variant::OP_AND, Variant::BOOL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXBoolAnd>(Variant::OP_AND, Variant::FLOAT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXObjectAnd>(Variant::OP_AND, Variant::BOOL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXBoolAnd>(Variant::OP_AND, Variant::OBJECT, Variant::BOOL);
+
+ register_op<OperatorEvaluatorIntXIntAnd>(Variant::OP_AND, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorIntXFloatAnd>(Variant::OP_AND, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXIntAnd>(Variant::OP_AND, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorIntXObjectAnd>(Variant::OP_AND, Variant::INT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXIntAnd>(Variant::OP_AND, Variant::OBJECT, Variant::INT);
+
+ register_op<OperatorEvaluatorFloatXFloatAnd>(Variant::OP_AND, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXObjectAnd>(Variant::OP_AND, Variant::FLOAT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXFloatAnd>(Variant::OP_AND, Variant::OBJECT, Variant::FLOAT);
+ register_op<OperatorEvaluatorObjectXObjectAnd>(Variant::OP_AND, Variant::OBJECT, Variant::OBJECT);
+ //XOR
+ register_op<OperatorEvaluatorNilXBoolXor>(Variant::OP_XOR, Variant::NIL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXNilXor>(Variant::OP_XOR, Variant::BOOL, Variant::NIL);
+ register_op<OperatorEvaluatorNilXIntXor>(Variant::OP_XOR, Variant::NIL, Variant::INT);
+ register_op<OperatorEvaluatorIntXNilXor>(Variant::OP_XOR, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXFloatXor>(Variant::OP_XOR, Variant::NIL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXNilXor>(Variant::OP_XOR, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXObjectXor>(Variant::OP_XOR, Variant::NIL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXNilXor>(Variant::OP_XOR, Variant::OBJECT, Variant::NIL);
+
+ register_op<OperatorEvaluatorBoolXBoolXor>(Variant::OP_XOR, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXIntXor>(Variant::OP_XOR, Variant::BOOL, Variant::INT);
+ register_op<OperatorEvaluatorIntXBoolXor>(Variant::OP_XOR, Variant::INT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXFloatXor>(Variant::OP_XOR, Variant::BOOL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXBoolXor>(Variant::OP_XOR, Variant::FLOAT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXObjectXor>(Variant::OP_XOR, Variant::BOOL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXBoolXor>(Variant::OP_XOR, Variant::OBJECT, Variant::BOOL);
+
+ register_op<OperatorEvaluatorIntXIntXor>(Variant::OP_XOR, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorIntXFloatXor>(Variant::OP_XOR, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXIntXor>(Variant::OP_XOR, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorIntXObjectXor>(Variant::OP_XOR, Variant::INT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXIntXor>(Variant::OP_XOR, Variant::OBJECT, Variant::INT);
+
+ register_op<OperatorEvaluatorFloatXFloatXor>(Variant::OP_XOR, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXObjectXor>(Variant::OP_XOR, Variant::FLOAT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXFloatXor>(Variant::OP_XOR, Variant::OBJECT, Variant::FLOAT);
+ register_op<OperatorEvaluatorObjectXObjectXor>(Variant::OP_XOR, Variant::OBJECT, Variant::OBJECT);
+
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT, Variant::NIL, Variant::NIL>>(Variant::OP_NOT, Variant::NIL, Variant::NIL);
+ register_op<OperatorEvaluatorNotBool>(Variant::OP_NOT, Variant::BOOL, Variant::NIL);
+ register_op<OperatorEvaluatorNotInt>(Variant::OP_NOT, Variant::INT, Variant::NIL);
+ 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<OperatorEvaluatorInDictionaryHasNil>(Variant::OP_IN, Variant::NIL, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<bool>>(Variant::OP_IN, Variant::BOOL, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<int64_t>>(Variant::OP_IN, Variant::INT, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<double>>(Variant::OP_IN, Variant::FLOAT, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<String>>(Variant::OP_IN, Variant::STRING, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Vector2>>(Variant::OP_IN, Variant::VECTOR2, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Vector2i>>(Variant::OP_IN, Variant::VECTOR2I, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Rect2>>(Variant::OP_IN, Variant::RECT2, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Rect2i>>(Variant::OP_IN, Variant::RECT2I, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Vector3>>(Variant::OP_IN, Variant::VECTOR3, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Vector3i>>(Variant::OP_IN, Variant::VECTOR3I, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Transform2D>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Plane>>(Variant::OP_IN, Variant::PLANE, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Quat>>(Variant::OP_IN, Variant::QUAT, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<AABB>>(Variant::OP_IN, Variant::AABB, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Basis>>(Variant::OP_IN, Variant::BASIS, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Transform>>(Variant::OP_IN, Variant::TRANSFORM, Variant::DICTIONARY);
+
+ register_op<OperatorEvaluatorInDictionaryHas<Color>>(Variant::OP_IN, Variant::COLOR, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<NodePath>>(Variant::OP_IN, Variant::NODE_PATH, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHasObject>(Variant::OP_IN, Variant::OBJECT, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Callable>>(Variant::OP_IN, Variant::CALLABLE, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Signal>>(Variant::OP_IN, Variant::SIGNAL, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Dictionary>>(Variant::OP_IN, Variant::DICTIONARY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Array>>(Variant::OP_IN, Variant::ARRAY, Variant::DICTIONARY);
+
+ register_op<OperatorEvaluatorInDictionaryHas<PackedByteArray>>(Variant::OP_IN, Variant::PACKED_BYTE_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedInt32Array>>(Variant::OP_IN, Variant::PACKED_INT32_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedInt64Array>>(Variant::OP_IN, Variant::PACKED_INT64_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedFloat32Array>>(Variant::OP_IN, Variant::PACKED_FLOAT32_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedFloat64Array>>(Variant::OP_IN, Variant::PACKED_FLOAT64_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedStringArray>>(Variant::OP_IN, Variant::PACKED_STRING_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedVector2Array>>(Variant::OP_IN, Variant::PACKED_VECTOR2_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedVector3Array>>(Variant::OP_IN, Variant::PACKED_VECTOR3_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedColorArray>>(Variant::OP_IN, Variant::PACKED_COLOR_ARRAY, Variant::DICTIONARY);
+
+ register_op<OperatorEvaluatorInArrayFindNil>(Variant::OP_IN, Variant::NIL, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<bool, Array>>(Variant::OP_IN, Variant::BOOL, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<int64_t, Array>>(Variant::OP_IN, Variant::INT, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<double, Array>>(Variant::OP_IN, Variant::FLOAT, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<String, Array>>(Variant::OP_IN, Variant::STRING, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector2, Array>>(Variant::OP_IN, Variant::VECTOR2, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector2i, Array>>(Variant::OP_IN, Variant::VECTOR2I, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Rect2, Array>>(Variant::OP_IN, Variant::RECT2, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Rect2i, Array>>(Variant::OP_IN, Variant::RECT2I, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector3, Array>>(Variant::OP_IN, Variant::VECTOR3, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector3i, Array>>(Variant::OP_IN, Variant::VECTOR3I, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Transform2D, Array>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Plane, Array>>(Variant::OP_IN, Variant::PLANE, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Quat, Array>>(Variant::OP_IN, Variant::QUAT, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<AABB, Array>>(Variant::OP_IN, Variant::AABB, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Basis, Array>>(Variant::OP_IN, Variant::BASIS, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Transform, Array>>(Variant::OP_IN, Variant::TRANSFORM, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<Color, Array>>(Variant::OP_IN, Variant::COLOR, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<StringName, Array>>(Variant::OP_IN, Variant::STRING_NAME, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<NodePath, Array>>(Variant::OP_IN, Variant::NODE_PATH, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFindObject>(Variant::OP_IN, Variant::OBJECT, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Callable, Array>>(Variant::OP_IN, Variant::CALLABLE, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Signal, Array>>(Variant::OP_IN, Variant::SIGNAL, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Dictionary, Array>>(Variant::OP_IN, Variant::DICTIONARY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Array, Array>>(Variant::OP_IN, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<PackedByteArray, Array>>(Variant::OP_IN, Variant::PACKED_BYTE_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedInt32Array, Array>>(Variant::OP_IN, Variant::PACKED_INT32_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedInt64Array, Array>>(Variant::OP_IN, Variant::PACKED_INT64_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedFloat32Array, Array>>(Variant::OP_IN, Variant::PACKED_FLOAT32_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedFloat64Array, Array>>(Variant::OP_IN, Variant::PACKED_FLOAT64_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedStringArray, Array>>(Variant::OP_IN, Variant::PACKED_STRING_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedVector2Array, Array>>(Variant::OP_IN, Variant::PACKED_VECTOR2_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedVector3Array, Array>>(Variant::OP_IN, Variant::PACKED_VECTOR3_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedColorArray, Array>>(Variant::OP_IN, Variant::PACKED_COLOR_ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedByteArray>>(Variant::OP_IN, Variant::INT, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedByteArray>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_BYTE_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedInt32Array>>(Variant::OP_IN, Variant::INT, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedInt32Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_INT32_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedInt64Array>>(Variant::OP_IN, Variant::INT, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedInt64Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_INT64_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedFloat32Array>>(Variant::OP_IN, Variant::INT, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedFloat32Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_FLOAT32_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedFloat64Array>>(Variant::OP_IN, Variant::INT, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedFloat64Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_FLOAT64_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<String, PackedStringArray>>(Variant::OP_IN, Variant::STRING, Variant::PACKED_STRING_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<Vector2, PackedVector2Array>>(Variant::OP_IN, Variant::VECTOR2, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector3, PackedVector3Array>>(Variant::OP_IN, Variant::VECTOR3, Variant::PACKED_VECTOR3_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<Color, PackedColorArray>>(Variant::OP_IN, Variant::COLOR, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorObjectHasPropertyString>(Variant::OP_IN, Variant::STRING, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectHasPropertyStringName>(Variant::OP_IN, Variant::STRING_NAME, Variant::OBJECT);
+}
+
+void unregister_variant_operators() {
+}
+
+void Variant::evaluate(const Operator &p_op, const Variant &p_a,
+ const Variant &p_b, Variant &r_ret, bool &r_valid) {
+ ERR_FAIL_INDEX(p_op, Variant::OP_MAX);
+ Variant::Type type_a = p_a.get_type();
+ Variant::Type type_b = p_b.get_type();
+ ERR_FAIL_INDEX(type_a, Variant::VARIANT_MAX);
+ ERR_FAIL_INDEX(type_b, Variant::VARIANT_MAX);
+
+ VariantEvaluatorFunction ev = operator_evaluator_table[p_op][type_a][type_b];
+ if (unlikely(!ev)) {
+ r_valid = false;
+ r_ret = Variant();
+ return;
+ }
+
+ ev(p_a, p_b, &r_ret, r_valid);
+}
+
+Variant::Type Variant::get_operator_return_type(Operator p_operator, Type p_type_a, Type p_type_b) {
+ ERR_FAIL_INDEX_V(p_operator, Variant::OP_MAX, Variant::NIL);
+ ERR_FAIL_INDEX_V(p_type_a, Variant::VARIANT_MAX, Variant::NIL);
+ ERR_FAIL_INDEX_V(p_type_b, Variant::VARIANT_MAX, Variant::NIL);
+
+ return operator_return_type_table[p_operator][p_type_a][p_type_b];
+}
+
+Variant::ValidatedOperatorEvaluator Variant::get_validated_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b) {
+ ERR_FAIL_INDEX_V(p_operator, Variant::OP_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_type_a, Variant::VARIANT_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_type_b, Variant::VARIANT_MAX, nullptr);
+ return validated_operator_evaluator_table[p_operator][p_type_a][p_type_b];
+}
+#ifdef PTRCALL_ENABLED
+Variant::PTROperatorEvaluator Variant::get_ptr_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b) {
+ ERR_FAIL_INDEX_V(p_operator, Variant::OP_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_type_a, Variant::VARIANT_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_type_b, Variant::VARIANT_MAX, nullptr);
+ return ptr_operator_evaluator_table[p_operator][p_type_a][p_type_b];
+}
+
+#endif
+
+static const char *_op_names[Variant::OP_MAX] = {
+ "==",
+ "!=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "+",
+ "-",
+ "*",
+ "/",
+ "- (negation)",
+ "+ (positive)",
+ "%",
+ "<<",
+ ">>",
+ "&",
+ "|",
+ "^",
+ "~",
+ "and",
+ "or",
+ "xor",
+ "not",
+ "in"
+
+};
+
+String Variant::get_operator_name(Operator p_op) {
+ ERR_FAIL_INDEX_V(p_op, OP_MAX, "");
+ return _op_names[p_op];
+}
+
+Variant::operator bool() const {
+ return booleanize();
+}
+
+// We consider all uninitialized or empty types to be false based on the type's
+// zeroiness.
+bool Variant::booleanize() const {
+ return !is_zero();
+}
+
+bool Variant::in(const Variant &p_index, bool *r_valid) const {
+ bool valid;
+ Variant ret;
+ evaluate(OP_IN, p_index, *this, ret, valid);
+ if (r_valid) {
+ *r_valid = valid;
+ return false;
+ }
+ ERR_FAIL_COND_V(ret.type != BOOL, false);
+ return *VariantGetInternalPtr<bool>::get_ptr(&ret);
+}
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
new file mode 100644
index 0000000000..5a0bbf041b
--- /dev/null
+++ b/core/variant/variant_parser.cpp
@@ -0,0 +1,1803 @@
+/*************************************************************************/
+/* variant_parser.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "variant_parser.h"
+
+#include "core/input/input_event.h"
+#include "core/io/resource_loader.h"
+#include "core/os/keyboard.h"
+#include "core/string/string_buffer.h"
+
+char32_t VariantParser::StreamFile::get_char() {
+ return f->get_8();
+}
+
+bool VariantParser::StreamFile::is_utf8() const {
+ return true;
+}
+
+bool VariantParser::StreamFile::is_eof() const {
+ return f->eof_reached();
+}
+
+char32_t VariantParser::StreamString::get_char() {
+ if (pos > s.length()) {
+ return 0;
+ } else if (pos == s.length()) {
+ // You need to try to read again when you have reached the end for EOF to be reported,
+ // so this works the same as files (like StreamFile does)
+ pos++;
+ return 0;
+ } else {
+ return s[pos++];
+ }
+}
+
+bool VariantParser::StreamString::is_utf8() const {
+ return false;
+}
+
+bool VariantParser::StreamString::is_eof() const {
+ return pos > s.length();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+const char *VariantParser::tk_name[TK_MAX] = {
+ "'{'",
+ "'}'",
+ "'['",
+ "']'",
+ "'('",
+ "')'",
+ "identifier",
+ "string",
+ "string_name",
+ "number",
+ "color",
+ "':'",
+ "','",
+ "'.'",
+ "'='",
+ "EOF",
+ "ERROR"
+};
+
+Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, String &r_err_str) {
+ bool string_name = false;
+
+ while (true) {
+ char32_t cchar;
+ if (p_stream->saved) {
+ cchar = p_stream->saved;
+ p_stream->saved = 0;
+ } else {
+ cchar = p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_token.type = TK_EOF;
+ return OK;
+ }
+ }
+
+ switch (cchar) {
+ case '\n': {
+ line++;
+ break;
+ }
+ case 0: {
+ r_token.type = TK_EOF;
+ return OK;
+ } break;
+ case '{': {
+ r_token.type = TK_CURLY_BRACKET_OPEN;
+ return OK;
+ }
+ case '}': {
+ r_token.type = TK_CURLY_BRACKET_CLOSE;
+ return OK;
+ }
+ case '[': {
+ r_token.type = TK_BRACKET_OPEN;
+ return OK;
+ }
+ case ']': {
+ r_token.type = TK_BRACKET_CLOSE;
+ return OK;
+ }
+ case '(': {
+ r_token.type = TK_PARENTHESIS_OPEN;
+ return OK;
+ }
+ case ')': {
+ r_token.type = TK_PARENTHESIS_CLOSE;
+ return OK;
+ }
+ case ':': {
+ r_token.type = TK_COLON;
+ return OK;
+ }
+ case ';': {
+ while (true) {
+ char32_t ch = p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_token.type = TK_EOF;
+ return OK;
+ }
+ if (ch == '\n') {
+ break;
+ }
+ }
+
+ break;
+ }
+ case ',': {
+ r_token.type = TK_COMMA;
+ return OK;
+ }
+ case '.': {
+ r_token.type = TK_PERIOD;
+ return OK;
+ }
+ case '=': {
+ r_token.type = TK_EQUAL;
+ return OK;
+ }
+ case '#': {
+ StringBuffer<> color_str;
+ color_str += '#';
+ while (true) {
+ char32_t ch = p_stream->get_char();
+ 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')) {
+ color_str += ch;
+
+ } else {
+ p_stream->saved = ch;
+ break;
+ }
+ }
+
+ r_token.value = Color::html(color_str.as_string());
+ r_token.type = TK_COLOR;
+ return OK;
+ }
+ case '@': {
+ cchar = p_stream->get_char();
+ if (cchar != '"') {
+ r_err_str = "Expected '\"' after '@'";
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+
+ string_name = true;
+ [[fallthrough]];
+ }
+ case '"': {
+ String str;
+ while (true) {
+ char32_t ch = p_stream->get_char();
+
+ if (ch == 0) {
+ r_err_str = "Unterminated String";
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ } else if (ch == '"') {
+ break;
+ } else if (ch == '\\') {
+ //escaped characters...
+ char32_t next = p_stream->get_char();
+ if (next == 0) {
+ r_err_str = "Unterminated String";
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ char32_t res = 0;
+
+ switch (next) {
+ case 'b':
+ res = 8;
+ break;
+ case 't':
+ res = 9;
+ break;
+ case 'n':
+ res = 10;
+ break;
+ case 'f':
+ res = 12;
+ break;
+ case 'r':
+ res = 13;
+ break;
+ case 'u': {
+ //hex number
+ for (int j = 0; j < 4; 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'))) {
+ 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') {
+ v = c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ v = c - 'a';
+ v += 10;
+ } else if (c >= 'A' && c <= 'F') {
+ v = c - 'A';
+ v += 10;
+ } else {
+ ERR_PRINT("Bug parsing hex constant.");
+ v = 0;
+ }
+
+ res <<= 4;
+ res |= v;
+ }
+
+ } break;
+ default: {
+ res = next;
+ } break;
+ }
+
+ str += res;
+
+ } else {
+ if (ch == '\n') {
+ line++;
+ }
+ str += ch;
+ }
+ }
+
+ if (p_stream->is_utf8()) {
+ str.parse_utf8(str.ascii(true).get_data());
+ }
+ if (string_name) {
+ r_token.type = TK_STRING_NAME;
+ r_token.value = StringName(str);
+ string_name = false; //reset
+ } else {
+ r_token.type = TK_STRING;
+ r_token.value = str;
+ }
+ return OK;
+
+ } break;
+ default: {
+ if (cchar <= 32) {
+ break;
+ }
+
+ if (cchar == '-' || (cchar >= '0' && cchar <= '9')) {
+ //a number
+
+ StringBuffer<> num;
+#define READING_SIGN 0
+#define READING_INT 1
+#define READING_DEC 2
+#define READING_EXP 3
+#define READING_DONE 4
+ int reading = READING_INT;
+
+ if (cchar == '-') {
+ num += '-';
+ cchar = p_stream->get_char();
+ }
+
+ char32_t c = cchar;
+ bool exp_sign = false;
+ bool exp_beg = false;
+ bool is_float = false;
+
+ while (true) {
+ switch (reading) {
+ case READING_INT: {
+ if (c >= '0' && c <= '9') {
+ //pass
+ } else if (c == '.') {
+ reading = READING_DEC;
+ is_float = true;
+ } else if (c == 'e') {
+ reading = READING_EXP;
+ is_float = true;
+ } else {
+ reading = READING_DONE;
+ }
+
+ } break;
+ case READING_DEC: {
+ if (c >= '0' && c <= '9') {
+ } else if (c == 'e') {
+ reading = READING_EXP;
+ } else {
+ reading = READING_DONE;
+ }
+
+ } break;
+ case READING_EXP: {
+ if (c >= '0' && c <= '9') {
+ exp_beg = true;
+
+ } else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) {
+ exp_sign = true;
+
+ } else {
+ reading = READING_DONE;
+ }
+ } break;
+ }
+
+ if (reading == READING_DONE) {
+ break;
+ }
+ num += c;
+ c = p_stream->get_char();
+ }
+
+ p_stream->saved = c;
+
+ r_token.type = TK_NUMBER;
+
+ if (is_float) {
+ r_token.value = num.as_double();
+ } else {
+ r_token.value = num.as_int();
+ }
+ return OK;
+
+ } else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') {
+ StringBuffer<> id;
+ bool first = true;
+
+ while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) {
+ id += cchar;
+ cchar = p_stream->get_char();
+ first = false;
+ }
+
+ p_stream->saved = cchar;
+
+ r_token.type = TK_IDENTIFIER;
+ r_token.value = id.as_string();
+ return OK;
+ } else {
+ r_err_str = "Unexpected character.";
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ }
+ }
+ }
+
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+}
+
+Error VariantParser::_parse_enginecfg(Stream *p_stream, Vector<String> &strings, int &line, String &r_err_str) {
+ Token token;
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_OPEN) {
+ r_err_str = "Expected '(' in old-style project.godot construct";
+ return ERR_PARSE_ERROR;
+ }
+
+ String accum;
+
+ while (true) {
+ char32_t c = p_stream->get_char();
+
+ if (p_stream->is_eof()) {
+ r_err_str = "Unexpected EOF while parsing old-style project.godot construct";
+ return ERR_PARSE_ERROR;
+ }
+
+ if (c == ',') {
+ strings.push_back(accum.strip_edges());
+ accum = String();
+ } else if (c == ')') {
+ strings.push_back(accum.strip_edges());
+ return OK;
+ } else if (c == '\n') {
+ line++;
+ }
+ }
+}
+
+template <class T>
+Error VariantParser::_parse_construct(Stream *p_stream, Vector<T> &r_construct, int &line, String &r_err_str) {
+ Token token;
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_OPEN) {
+ r_err_str = "Expected '(' in constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ bool first = true;
+ while (true) {
+ if (!first) {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type == TK_COMMA) {
+ //do none
+ } else if (token.type == TK_PARENTHESIS_CLOSE) {
+ break;
+ } else {
+ r_err_str = "Expected ',' or ')' in constructor";
+ return ERR_PARSE_ERROR;
+ }
+ }
+ get_token(p_stream, token, line, r_err_str);
+
+ 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;
+ }
+
+ r_construct.push_back(token.value);
+ first = false;
+ }
+
+ return OK;
+}
+
+Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
+ if (token.type == TK_CURLY_BRACKET_OPEN) {
+ Dictionary d;
+ Error err = _parse_dictionary(d, p_stream, line, r_err_str, p_res_parser);
+ if (err) {
+ return err;
+ }
+ value = d;
+ return OK;
+ } else if (token.type == TK_BRACKET_OPEN) {
+ Array a;
+ Error err = _parse_array(a, p_stream, line, r_err_str, p_res_parser);
+ if (err) {
+ return err;
+ }
+ value = a;
+ return OK;
+ } else if (token.type == TK_IDENTIFIER) {
+ String id = token.value;
+ if (id == "true") {
+ value = true;
+ } else if (id == "false") {
+ value = false;
+ } else if (id == "null" || id == "nil") {
+ value = Variant();
+ } else if (id == "inf") {
+ value = Math_INF;
+ } else if (id == "nan") {
+ value = Math_NAN;
+ } else if (id == "Vector2") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 2) {
+ r_err_str = "Expected 2 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Vector2(args[0], args[1]);
+ } else if (id == "Vector2i") {
+ Vector<int32_t> args;
+ Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 2) {
+ r_err_str = "Expected 2 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Vector2i(args[0], args[1]);
+ } else if (id == "Rect2") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 4) {
+ r_err_str = "Expected 4 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Rect2(args[0], args[1], args[2], args[3]);
+ } else if (id == "Rect2i") {
+ Vector<int32_t> args;
+ Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 4) {
+ r_err_str = "Expected 4 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Rect2i(args[0], args[1], args[2], args[3]);
+ } else if (id == "Vector3") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 3) {
+ r_err_str = "Expected 3 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Vector3(args[0], args[1], args[2]);
+ } else if (id == "Vector3i") {
+ Vector<int32_t> args;
+ Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 3) {
+ r_err_str = "Expected 3 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Vector3i(args[0], args[1], args[2]);
+ } else if (id == "Transform2D" || id == "Matrix32") { //compatibility
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 6) {
+ r_err_str = "Expected 6 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ Transform2D m;
+ m[0] = Vector2(args[0], args[1]);
+ m[1] = Vector2(args[2], args[3]);
+ m[2] = Vector2(args[4], args[5]);
+ value = m;
+ } else if (id == "Plane") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 4) {
+ r_err_str = "Expected 4 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Plane(args[0], args[1], args[2], args[3]);
+ } else if (id == "Quat") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 4) {
+ r_err_str = "Expected 4 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Quat(args[0], args[1], args[2], args[3]);
+ } else if (id == "AABB" || id == "Rect3") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 6) {
+ r_err_str = "Expected 6 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = AABB(Vector3(args[0], args[1], args[2]), Vector3(args[3], args[4], args[5]));
+ } else if (id == "Basis" || id == "Matrix3") { //compatibility
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 9) {
+ r_err_str = "Expected 9 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
+ } else if (id == "Transform") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 12) {
+ r_err_str = "Expected 12 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Transform(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11]));
+ } else if (id == "Color") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (args.size() != 4) {
+ r_err_str = "Expected 4 arguments for constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = Color(args[0], args[1], args[2], args[3]);
+ } else if (id == "NodePath") {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_OPEN) {
+ r_err_str = "Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_STRING) {
+ r_err_str = "Expected string as argument for NodePath()";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = NodePath(String(token.value));
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_CLOSE) {
+ r_err_str = "Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+ } else if (id == "RID") {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_OPEN) {
+ r_err_str = "Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_NUMBER) {
+ r_err_str = "Expected number as argument";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = token.value;
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_CLOSE) {
+ r_err_str = "Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+ } else if (id == "Object") {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_OPEN) {
+ r_err_str = "Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream, token, line, r_err_str);
+
+ if (token.type != TK_IDENTIFIER) {
+ r_err_str = "Expected identifier with type of object";
+ return ERR_PARSE_ERROR;
+ }
+
+ String type = token.value;
+
+ Object *obj = ClassDB::instance(type);
+
+ if (!obj) {
+ r_err_str = "Can't instance Object() of type: " + type;
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_COMMA) {
+ r_err_str = "Expected ',' after object type";
+ return ERR_PARSE_ERROR;
+ }
+
+ bool at_key = true;
+ String key;
+ Token token2;
+ bool need_comma = false;
+
+ while (true) {
+ if (p_stream->is_eof()) {
+ r_err_str = "Unexpected End of File while parsing Object()";
+ return ERR_FILE_CORRUPT;
+ }
+
+ if (at_key) {
+ Error err = get_token(p_stream, token2, line, r_err_str);
+ if (err != OK) {
+ return err;
+ }
+
+ if (token2.type == TK_PARENTHESIS_CLOSE) {
+ Reference *reference = Object::cast_to<Reference>(obj);
+ if (reference) {
+ value = REF(reference);
+ } else {
+ value = obj;
+ }
+ return OK;
+ }
+
+ if (need_comma) {
+ if (token2.type != TK_COMMA) {
+ r_err_str = "Expected '}' or ','";
+ return ERR_PARSE_ERROR;
+ } else {
+ need_comma = false;
+ continue;
+ }
+ }
+
+ if (token2.type != TK_STRING) {
+ r_err_str = "Expected property name as string";
+ return ERR_PARSE_ERROR;
+ }
+
+ key = token2.value;
+
+ err = get_token(p_stream, token2, line, r_err_str);
+
+ if (err != OK) {
+ return err;
+ }
+ if (token2.type != TK_COLON) {
+ r_err_str = "Expected ':'";
+ return ERR_PARSE_ERROR;
+ }
+ at_key = false;
+ } else {
+ Error err = get_token(p_stream, token2, line, r_err_str);
+ if (err != OK) {
+ return err;
+ }
+
+ Variant v;
+ err = parse_value(token2, v, p_stream, line, r_err_str, p_res_parser);
+ if (err) {
+ return err;
+ }
+ obj->set(key, v);
+ need_comma = true;
+ at_key = true;
+ }
+ }
+ } else if (id == "Resource" || id == "SubResource" || id == "ExtResource") {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_OPEN) {
+ r_err_str = "Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ if (p_res_parser && id == "Resource" && p_res_parser->func) {
+ RES res;
+ Error err = p_res_parser->func(p_res_parser->userdata, p_stream, res, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ value = res;
+ } else if (p_res_parser && id == "ExtResource" && p_res_parser->ext_func) {
+ RES res;
+ Error err = p_res_parser->ext_func(p_res_parser->userdata, p_stream, res, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ value = res;
+ } else if (p_res_parser && id == "SubResource" && p_res_parser->sub_func) {
+ RES res;
+ Error err = p_res_parser->sub_func(p_res_parser->userdata, p_stream, res, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ value = res;
+ } else {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type == TK_STRING) {
+ String path = token.value;
+ RES res = ResourceLoader::load(path);
+ if (res.is_null()) {
+ r_err_str = "Can't load resource at path: '" + path + "'.";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_CLOSE) {
+ r_err_str = "Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+ value = res;
+ } else {
+ r_err_str = "Expected string as argument for Resource().";
+ return ERR_PARSE_ERROR;
+ }
+ }
+ } else if (id == "PackedByteArray" || id == "PoolByteArray" || id == "ByteArray") {
+ Vector<uint8_t> args;
+ Error err = _parse_construct<uint8_t>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ Vector<uint8_t> arr;
+ {
+ int len = args.size();
+ arr.resize(len);
+ uint8_t *w = arr.ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i] = args[i];
+ }
+ }
+
+ value = arr;
+ } else if (id == "PackedInt32Array" || id == "PackedIntArray" || id == "PoolIntArray" || id == "IntArray") {
+ Vector<int32_t> args;
+ Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ Vector<int32_t> arr;
+ {
+ int32_t len = args.size();
+ arr.resize(len);
+ int32_t *w = arr.ptrw();
+ for (int32_t i = 0; i < len; i++) {
+ w[i] = int32_t(args[i]);
+ }
+ }
+
+ value = arr;
+ } else if (id == "PackedInt64Array") {
+ Vector<int64_t> args;
+ Error err = _parse_construct<int64_t>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ Vector<int64_t> arr;
+ {
+ int64_t len = args.size();
+ arr.resize(len);
+ int64_t *w = arr.ptrw();
+ for (int64_t i = 0; i < len; i++) {
+ w[i] = int64_t(args[i]);
+ }
+ }
+
+ value = arr;
+ } else if (id == "PackedFloat32Array" || id == "PackedRealArray" || id == "PoolRealArray" || id == "FloatArray") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ Vector<float> arr;
+ {
+ int len = args.size();
+ arr.resize(len);
+ float *w = arr.ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i] = args[i];
+ }
+ }
+
+ value = arr;
+ } else if (id == "PackedFloat64Array") {
+ Vector<double> args;
+ Error err = _parse_construct<double>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ Vector<double> arr;
+ {
+ int len = args.size();
+ arr.resize(len);
+ double *w = arr.ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i] = args[i];
+ }
+ }
+
+ value = arr;
+ } else if (id == "PackedStringArray" || id == "PoolStringArray" || id == "StringArray") {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_OPEN) {
+ r_err_str = "Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ Vector<String> cs;
+
+ bool first = true;
+ while (true) {
+ if (!first) {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type == TK_COMMA) {
+ //do none
+ } else if (token.type == TK_PARENTHESIS_CLOSE) {
+ break;
+ } else {
+ r_err_str = "Expected ',' or ')'";
+ return ERR_PARSE_ERROR;
+ }
+ }
+ get_token(p_stream, token, line, r_err_str);
+
+ if (token.type == TK_PARENTHESIS_CLOSE) {
+ break;
+ } else if (token.type != TK_STRING) {
+ r_err_str = "Expected string";
+ return ERR_PARSE_ERROR;
+ }
+
+ first = false;
+ cs.push_back(token.value);
+ }
+
+ Vector<String> arr;
+ {
+ int len = cs.size();
+ arr.resize(len);
+ String *w = arr.ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i] = cs[i];
+ }
+ }
+
+ value = arr;
+ } else if (id == "PackedVector2Array" || id == "PoolVector2Array" || id == "Vector2Array") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ Vector<Vector2> arr;
+ {
+ int len = args.size() / 2;
+ arr.resize(len);
+ Vector2 *w = arr.ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i] = Vector2(args[i * 2 + 0], args[i * 2 + 1]);
+ }
+ }
+
+ value = arr;
+ } else if (id == "PackedVector3Array" || id == "PoolVector3Array" || id == "Vector3Array") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ Vector<Vector3> arr;
+ {
+ int len = args.size() / 3;
+ arr.resize(len);
+ Vector3 *w = arr.ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i] = Vector3(args[i * 3 + 0], args[i * 3 + 1], args[i * 3 + 2]);
+ }
+ }
+
+ value = arr;
+ } else if (id == "PackedColorArray" || id == "PoolColorArray" || id == "ColorArray") {
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ Vector<Color> arr;
+ {
+ int len = args.size() / 4;
+ arr.resize(len);
+ Color *w = arr.ptrw();
+ for (int i = 0; i < len; i++) {
+ w[i] = Color(args[i * 4 + 0], args[i * 4 + 1], args[i * 4 + 2], args[i * 4 + 3]);
+ }
+ }
+
+ value = arr;
+ } else {
+ r_err_str = "Unexpected identifier: '" + id + "'.";
+ return ERR_PARSE_ERROR;
+ }
+
+ // All above branches end up here unless they had an early return.
+ return OK;
+ } else if (token.type == TK_NUMBER) {
+ value = token.value;
+ return OK;
+ } else if (token.type == TK_STRING) {
+ value = token.value;
+ return OK;
+ } else if (token.type == TK_STRING_NAME) {
+ value = token.value;
+ return OK;
+ } else if (token.type == TK_COLOR) {
+ value = token.value;
+ return OK;
+ } else {
+ r_err_str = "Expected value, got " + String(tk_name[token.type]) + ".";
+ return ERR_PARSE_ERROR;
+ }
+}
+
+Error VariantParser::_parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
+ Token token;
+ bool need_comma = false;
+
+ while (true) {
+ if (p_stream->is_eof()) {
+ r_err_str = "Unexpected End of File while parsing array";
+ return ERR_FILE_CORRUPT;
+ }
+
+ Error err = get_token(p_stream, token, line, r_err_str);
+ if (err != OK) {
+ return err;
+ }
+
+ if (token.type == TK_BRACKET_CLOSE) {
+ return OK;
+ }
+
+ if (need_comma) {
+ if (token.type != TK_COMMA) {
+ r_err_str = "Expected ','";
+ return ERR_PARSE_ERROR;
+ } else {
+ need_comma = false;
+ continue;
+ }
+ }
+
+ Variant v;
+ err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser);
+ if (err) {
+ return err;
+ }
+
+ array.push_back(v);
+ need_comma = true;
+ }
+}
+
+Error VariantParser::_parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
+ bool at_key = true;
+ Variant key;
+ Token token;
+ bool need_comma = false;
+
+ while (true) {
+ if (p_stream->is_eof()) {
+ r_err_str = "Unexpected End of File while parsing dictionary";
+ return ERR_FILE_CORRUPT;
+ }
+
+ if (at_key) {
+ Error err = get_token(p_stream, token, line, r_err_str);
+ if (err != OK) {
+ return err;
+ }
+
+ if (token.type == TK_CURLY_BRACKET_CLOSE) {
+ return OK;
+ }
+
+ if (need_comma) {
+ if (token.type != TK_COMMA) {
+ r_err_str = "Expected '}' or ','";
+ return ERR_PARSE_ERROR;
+ } else {
+ need_comma = false;
+ continue;
+ }
+ }
+
+ err = parse_value(token, key, p_stream, line, r_err_str, p_res_parser);
+
+ if (err) {
+ return err;
+ }
+
+ err = get_token(p_stream, token, line, r_err_str);
+
+ if (err != OK) {
+ return err;
+ }
+ if (token.type != TK_COLON) {
+ r_err_str = "Expected ':'";
+ return ERR_PARSE_ERROR;
+ }
+ at_key = false;
+ } else {
+ Error err = get_token(p_stream, token, line, r_err_str);
+ if (err != OK) {
+ return err;
+ }
+
+ Variant v;
+ err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser);
+ if (err) {
+ return err;
+ }
+ object[key] = v;
+ need_comma = true;
+ at_key = true;
+ }
+ }
+}
+
+Error VariantParser::_parse_tag(Token &token, Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser, bool p_simple_tag) {
+ r_tag.fields.clear();
+
+ if (token.type != TK_BRACKET_OPEN) {
+ r_err_str = "Expected '['";
+ return ERR_PARSE_ERROR;
+ }
+
+ if (p_simple_tag) {
+ r_tag.name = "";
+ r_tag.fields.clear();
+
+ while (true) {
+ char32_t c = p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_err_str = "Unexpected EOF while parsing simple tag";
+ return ERR_PARSE_ERROR;
+ }
+ if (c == ']') {
+ break;
+ }
+ r_tag.name += String::chr(c);
+ }
+
+ r_tag.name = r_tag.name.strip_edges();
+
+ return OK;
+ }
+
+ get_token(p_stream, token, line, r_err_str);
+
+ if (token.type != TK_IDENTIFIER) {
+ r_err_str = "Expected identifier (tag name)";
+ return ERR_PARSE_ERROR;
+ }
+
+ r_tag.name = token.value;
+ bool parsing_tag = true;
+
+ while (true) {
+ if (p_stream->is_eof()) {
+ r_err_str = "Unexpected End of File while parsing tag: " + r_tag.name;
+ return ERR_FILE_CORRUPT;
+ }
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type == TK_BRACKET_CLOSE) {
+ break;
+ }
+
+ if (parsing_tag && token.type == TK_PERIOD) {
+ r_tag.name += "."; //support tags such as [someprop.Android] for specific platforms
+ get_token(p_stream, token, line, r_err_str);
+ } else if (parsing_tag && token.type == TK_COLON) {
+ r_tag.name += ":"; //support tags such as [someprop.Android] for specific platforms
+ get_token(p_stream, token, line, r_err_str);
+ } else {
+ parsing_tag = false;
+ }
+
+ if (token.type != TK_IDENTIFIER) {
+ r_err_str = "Expected Identifier";
+ return ERR_PARSE_ERROR;
+ }
+
+ String id = token.value;
+
+ if (parsing_tag) {
+ r_tag.name += id;
+ continue;
+ }
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_EQUAL) {
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream, token, line, r_err_str);
+ Variant value;
+ Error err = parse_value(token, value, p_stream, line, r_err_str, p_res_parser);
+ if (err) {
+ return err;
+ }
+
+ r_tag.fields[id] = value;
+ }
+
+ return OK;
+}
+
+Error VariantParser::parse_tag(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser, bool p_simple_tag) {
+ Token token;
+ get_token(p_stream, token, line, r_err_str);
+
+ if (token.type == TK_EOF) {
+ return ERR_FILE_EOF;
+ }
+
+ if (token.type != TK_BRACKET_OPEN) {
+ r_err_str = "Expected '['";
+ return ERR_PARSE_ERROR;
+ }
+
+ return _parse_tag(token, p_stream, line, r_err_str, r_tag, p_res_parser, p_simple_tag);
+}
+
+Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, String &r_assign, Variant &r_value, ResourceParser *p_res_parser, bool p_simple_tag) {
+ //assign..
+ r_assign = "";
+ String what;
+
+ while (true) {
+ char32_t c;
+ if (p_stream->saved) {
+ c = p_stream->saved;
+ p_stream->saved = 0;
+
+ } else {
+ c = p_stream->get_char();
+ }
+
+ if (p_stream->is_eof()) {
+ return ERR_FILE_EOF;
+ }
+
+ if (c == ';') { //comment
+ while (true) {
+ char32_t ch = p_stream->get_char();
+ if (p_stream->is_eof()) {
+ return ERR_FILE_EOF;
+ }
+ if (ch == '\n') {
+ break;
+ }
+ }
+ continue;
+ }
+
+ if (c == '[' && what.length() == 0) {
+ //it's a tag!
+ p_stream->saved = '['; //go back one
+
+ Error err = parse_tag(p_stream, line, r_err_str, r_tag, p_res_parser, p_simple_tag);
+
+ return err;
+ }
+
+ if (c > 32) {
+ if (c == '"') { //quoted
+ p_stream->saved = '"';
+ Token tk;
+ Error err = get_token(p_stream, tk, line, r_err_str);
+ if (err) {
+ return err;
+ }
+ if (tk.type != TK_STRING) {
+ r_err_str = "Error reading quoted string";
+ return ERR_INVALID_DATA;
+ }
+
+ what = tk.value;
+
+ } else if (c != '=') {
+ what += String::chr(c);
+ } else {
+ r_assign = what;
+ Token token;
+ get_token(p_stream, token, line, r_err_str);
+ Error err = parse_value(token, r_value, p_stream, line, r_err_str, p_res_parser);
+ return err;
+ }
+ } else if (c == '\n') {
+ line++;
+ }
+ }
+}
+
+Error VariantParser::parse(Stream *p_stream, Variant &r_ret, String &r_err_str, int &r_err_line, ResourceParser *p_res_parser) {
+ Token token;
+ Error err = get_token(p_stream, token, r_err_line, r_err_str);
+ if (err) {
+ return err;
+ }
+
+ if (token.type == TK_EOF) {
+ return ERR_FILE_EOF;
+ }
+
+ return parse_value(token, r_ret, p_stream, r_err_line, r_err_str, p_res_parser);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+static String rtosfix(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 {
+ 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) {
+ switch (p_variant.get_type()) {
+ case Variant::NIL: {
+ p_store_string_func(p_store_string_ud, "null");
+ } break;
+ case Variant::BOOL: {
+ p_store_string_func(p_store_string_ud, p_variant.operator bool() ? "true" : "false");
+ } break;
+ case Variant::INT: {
+ p_store_string_func(p_store_string_ud, itos(p_variant.operator int64_t()));
+ } break;
+ case Variant::FLOAT: {
+ String s = rtosfix(p_variant.operator real_t());
+ if (s != "inf" && s != "nan") {
+ if (s.find(".") == -1 && s.find("e") == -1) {
+ s += ".0";
+ }
+ }
+ p_store_string_func(p_store_string_ud, s);
+ } break;
+ case Variant::STRING: {
+ String str = p_variant;
+
+ str = "\"" + str.c_escape_multiline() + "\"";
+ p_store_string_func(p_store_string_ud, str);
+ } break;
+ case Variant::VECTOR2: {
+ Vector2 v = p_variant;
+ p_store_string_func(p_store_string_ud, "Vector2( " + rtosfix(v.x) + ", " + rtosfix(v.y) + " )");
+ } break;
+ case Variant::VECTOR2I: {
+ Vector2i v = p_variant;
+ p_store_string_func(p_store_string_ud, "Vector2i( " + itos(v.x) + ", " + itos(v.y) + " )");
+ } break;
+ case Variant::RECT2: {
+ Rect2 aabb = p_variant;
+ p_store_string_func(p_store_string_ud, "Rect2( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + " )");
+
+ } break;
+ case Variant::RECT2I: {
+ Rect2i aabb = p_variant;
+ p_store_string_func(p_store_string_ud, "Rect2i( " + itos(aabb.position.x) + ", " + itos(aabb.position.y) + ", " + itos(aabb.size.x) + ", " + itos(aabb.size.y) + " )");
+
+ } break;
+ case Variant::VECTOR3: {
+ Vector3 v = p_variant;
+ p_store_string_func(p_store_string_ud, "Vector3( " + rtosfix(v.x) + ", " + rtosfix(v.y) + ", " + rtosfix(v.z) + " )");
+ } break;
+ case Variant::VECTOR3I: {
+ Vector3i v = p_variant;
+ p_store_string_func(p_store_string_ud, "Vector3i( " + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + " )");
+ } break;
+ case Variant::PLANE: {
+ Plane p = p_variant;
+ p_store_string_func(p_store_string_ud, "Plane( " + rtosfix(p.normal.x) + ", " + rtosfix(p.normal.y) + ", " + rtosfix(p.normal.z) + ", " + rtosfix(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) + " )");
+
+ } break;
+ case Variant::QUAT: {
+ Quat quat = p_variant;
+ p_store_string_func(p_store_string_ud, "Quat( " + rtosfix(quat.x) + ", " + rtosfix(quat.y) + ", " + rtosfix(quat.z) + ", " + rtosfix(quat.w) + " )");
+
+ } break;
+ case Variant::TRANSFORM2D: {
+ String s = "Transform2D( ";
+ Transform2D m3 = p_variant;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 2; j++) {
+ if (i != 0 || j != 0) {
+ s += ", ";
+ }
+ s += rtosfix(m3.elements[i][j]);
+ }
+ }
+
+ p_store_string_func(p_store_string_ud, s + " )");
+
+ } break;
+ case Variant::BASIS: {
+ String s = "Basis( ";
+ Basis m3 = p_variant;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (i != 0 || j != 0) {
+ s += ", ";
+ }
+ s += rtosfix(m3.elements[i][j]);
+ }
+ }
+
+ p_store_string_func(p_store_string_ud, s + " )");
+
+ } break;
+ case Variant::TRANSFORM: {
+ String s = "Transform( ";
+ Transform t = p_variant;
+ Basis &m3 = t.basis;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (i != 0 || j != 0) {
+ s += ", ";
+ }
+ s += rtosfix(m3.elements[i][j]);
+ }
+ }
+
+ s = s + ", " + rtosfix(t.origin.x) + ", " + rtosfix(t.origin.y) + ", " + rtosfix(t.origin.z);
+
+ p_store_string_func(p_store_string_ud, s + " )");
+ } break;
+
+ // 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) + " )");
+
+ } break;
+ case Variant::STRING_NAME: {
+ String str = p_variant;
+
+ str = "@\"" + str.c_escape() + "\"";
+ p_store_string_func(p_store_string_ud, str);
+
+ } break;
+ case Variant::NODE_PATH: {
+ String str = p_variant;
+
+ str = "NodePath(\"" + str.c_escape() + "\")";
+ p_store_string_func(p_store_string_ud, str);
+
+ } break;
+
+ case Variant::OBJECT: {
+ Object *obj = p_variant;
+
+ if (!obj) {
+ p_store_string_func(p_store_string_ud, "null");
+ break; // don't save it
+ }
+
+ RES res = p_variant;
+ if (res.is_valid()) {
+ //is resource
+ String res_text;
+
+ //try external function
+ if (p_encode_res_func) {
+ res_text = p_encode_res_func(p_encode_res_ud, res);
+ }
+
+ //try path because it's a file
+ if (res_text == String() && 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()) {
+ p_store_string_func(p_store_string_ud, res_text);
+ break;
+ }
+ }
+
+ //store as generic object
+
+ p_store_string_func(p_store_string_ud, "Object(" + obj->get_class() + ",");
+
+ List<PropertyInfo> props;
+ obj->get_property_list(&props);
+ bool first = true;
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ if (E->get().usage & PROPERTY_USAGE_STORAGE || E->get().usage & PROPERTY_USAGE_SCRIPT_VARIABLE) {
+ //must be serialized
+
+ if (first) {
+ first = false;
+ } else {
+ p_store_string_func(p_store_string_ud, ",");
+ }
+
+ p_store_string_func(p_store_string_ud, "\"" + E->get().name + "\":");
+ write(obj->get(E->get().name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud);
+ }
+ }
+
+ p_store_string_func(p_store_string_ud, ")\n");
+
+ } break;
+
+ case Variant::DICTIONARY: {
+ Dictionary dict = p_variant;
+
+ 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->get()]))
+ 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");
+ }
+ }
+
+ 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, ", ");
+ }
+ 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, " ]");
+
+ } break;
+
+ case Variant::PACKED_BYTE_ARRAY: {
+ p_store_string_func(p_store_string_ud, "PackedByteArray( ");
+ String s;
+ Vector<uint8_t> data = p_variant;
+ int len = data.size();
+ const uint8_t *ptr = data.ptr();
+
+ for (int i = 0; i < len; i++) {
+ if (i > 0) {
+ p_store_string_func(p_store_string_ud, ", ");
+ }
+
+ p_store_string_func(p_store_string_ud, itos(ptr[i]));
+ }
+
+ p_store_string_func(p_store_string_ud, " )");
+
+ } break;
+ case Variant::PACKED_INT32_ARRAY: {
+ p_store_string_func(p_store_string_ud, "PackedInt32Array( ");
+ Vector<int32_t> data = p_variant;
+ int32_t len = data.size();
+ const int32_t *ptr = data.ptr();
+
+ for (int32_t i = 0; i < len; i++) {
+ if (i > 0) {
+ p_store_string_func(p_store_string_ud, ", ");
+ }
+
+ p_store_string_func(p_store_string_ud, itos(ptr[i]));
+ }
+
+ p_store_string_func(p_store_string_ud, " )");
+
+ } break;
+ case Variant::PACKED_INT64_ARRAY: {
+ p_store_string_func(p_store_string_ud, "PackedInt64Array( ");
+ Vector<int64_t> data = p_variant;
+ int64_t len = data.size();
+ const int64_t *ptr = data.ptr();
+
+ for (int64_t i = 0; i < len; i++) {
+ if (i > 0) {
+ p_store_string_func(p_store_string_ud, ", ");
+ }
+
+ p_store_string_func(p_store_string_ud, itos(ptr[i]));
+ }
+
+ p_store_string_func(p_store_string_ud, " )");
+
+ } break;
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ p_store_string_func(p_store_string_ud, "PackedFloat32Array( ");
+ Vector<float> data = p_variant;
+ int len = data.size();
+ const float *ptr = data.ptr();
+
+ for (int i = 0; i < len; i++) {
+ 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, " )");
+
+ } break;
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ p_store_string_func(p_store_string_ud, "PackedFloat64Array( ");
+ Vector<double> data = p_variant;
+ int len = data.size();
+ const double *ptr = data.ptr();
+
+ for (int i = 0; i < len; i++) {
+ 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, " )");
+
+ } break;
+ case Variant::PACKED_STRING_ARRAY: {
+ p_store_string_func(p_store_string_ud, "PackedStringArray( ");
+ Vector<String> data = p_variant;
+ int len = data.size();
+ const String *ptr = data.ptr();
+
+ String s;
+ //write_string("\n");
+
+ for (int i = 0; i < len; i++) {
+ if (i > 0) {
+ p_store_string_func(p_store_string_ud, ", ");
+ }
+ String str = ptr[i];
+ p_store_string_func(p_store_string_ud, "\"" + str.c_escape() + "\"");
+ }
+
+ p_store_string_func(p_store_string_ud, " )");
+
+ } break;
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ p_store_string_func(p_store_string_ud, "PackedVector2Array( ");
+ Vector<Vector2> data = p_variant;
+ int len = data.size();
+ const Vector2 *ptr = data.ptr();
+
+ for (int i = 0; i < len; i++) {
+ 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, " )");
+
+ } break;
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ p_store_string_func(p_store_string_ud, "PackedVector3Array( ");
+ Vector<Vector3> data = p_variant;
+ int len = data.size();
+ const Vector3 *ptr = data.ptr();
+
+ for (int i = 0; i < len; i++) {
+ 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, " )");
+
+ } break;
+ case Variant::PACKED_COLOR_ARRAY: {
+ p_store_string_func(p_store_string_ud, "PackedColorArray( ");
+
+ Vector<Color> data = p_variant;
+ int len = data.size();
+ const Color *ptr = data.ptr();
+
+ for (int i = 0; i < len; i++) {
+ if (i > 0) {
+ 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, " )");
+
+ } break;
+ default: {
+ }
+ }
+
+ return OK;
+}
+
+static Error _write_to_str(void *ud, const String &p_string) {
+ String *str = (String *)ud;
+ (*str) += p_string;
+ return OK;
+}
+
+Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud) {
+ r_string = String();
+
+ return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud);
+}
diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h
new file mode 100644
index 0000000000..59d18a8b9f
--- /dev/null
+++ b/core/variant/variant_parser.h
@@ -0,0 +1,148 @@
+/*************************************************************************/
+/* variant_parser.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef VARIANT_PARSER_H
+#define VARIANT_PARSER_H
+
+#include "core/io/resource.h"
+#include "core/os/file_access.h"
+#include "core/variant/variant.h"
+
+class VariantParser {
+public:
+ struct Stream {
+ virtual char32_t get_char() = 0;
+ virtual bool is_utf8() const = 0;
+ virtual bool is_eof() const = 0;
+
+ char32_t saved = 0;
+
+ Stream() {}
+ virtual ~Stream() {}
+ };
+
+ struct StreamFile : public Stream {
+ FileAccess *f = nullptr;
+
+ virtual char32_t get_char();
+ virtual bool is_utf8() const;
+ virtual bool is_eof() const;
+
+ StreamFile() {}
+ };
+
+ struct StreamString : public Stream {
+ String s;
+ int pos = 0;
+
+ virtual char32_t get_char();
+ virtual bool is_utf8() const;
+ virtual bool is_eof() const;
+
+ StreamString() {}
+ };
+
+ typedef Error (*ParseResourceFunc)(void *p_self, Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
+
+ struct ResourceParser {
+ void *userdata = nullptr;
+ ParseResourceFunc func;
+ ParseResourceFunc ext_func;
+ ParseResourceFunc sub_func;
+ };
+
+ enum TokenType {
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_PARENTHESIS_OPEN,
+ TK_PARENTHESIS_CLOSE,
+ TK_IDENTIFIER,
+ TK_STRING,
+ TK_STRING_NAME,
+ TK_NUMBER,
+ TK_COLOR,
+ TK_COLON,
+ TK_COMMA,
+ TK_PERIOD,
+ TK_EQUAL,
+ TK_EOF,
+ TK_ERROR,
+ TK_MAX
+ };
+
+ enum Expecting {
+
+ EXPECT_OBJECT,
+ EXPECT_OBJECT_KEY,
+ EXPECT_COLON,
+ EXPECT_OBJECT_VALUE,
+ };
+
+ struct Token {
+ TokenType type;
+ Variant value;
+ };
+
+ struct Tag {
+ String name;
+ Map<String, Variant> fields;
+ };
+
+private:
+ static const char *tk_name[TK_MAX];
+
+ template <class T>
+ static Error _parse_construct(Stream *p_stream, Vector<T> &r_construct, int &line, String &r_err_str);
+ static Error _parse_enginecfg(Stream *p_stream, Vector<String> &strings, int &line, String &r_err_str);
+ static Error _parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
+ static Error _parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
+ static Error _parse_tag(Token &token, Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser = nullptr, bool p_simple_tag = false);
+
+public:
+ static Error parse_tag(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser = nullptr, bool p_simple_tag = false);
+ static Error parse_tag_assign_eof(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, String &r_assign, Variant &r_value, ResourceParser *p_res_parser = nullptr, bool p_simple_tag = false);
+
+ static Error parse_value(Token &token, Variant &value, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
+ static Error get_token(Stream *p_stream, Token &r_token, int &line, String &r_err_str);
+ static Error parse(Stream *p_stream, Variant &r_ret, String &r_err_str, int &r_err_line, ResourceParser *p_res_parser = nullptr);
+};
+
+class VariantWriter {
+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_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr);
+};
+
+#endif // VARIANT_PARSER_H
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
new file mode 100644
index 0000000000..6d9599a27e
--- /dev/null
+++ b/core/variant/variant_setget.cpp
@@ -0,0 +1,2587 @@
+/*************************************************************************/
+/* variant_setget.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "variant.h"
+
+#include "core/core_string_names.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/object/class_db.h"
+#include "core/templates/local_vector.h"
+#include "core/variant/variant_internal.h"
+
+/**** NAMED SETTERS AND GETTERS ****/
+
+#define SETGET_STRUCT(m_base_type, m_member_type, m_member) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ *member = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
+ } \
+ static void validated_get(const Variant *base, Variant *member) { \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_member = PtrToArg<m_member_type>::convert(member); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_NUMBER_STRUCT(m_base_type, m_member_type, m_member) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ *member = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
+ } \
+ static void validated_get(const Variant *base, Variant *member) { \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == Variant::FLOAT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<double>::get_ptr(value); \
+ valid = true; \
+ } else if (value->get_type() == Variant::INT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<int64_t>::get_ptr(value); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_member = PtrToArg<m_member_type>::convert(member); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ *member = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
+ } \
+ static void validated_get(const Variant *base, Variant *member) { \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_custom = PtrToArg<m_member_type>::convert(member); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_NUMBER_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ *member = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
+ } \
+ static void validated_get(const Variant *base, Variant *member) { \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == Variant::FLOAT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<double>::get_ptr(value); \
+ valid = true; \
+ } else if (value->get_type() == Variant::INT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<int64_t>::get_ptr(value); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_custom = PtrToArg<m_member_type>::convert(member); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ *member = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
+ } \
+ static void validated_get(const Variant *base, Variant *member) { \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_setter(PtrToArg<m_member_type>::convert(member)); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_NUMBER_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ *member = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
+ } \
+ static void validated_get(const Variant *base, Variant *member) { \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == Variant::FLOAT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<double>::get_ptr(value)); \
+ valid = true; \
+ } else if (value->get_type() == Variant::INT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<int64_t>::get_ptr(value)); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_setter(PtrToArg<m_member_type>::convert(member)); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_STRUCT_FUNC_INDEX(m_base_type, m_member_type, m_member, m_setter, m_getter, m_index) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ *member = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \
+ } \
+ static void validated_get(const Variant *base, Variant *member) { \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(m_index), member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_setter(m_index, PtrToArg<m_member_type>::convert(member)); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+SETGET_NUMBER_STRUCT(Vector2, double, x)
+SETGET_NUMBER_STRUCT(Vector2, double, y)
+
+SETGET_NUMBER_STRUCT(Vector2i, int64_t, x)
+SETGET_NUMBER_STRUCT(Vector2i, int64_t, y)
+
+SETGET_NUMBER_STRUCT(Vector3, double, x)
+SETGET_NUMBER_STRUCT(Vector3, double, y)
+SETGET_NUMBER_STRUCT(Vector3, double, z)
+
+SETGET_NUMBER_STRUCT(Vector3i, int64_t, x)
+SETGET_NUMBER_STRUCT(Vector3i, int64_t, y)
+SETGET_NUMBER_STRUCT(Vector3i, int64_t, z)
+
+SETGET_STRUCT(Rect2, Vector2, position)
+SETGET_STRUCT(Rect2, Vector2, size)
+SETGET_STRUCT_FUNC(Rect2, Vector2, end, set_end, get_end)
+
+SETGET_STRUCT(Rect2i, Vector2i, position)
+SETGET_STRUCT(Rect2i, Vector2i, size)
+SETGET_STRUCT_FUNC(Rect2i, Vector2i, end, set_end, get_end)
+
+SETGET_STRUCT(AABB, Vector3, position)
+SETGET_STRUCT(AABB, Vector3, size)
+SETGET_STRUCT_FUNC(AABB, Vector3, end, set_end, get_end)
+
+SETGET_STRUCT_CUSTOM(Transform2D, Vector2, x, elements[0])
+SETGET_STRUCT_CUSTOM(Transform2D, Vector2, y, elements[1])
+SETGET_STRUCT_CUSTOM(Transform2D, Vector2, origin, elements[2])
+
+SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, x, normal.x)
+SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, y, normal.y)
+SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, z, normal.z)
+SETGET_STRUCT(Plane, Vector3, normal)
+SETGET_NUMBER_STRUCT(Plane, double, d)
+
+SETGET_NUMBER_STRUCT(Quat, double, x)
+SETGET_NUMBER_STRUCT(Quat, double, y)
+SETGET_NUMBER_STRUCT(Quat, double, z)
+SETGET_NUMBER_STRUCT(Quat, double, w)
+
+SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_axis, get_axis, 0)
+SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_axis, get_axis, 1)
+SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_axis, get_axis, 2)
+
+SETGET_STRUCT(Transform, Basis, basis)
+SETGET_STRUCT(Transform, Vector3, origin)
+
+SETGET_NUMBER_STRUCT(Color, double, r)
+SETGET_NUMBER_STRUCT(Color, double, g)
+SETGET_NUMBER_STRUCT(Color, double, b)
+SETGET_NUMBER_STRUCT(Color, double, a)
+
+SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, r8, set_r8, get_r8)
+SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, g8, set_g8, get_g8)
+SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, b8, set_b8, get_b8)
+SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, a8, set_a8, get_a8)
+
+SETGET_NUMBER_STRUCT_FUNC(Color, double, h, set_h, get_h)
+SETGET_NUMBER_STRUCT_FUNC(Color, double, s, set_s, get_s)
+SETGET_NUMBER_STRUCT_FUNC(Color, double, v, set_v, get_v)
+
+struct VariantSetterGetterInfo {
+ void (*setter)(Variant *base, const Variant *value, bool &valid);
+ void (*getter)(const Variant *base, Variant *value);
+ Variant::ValidatedSetter validated_setter;
+ Variant::ValidatedGetter validated_getter;
+ Variant::PTRSetter ptr_setter;
+ Variant::PTRGetter ptr_getter;
+ Variant::Type member_type;
+};
+
+static LocalVector<VariantSetterGetterInfo> variant_setters_getters[Variant::VARIANT_MAX];
+static LocalVector<StringName> variant_setters_getters_names[Variant::VARIANT_MAX]; //one next to another to make it cache friendly
+
+template <class T>
+static void register_member(Variant::Type p_type, const StringName &p_member) {
+ VariantSetterGetterInfo sgi;
+ sgi.setter = T::set;
+ sgi.validated_setter = T::validated_set;
+ sgi.ptr_setter = T::ptr_set;
+
+ sgi.getter = T::get;
+ sgi.validated_getter = T::validated_get;
+ sgi.ptr_getter = T::ptr_get;
+
+ sgi.member_type = T::get_type();
+
+ variant_setters_getters[p_type].push_back(sgi);
+ variant_setters_getters_names[p_type].push_back(p_member);
+}
+
+void register_named_setters_getters() {
+#define REGISTER_MEMBER(m_base_type, m_member) register_member<VariantSetGet_##m_base_type##_##m_member>(GetTypeInfo<m_base_type>::VARIANT_TYPE, #m_member)
+
+ REGISTER_MEMBER(Vector2, x);
+ REGISTER_MEMBER(Vector2, y);
+
+ REGISTER_MEMBER(Vector2i, x);
+ REGISTER_MEMBER(Vector2i, y);
+
+ REGISTER_MEMBER(Vector3, x);
+ REGISTER_MEMBER(Vector3, y);
+ REGISTER_MEMBER(Vector3, z);
+
+ REGISTER_MEMBER(Vector3i, x);
+ REGISTER_MEMBER(Vector3i, y);
+ REGISTER_MEMBER(Vector3i, z);
+
+ REGISTER_MEMBER(Rect2, position);
+ REGISTER_MEMBER(Rect2, size);
+ REGISTER_MEMBER(Rect2, end);
+
+ REGISTER_MEMBER(Rect2i, position);
+ REGISTER_MEMBER(Rect2i, size);
+ REGISTER_MEMBER(Rect2i, end);
+
+ REGISTER_MEMBER(AABB, position);
+ REGISTER_MEMBER(AABB, size);
+ REGISTER_MEMBER(AABB, end);
+
+ REGISTER_MEMBER(Transform2D, x);
+ REGISTER_MEMBER(Transform2D, y);
+ REGISTER_MEMBER(Transform2D, origin);
+
+ REGISTER_MEMBER(Plane, x);
+ REGISTER_MEMBER(Plane, y);
+ REGISTER_MEMBER(Plane, z);
+ REGISTER_MEMBER(Plane, d);
+ REGISTER_MEMBER(Plane, normal);
+
+ REGISTER_MEMBER(Quat, x);
+ REGISTER_MEMBER(Quat, y);
+ REGISTER_MEMBER(Quat, z);
+ REGISTER_MEMBER(Quat, w);
+
+ REGISTER_MEMBER(Basis, x);
+ REGISTER_MEMBER(Basis, y);
+ REGISTER_MEMBER(Basis, z);
+
+ REGISTER_MEMBER(Transform, basis);
+ REGISTER_MEMBER(Transform, origin);
+
+ REGISTER_MEMBER(Color, r);
+ REGISTER_MEMBER(Color, g);
+ REGISTER_MEMBER(Color, b);
+ REGISTER_MEMBER(Color, a);
+
+ REGISTER_MEMBER(Color, r8);
+ REGISTER_MEMBER(Color, g8);
+ REGISTER_MEMBER(Color, b8);
+ REGISTER_MEMBER(Color, a8);
+
+ REGISTER_MEMBER(Color, h);
+ REGISTER_MEMBER(Color, s);
+ REGISTER_MEMBER(Color, v);
+}
+
+void unregister_named_setters_getters() {
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ variant_setters_getters[i].clear();
+ variant_setters_getters_names[i].clear();
+ }
+}
+
+bool Variant::has_member(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Variant::Type Variant::get_member_type(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::VARIANT_MAX);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].member_type;
+ }
+ }
+
+ return Variant::NIL;
+}
+
+void Variant::get_member_list(Variant::Type p_type, List<StringName> *r_members) {
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ r_members->push_back(variant_setters_getters_names[p_type][i]);
+ }
+}
+
+Variant::ValidatedSetter Variant::get_member_validated_setter(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].validated_setter;
+ }
+ }
+
+ return nullptr;
+}
+Variant::ValidatedGetter Variant::get_member_validated_getter(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].validated_getter;
+ }
+ }
+
+ return nullptr;
+}
+
+Variant::PTRSetter Variant::get_member_ptr_setter(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].ptr_setter;
+ }
+ }
+
+ return nullptr;
+}
+
+Variant::PTRGetter Variant::get_member_ptr_getter(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].ptr_getter;
+ }
+ }
+
+ return nullptr;
+}
+
+void Variant::set_named(const StringName &p_member, const Variant &p_value, bool &r_valid) {
+ uint32_t s = variant_setters_getters[type].size();
+ if (s) {
+ for (uint32_t i = 0; i < s; i++) {
+ if (variant_setters_getters_names[type][i] == p_member) {
+ variant_setters_getters[type][i].setter(this, &p_value, r_valid);
+ return;
+ }
+ }
+ r_valid = false;
+
+ } else if (type == Variant::OBJECT) {
+ Object *obj = get_validated_object();
+ if (!obj) {
+ r_valid = false;
+ } else {
+ obj->set(p_member, p_value, &r_valid);
+ return;
+ }
+ } else if (type == Variant::DICTIONARY) {
+ Variant *v = VariantGetInternalPtr<Dictionary>::get_ptr(this)->getptr(p_member);
+ if (v) {
+ *v = p_value;
+ r_valid = true;
+ } else {
+ r_valid = false;
+ }
+
+ } else {
+ r_valid = false;
+ }
+}
+
+Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
+ Variant ret;
+ uint32_t s = variant_setters_getters[type].size();
+ if (s) {
+ for (uint32_t i = 0; i < s; i++) {
+ if (variant_setters_getters_names[type][i] == p_member) {
+ variant_setters_getters[type][i].getter(this, &ret);
+ r_valid = true;
+ return ret;
+ }
+ }
+
+ r_valid = false;
+
+ } else if (type == Variant::OBJECT) {
+ Object *obj = get_validated_object();
+ if (!obj) {
+ r_valid = false;
+ return "Instance base is null.";
+ } else {
+ return obj->get(p_member, &r_valid);
+ }
+ } else if (type == Variant::DICTIONARY) {
+ const Variant *v = VariantGetInternalPtr<Dictionary>::get_ptr(this)->getptr(p_member);
+ if (v) {
+ r_valid = true;
+
+ return *v;
+ } else {
+ r_valid = false;
+ }
+
+ } else {
+ r_valid = false;
+ }
+
+ return ret;
+}
+
+/**** INDEXED SETTERS AND GETTERS ****/
+
+#ifdef DEBUG_ENABLED
+
+#define OOB_TEST(m_idx, m_v) \
+ ERR_FAIL_INDEX(m_idx, m_v)
+
+#else
+
+#define OOB_TEST(m_idx, m_v)
+
+#endif
+
+#ifdef DEBUG_ENABLED
+
+#define NULL_TEST(m_key) \
+ ERR_FAIL_COND(!m_key)
+
+#else
+
+#define NULL_TEST(m_key)
+
+#endif
+
+#define INDEXED_SETGET_STRUCT_TYPED(m_base_type, m_elem_type) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ *value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void validated_get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ PtrToArg<m_elem_type>::encode(v[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
+ oob = false; \
+ valid = false; \
+ return; \
+ } \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ v.write[index] = PtrToArg<m_elem_type>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
+ };
+
+#define INDEXED_SETGET_STRUCT_TYPED_NUMERIC(m_base_type, m_elem_type, m_assign_type) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ *value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void validated_get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ PtrToArg<m_elem_type>::encode(v[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ m_assign_type num; \
+ if (value->get_type() == Variant::INT) { \
+ num = (m_assign_type)*VariantGetInternalPtr<int64_t>::get_ptr(value); \
+ } else if (value->get_type() == Variant::FLOAT) { \
+ num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \
+ } else { \
+ oob = false; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = num; \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ v.write[index] = PtrToArg<m_elem_type>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
+ };
+
+#define INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(m_base_type, m_elem_type, m_assign_type, m_max) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ *value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void validated_get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ PtrToArg<m_elem_type>::encode(v[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ m_assign_type num; \
+ if (value->get_type() == Variant::INT) { \
+ num = (m_assign_type)*VariantGetInternalPtr<int64_t>::get_ptr(value); \
+ } else if (value->get_type() == Variant::FLOAT) { \
+ num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \
+ } else { \
+ oob = false; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = num; \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ v[index] = PtrToArg<m_elem_type>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
+ };
+
+#define INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(m_base_type, m_elem_type, m_accessor, m_max) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ *value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))m_accessor[index]; \
+ oob = false; \
+ } \
+ static void validated_get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))m_accessor[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ PtrToArg<m_elem_type>::encode(v m_accessor[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
+ oob = false; \
+ valid = false; \
+ } \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)) m_accessor[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)) m_accessor[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ v m_accessor[index] = PtrToArg<m_elem_type>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
+ };
+
+#define INDEXED_SETGET_STRUCT_BULTIN_FUNC(m_base_type, m_elem_type, m_set, m_get, m_max) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ *value = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_get(index); \
+ oob = false; \
+ } \
+ static void validated_get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_get(index); \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ PtrToArg<m_elem_type>::encode(v.m_get(index), member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
+ oob = false; \
+ valid = false; \
+ } \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_set(index, *VariantGetInternalPtr<m_elem_type>::get_ptr(value)); \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_set(index, *VariantGetInternalPtr<m_elem_type>::get_ptr(value)); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ v.m_set(index, PtrToArg<m_elem_type>::convert(member)); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
+ };
+
+#define INDEXED_SETGET_STRUCT_VARIANT(m_base_type) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ *value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void validated_get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ *value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ PtrToArg<Variant>::encode(v[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ v[index] = PtrToArg<Variant>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return Variant::NIL; } \
+ static uint64_t get_indexed_size(const Variant *base) { return 0; } \
+ };
+
+#define INDEXED_SETGET_STRUCT_DICT(m_base_type) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ const Variant *ptr = VariantGetInternalPtr<m_base_type>::get_ptr(base)->getptr(index); \
+ if (!ptr) { \
+ oob = true; \
+ return; \
+ } \
+ *value = *ptr; \
+ oob = false; \
+ } \
+ static void validated_get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ const Variant *ptr = VariantGetInternalPtr<m_base_type>::get_ptr(base)->getptr(index); \
+ if (!ptr) { \
+ oob = true; \
+ return; \
+ } \
+ *value = *ptr; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ const Variant *ptr = v.getptr(index); \
+ NULL_TEST(ptr); \
+ PtrToArg<Variant>::encode(*ptr, member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ v[index] = PtrToArg<Variant>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return Variant::NIL; } \
+ static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
+ };
+
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2, double, real_t, 2)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2i, int64_t, int32_t, 2)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3, double, real_t, 3)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3i, int64_t, int32_t, 3)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quat, double, real_t, 4)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4)
+
+INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .elements, 3)
+INDEXED_SETGET_STRUCT_BULTIN_FUNC(Basis, Vector3, set_axis, get_axis, 3)
+
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedByteArray, int64_t, uint8_t)
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedInt32Array, int64_t, int32_t)
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedInt64Array, int64_t, int64_t)
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedFloat32Array, double, float)
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedFloat64Array, double, double)
+INDEXED_SETGET_STRUCT_TYPED(PackedVector2Array, Vector2)
+INDEXED_SETGET_STRUCT_TYPED(PackedVector3Array, Vector3)
+INDEXED_SETGET_STRUCT_TYPED(PackedStringArray, String)
+INDEXED_SETGET_STRUCT_TYPED(PackedColorArray, Color)
+
+INDEXED_SETGET_STRUCT_VARIANT(Array)
+INDEXED_SETGET_STRUCT_DICT(Dictionary)
+
+struct VariantIndexedSetterGetterInfo {
+ void (*setter)(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob);
+ void (*getter)(const Variant *base, int64_t index, Variant *value, bool &oob);
+
+ Variant::ValidatedIndexedSetter validated_setter;
+ Variant::ValidatedIndexedGetter validated_getter;
+
+ Variant::PTRIndexedSetter ptr_setter;
+ Variant::PTRIndexedGetter ptr_getter;
+
+ uint64_t (*get_indexed_size)(const Variant *base);
+
+ Variant::Type index_type;
+
+ bool valid = false;
+};
+
+static VariantIndexedSetterGetterInfo variant_indexed_setters_getters[Variant::VARIANT_MAX];
+
+template <class T>
+static void register_indexed_member(Variant::Type p_type) {
+ VariantIndexedSetterGetterInfo &sgi = variant_indexed_setters_getters[p_type];
+
+ sgi.setter = T::set;
+ sgi.validated_setter = T::validated_set;
+ sgi.ptr_setter = T::ptr_set;
+
+ sgi.getter = T::get;
+ sgi.validated_getter = T::validated_get;
+ sgi.ptr_getter = T::ptr_get;
+
+ sgi.index_type = T::get_index_type();
+ sgi.get_indexed_size = T::get_indexed_size;
+
+ sgi.valid = true;
+}
+
+void register_indexed_setters_getters() {
+#define REGISTER_INDEXED_MEMBER(m_base_type) register_indexed_member<VariantIndexedSetGet_##m_base_type>(GetTypeInfo<m_base_type>::VARIANT_TYPE)
+
+ REGISTER_INDEXED_MEMBER(Vector2);
+ REGISTER_INDEXED_MEMBER(Vector2i);
+ REGISTER_INDEXED_MEMBER(Vector3);
+ REGISTER_INDEXED_MEMBER(Vector3i);
+ REGISTER_INDEXED_MEMBER(Quat);
+ REGISTER_INDEXED_MEMBER(Color);
+ REGISTER_INDEXED_MEMBER(Transform2D);
+ REGISTER_INDEXED_MEMBER(Basis);
+
+ REGISTER_INDEXED_MEMBER(PackedByteArray);
+ REGISTER_INDEXED_MEMBER(PackedInt32Array);
+ REGISTER_INDEXED_MEMBER(PackedInt64Array);
+ REGISTER_INDEXED_MEMBER(PackedFloat64Array);
+ REGISTER_INDEXED_MEMBER(PackedVector2Array);
+ REGISTER_INDEXED_MEMBER(PackedVector3Array);
+ REGISTER_INDEXED_MEMBER(PackedStringArray);
+ REGISTER_INDEXED_MEMBER(PackedColorArray);
+
+ REGISTER_INDEXED_MEMBER(Array);
+ REGISTER_INDEXED_MEMBER(Dictionary);
+}
+
+static void unregister_indexed_setters_getters() {
+}
+
+bool Variant::has_indexing(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ return variant_indexed_setters_getters[p_type].valid;
+}
+
+Variant::Type Variant::get_indexed_element_type(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::VARIANT_MAX);
+ return variant_indexed_setters_getters[p_type].index_type;
+}
+
+Variant::ValidatedIndexedSetter Variant::get_member_validated_indexed_setter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ return variant_indexed_setters_getters[p_type].validated_setter;
+}
+Variant::ValidatedIndexedGetter Variant::get_member_validated_indexed_getter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ return variant_indexed_setters_getters[p_type].validated_getter;
+}
+
+Variant::PTRIndexedSetter Variant::get_member_ptr_indexed_setter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ return variant_indexed_setters_getters[p_type].ptr_setter;
+}
+Variant::PTRIndexedGetter Variant::get_member_ptr_indexed_getter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ return variant_indexed_setters_getters[p_type].ptr_getter;
+}
+
+void Variant::set_indexed(int64_t p_index, const Variant &p_value, bool &r_valid, bool &r_oob) {
+ if (likely(variant_indexed_setters_getters[type].valid)) {
+ variant_indexed_setters_getters[type].setter(this, p_index, &p_value, r_valid, r_oob);
+ } else {
+ r_valid = false;
+ r_oob = false;
+ }
+}
+Variant Variant::get_indexed(int64_t p_index, bool &r_valid, bool &r_oob) const {
+ if (likely(variant_indexed_setters_getters[type].valid)) {
+ Variant ret;
+ variant_indexed_setters_getters[type].getter(this, p_index, &ret, r_oob);
+ r_valid = !r_oob;
+ return ret;
+ } else {
+ r_valid = false;
+ r_oob = false;
+ return Variant();
+ }
+}
+
+uint64_t Variant::get_indexed_size() const {
+ if (likely(variant_indexed_setters_getters[type].valid && variant_indexed_setters_getters[type].get_indexed_size)) {
+ return variant_indexed_setters_getters[type].get_indexed_size(this);
+ } else {
+ return 0;
+ }
+}
+
+struct VariantKeyedSetGetDictionary {
+ static void get(const Variant *base, const Variant *key, Variant *value, bool &r_valid) {
+ const Variant *ptr = VariantGetInternalPtr<Dictionary>::get_ptr(base)->getptr(*key);
+ if (!ptr) {
+ r_valid = false;
+ return;
+ }
+ *value = *ptr;
+ r_valid = true;
+ }
+ static void ptr_get(const void *base, const void *key, void *value) {
+ /* avoid ptrconvert for performance*/
+ const Dictionary &v = *reinterpret_cast<const Dictionary *>(base);
+ const Variant *ptr = v.getptr(PtrToArg<Variant>::convert(key));
+ NULL_TEST(ptr);
+ PtrToArg<Variant>::encode(*ptr, value);
+ }
+ static void set(Variant *base, const Variant *key, const Variant *value, bool &r_valid) {
+ (*VariantGetInternalPtr<Dictionary>::get_ptr(base))[*key] = *value;
+ r_valid = true;
+ }
+ static void ptr_set(void *base, const void *key, const void *value) {
+ Dictionary &v = *reinterpret_cast<Dictionary *>(base);
+ v[PtrToArg<Variant>::convert(key)] = PtrToArg<Variant>::convert(value);
+ }
+
+ static bool has(const Variant *base, const Variant *key, bool &r_valid) {
+ r_valid = true;
+ return VariantGetInternalPtr<Dictionary>::get_ptr(base)->has(*key);
+ }
+ static bool ptr_has(const void *base, const void *key) {
+ /* avoid ptrconvert for performance*/
+ const Dictionary &v = *reinterpret_cast<const Dictionary *>(base);
+ return v.has(PtrToArg<Variant>::convert(key));
+ }
+};
+
+struct VariantKeyedSetGetObject {
+ static void get(const Variant *base, const Variant *key, Variant *value, bool &r_valid) {
+ Object *obj = base->get_validated_object();
+
+ if (!obj) {
+ r_valid = false;
+ *value = Variant();
+ return;
+ }
+ *value = obj->getvar(*key, &r_valid);
+ }
+ static void ptr_get(const void *base, const void *key, void *value) {
+ const Object *obj = PtrToArg<Object *>::convert(base);
+ NULL_TEST(obj);
+ Variant v = obj->getvar(PtrToArg<Variant>::convert(key));
+ PtrToArg<Variant>::encode(v, value);
+ }
+ static void set(Variant *base, const Variant *key, const Variant *value, bool &r_valid) {
+ Object *obj = base->get_validated_object();
+
+ if (!obj) {
+ r_valid = false;
+ return;
+ }
+ obj->setvar(*key, *value, &r_valid);
+ }
+ static void ptr_set(void *base, const void *key, const void *value) {
+ Object *obj = PtrToArg<Object *>::convert(base);
+ NULL_TEST(obj);
+ obj->setvar(PtrToArg<Variant>::convert(key), PtrToArg<Variant>::convert(value));
+ }
+
+ static bool has(const Variant *base, const Variant *key, bool &r_valid) {
+ Object *obj = base->get_validated_object();
+ if (obj != nullptr) {
+ r_valid = false;
+ return false;
+ }
+ r_valid = true;
+ bool exists;
+ obj->getvar(*key, &exists);
+ return exists;
+ }
+ static bool ptr_has(const void *base, const void *key) {
+ const Object *obj = PtrToArg<Object *>::convert(base);
+ ERR_FAIL_COND_V(!obj, false);
+ bool valid;
+ obj->getvar(PtrToArg<Variant>::convert(key), &valid);
+ return valid;
+ }
+};
+
+/*typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value);
+typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool &valid);
+typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key);
+
+typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value);
+typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value);
+typedef bool (*PTRKeyedChecker)(const void *base, const void *key);*/
+
+struct VariantKeyedSetterGetterInfo {
+ Variant::ValidatedKeyedSetter validated_setter;
+ Variant::ValidatedKeyedGetter validated_getter;
+ Variant::ValidatedKeyedChecker validated_checker;
+
+ Variant::PTRKeyedSetter ptr_setter;
+ Variant::PTRKeyedGetter ptr_getter;
+ Variant::PTRKeyedChecker ptr_checker;
+
+ bool valid = false;
+};
+
+static VariantKeyedSetterGetterInfo variant_keyed_setters_getters[Variant::VARIANT_MAX];
+
+template <class T>
+static void register_keyed_member(Variant::Type p_type) {
+ VariantKeyedSetterGetterInfo &sgi = variant_keyed_setters_getters[p_type];
+
+ sgi.validated_setter = T::set;
+ sgi.ptr_setter = T::ptr_set;
+
+ sgi.validated_getter = T::get;
+ sgi.ptr_getter = T::ptr_get;
+
+ sgi.validated_checker = T::has;
+ sgi.ptr_checker = T::ptr_has;
+
+ sgi.valid = true;
+}
+
+static void register_keyed_setters_getters() {
+ register_keyed_member<VariantKeyedSetGetDictionary>(Variant::DICTIONARY);
+ register_keyed_member<VariantKeyedSetGetObject>(Variant::OBJECT);
+}
+bool Variant::is_keyed(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, false);
+ return variant_keyed_setters_getters[p_type].valid;
+}
+
+Variant::ValidatedKeyedSetter Variant::get_member_validated_keyed_setter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].validated_setter;
+}
+Variant::ValidatedKeyedGetter Variant::get_member_validated_keyed_getter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].validated_getter;
+}
+Variant::ValidatedKeyedChecker Variant::get_member_validated_keyed_checker(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].validated_checker;
+}
+
+Variant::PTRKeyedSetter Variant::get_member_ptr_keyed_setter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].ptr_setter;
+}
+Variant::PTRKeyedGetter Variant::get_member_ptr_keyed_getter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].ptr_getter;
+}
+Variant::PTRKeyedChecker Variant::get_member_ptr_keyed_checker(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].ptr_checker;
+}
+
+void Variant::set_keyed(const Variant &p_key, const Variant &p_value, bool &r_valid) {
+ if (likely(variant_keyed_setters_getters[type].valid)) {
+ variant_keyed_setters_getters[type].validated_setter(this, &p_key, &p_value, r_valid);
+ } else {
+ r_valid = false;
+ }
+}
+Variant Variant::get_keyed(const Variant &p_key, bool &r_valid) const {
+ if (likely(variant_keyed_setters_getters[type].valid)) {
+ Variant ret;
+ variant_keyed_setters_getters[type].validated_getter(this, &p_key, &ret, r_valid);
+ return ret;
+ } else {
+ r_valid = false;
+ return Variant();
+ }
+}
+bool Variant::has_key(const Variant &p_key, bool &r_valid) const {
+ if (likely(variant_keyed_setters_getters[type].valid)) {
+ return variant_keyed_setters_getters[type].validated_checker(this, &p_key, r_valid);
+ } else {
+ r_valid = false;
+ return false;
+ }
+}
+
+void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) {
+ if (type == DICTIONARY || type == OBJECT) {
+ bool valid;
+ set_keyed(p_index, p_value, valid);
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ } else {
+ bool valid = false;
+ if (p_index.get_type() == STRING_NAME) {
+ set_named(*VariantGetInternalPtr<StringName>::get_ptr(&p_index), p_value, valid);
+ } else if (p_index.get_type() == INT) {
+ bool obb;
+ set_indexed(*VariantGetInternalPtr<int64_t>::get_ptr(&p_index), p_value, valid, obb);
+ if (obb) {
+ valid = false;
+ }
+ } else if (p_index.get_type() == STRING) { // less efficient version of named
+ set_named(*VariantGetInternalPtr<String>::get_ptr(&p_index), p_value, valid);
+ } else if (p_index.get_type() == FLOAT) { // less efficient version of indexed
+ bool obb;
+ set_indexed(*VariantGetInternalPtr<double>::get_ptr(&p_index), p_value, valid, obb);
+ if (obb) {
+ valid = false;
+ }
+ }
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ }
+}
+
+Variant Variant::get(const Variant &p_index, bool *r_valid) const {
+ Variant ret;
+ if (type == DICTIONARY || type == OBJECT) {
+ bool valid;
+ ret = get_keyed(p_index, valid);
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ } else {
+ bool valid = false;
+ if (p_index.get_type() == STRING_NAME) {
+ ret = get_named(*VariantGetInternalPtr<StringName>::get_ptr(&p_index), valid);
+ } else if (p_index.get_type() == INT) {
+ bool obb;
+ ret = get_indexed(*VariantGetInternalPtr<int64_t>::get_ptr(&p_index), valid, obb);
+ if (obb) {
+ valid = false;
+ }
+ } else if (p_index.get_type() == STRING) { // less efficient version of named
+ ret = get_named(*VariantGetInternalPtr<String>::get_ptr(&p_index), valid);
+ } else if (p_index.get_type() == FLOAT) { // less efficient version of indexed
+ bool obb;
+ ret = get_indexed(*VariantGetInternalPtr<double>::get_ptr(&p_index), valid, obb);
+ if (obb) {
+ valid = false;
+ }
+ }
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ }
+
+ return ret;
+}
+
+void Variant::get_property_list(List<PropertyInfo> *p_list) const {
+ if (type == DICTIONARY) {
+ const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
+ List<Variant> keys;
+ dic->get_key_list(&keys);
+ for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
+ if (E->get().get_type() == Variant::STRING) {
+ p_list->push_back(PropertyInfo(Variant::STRING, E->get()));
+ }
+ }
+ } else if (type == OBJECT) {
+ Object *obj = get_validated_object();
+ ERR_FAIL_COND(!obj);
+ obj->get_property_list(p_list);
+
+ } else {
+ List<StringName> members;
+ get_member_list(type, &members);
+ for (List<StringName>::Element *E = members.front(); E; E = E->next()) {
+ PropertyInfo pi;
+ pi.name = E->get();
+ pi.type = get_member_type(type, E->get());
+ p_list->push_back(pi);
+ }
+ }
+}
+
+bool Variant::iter_init(Variant &r_iter, bool &valid) const {
+ valid = true;
+ switch (type) {
+ case INT: {
+ r_iter = 0;
+ return _data._int > 0;
+ } break;
+ case FLOAT: {
+ r_iter = 0;
+ return _data._float > 0.0;
+ } break;
+ case VECTOR2: {
+ double from = reinterpret_cast<const Vector2 *>(_data._mem)->x;
+ double to = reinterpret_cast<const Vector2 *>(_data._mem)->y;
+
+ r_iter = from;
+
+ return from < to;
+ } break;
+ case VECTOR2I: {
+ int64_t from = reinterpret_cast<const Vector2i *>(_data._mem)->x;
+ int64_t to = reinterpret_cast<const Vector2i *>(_data._mem)->y;
+
+ r_iter = from;
+
+ return from < to;
+ } break;
+ case VECTOR3: {
+ double from = reinterpret_cast<const Vector3 *>(_data._mem)->x;
+ double to = reinterpret_cast<const Vector3 *>(_data._mem)->y;
+ double step = reinterpret_cast<const Vector3 *>(_data._mem)->z;
+
+ r_iter = from;
+
+ if (from == to) {
+ return false;
+ } else if (from < to) {
+ return step > 0;
+ }
+ return step < 0;
+ } break;
+ case VECTOR3I: {
+ int64_t from = reinterpret_cast<const Vector3i *>(_data._mem)->x;
+ int64_t to = reinterpret_cast<const Vector3i *>(_data._mem)->y;
+ int64_t step = reinterpret_cast<const Vector3i *>(_data._mem)->z;
+
+ r_iter = from;
+
+ if (from == to) {
+ return false;
+ } else if (from < to) {
+ return step > 0;
+ }
+ return step < 0;
+ } break;
+ case OBJECT: {
+ if (!_get_obj().obj) {
+ valid = false;
+ return false;
+ }
+
+#ifdef DEBUG_ENABLED
+
+ if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ valid = false;
+ return false;
+ }
+
+#endif
+ Callable::CallError ce;
+ ce.error = Callable::CallError::CALL_OK;
+ Array ref;
+ ref.push_back(r_iter);
+ Variant vref = ref;
+ const Variant *refp[] = { &vref };
+ Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_init, refp, 1, ce);
+
+ if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
+ valid = false;
+ return false;
+ }
+
+ r_iter = ref[0];
+ return ret;
+ } break;
+
+ case STRING: {
+ const String *str = reinterpret_cast<const String *>(_data._mem);
+ if (str->empty()) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case DICTIONARY: {
+ const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
+ if (dic->empty()) {
+ return false;
+ }
+
+ const Variant *next = dic->next(nullptr);
+ r_iter = *next;
+ return true;
+
+ } break;
+ case ARRAY: {
+ const Array *arr = reinterpret_cast<const Array *>(_data._mem);
+ if (arr->empty()) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case PACKED_BYTE_ARRAY: {
+ const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_STRING_ARRAY: {
+ const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ default: {
+ }
+ }
+
+ valid = false;
+ return false;
+}
+
+bool Variant::iter_next(Variant &r_iter, bool &valid) const {
+ valid = true;
+ switch (type) {
+ case INT: {
+ int64_t idx = r_iter;
+ idx++;
+ if (idx >= _data._int) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case FLOAT: {
+ int64_t idx = r_iter;
+ idx++;
+ if (idx >= _data._float) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case VECTOR2: {
+ double to = reinterpret_cast<const Vector2 *>(_data._mem)->y;
+
+ double idx = r_iter;
+ idx++;
+
+ if (idx >= to) {
+ return false;
+ }
+
+ r_iter = idx;
+ return true;
+ } break;
+ case VECTOR2I: {
+ int64_t to = reinterpret_cast<const Vector2i *>(_data._mem)->y;
+
+ int64_t idx = r_iter;
+ idx++;
+
+ if (idx >= to) {
+ return false;
+ }
+
+ r_iter = idx;
+ return true;
+ } break;
+ case VECTOR3: {
+ double to = reinterpret_cast<const Vector3 *>(_data._mem)->y;
+ double step = reinterpret_cast<const Vector3 *>(_data._mem)->z;
+
+ double idx = r_iter;
+ idx += step;
+
+ if (step < 0 && idx <= to) {
+ return false;
+ }
+
+ if (step > 0 && idx >= to) {
+ return false;
+ }
+
+ r_iter = idx;
+ return true;
+ } break;
+ case VECTOR3I: {
+ int64_t to = reinterpret_cast<const Vector3i *>(_data._mem)->y;
+ int64_t step = reinterpret_cast<const Vector3i *>(_data._mem)->z;
+
+ int64_t idx = r_iter;
+ idx += step;
+
+ if (step < 0 && idx <= to) {
+ return false;
+ }
+
+ if (step > 0 && idx >= to) {
+ return false;
+ }
+
+ r_iter = idx;
+ return true;
+ } break;
+ case OBJECT: {
+ if (!_get_obj().obj) {
+ valid = false;
+ return false;
+ }
+
+#ifdef DEBUG_ENABLED
+
+ if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ valid = false;
+ return false;
+ }
+
+#endif
+ Callable::CallError ce;
+ ce.error = Callable::CallError::CALL_OK;
+ Array ref;
+ ref.push_back(r_iter);
+ Variant vref = ref;
+ const Variant *refp[] = { &vref };
+ Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_next, refp, 1, ce);
+
+ if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
+ valid = false;
+ return false;
+ }
+
+ r_iter = ref[0];
+
+ return ret;
+ } break;
+
+ case STRING: {
+ const String *str = reinterpret_cast<const String *>(_data._mem);
+ int idx = r_iter;
+ idx++;
+ if (idx >= str->length()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case DICTIONARY: {
+ const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
+ const Variant *next = dic->next(&r_iter);
+ if (!next) {
+ return false;
+ }
+
+ r_iter = *next;
+ return true;
+
+ } break;
+ case ARRAY: {
+ const Array *arr = reinterpret_cast<const Array *>(_data._mem);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case PACKED_BYTE_ARRAY: {
+ const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
+ int32_t idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
+ int64_t idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_STRING_ARRAY: {
+ const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ default: {
+ }
+ }
+
+ valid = false;
+ return false;
+}
+
+Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
+ r_valid = true;
+ switch (type) {
+ case INT: {
+ return r_iter;
+ } break;
+ case FLOAT: {
+ return r_iter;
+ } break;
+ case VECTOR2: {
+ return r_iter;
+ } break;
+ case VECTOR2I: {
+ return r_iter;
+ } break;
+ case VECTOR3: {
+ return r_iter;
+ } break;
+ case VECTOR3I: {
+ return r_iter;
+ } break;
+ case OBJECT: {
+ if (!_get_obj().obj) {
+ r_valid = false;
+ return Variant();
+ }
+#ifdef DEBUG_ENABLED
+ if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ r_valid = false;
+ return Variant();
+ }
+
+#endif
+ Callable::CallError ce;
+ ce.error = Callable::CallError::CALL_OK;
+ const Variant *refp[] = { &r_iter };
+ Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_get, refp, 1, ce);
+
+ if (ce.error != Callable::CallError::CALL_OK) {
+ r_valid = false;
+ return Variant();
+ }
+
+ //r_iter=ref[0];
+
+ return ret;
+ } break;
+
+ case STRING: {
+ const String *str = reinterpret_cast<const String *>(_data._mem);
+ return str->substr(r_iter, 1);
+ } break;
+ case DICTIONARY: {
+ return r_iter; //iterator is the same as the key
+
+ } break;
+ case ARRAY: {
+ const Array *arr = reinterpret_cast<const Array *>(_data._mem);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_BYTE_ARRAY: {
+ const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
+ int32_t idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
+ int64_t idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_STRING_ARRAY: {
+ const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ default: {
+ }
+ }
+
+ r_valid = false;
+ return Variant();
+}
+
+Variant Variant::duplicate(bool deep) const {
+ switch (type) {
+ case OBJECT: {
+ /* breaks stuff :(
+ if (deep && !_get_obj().ref.is_null()) {
+ Ref<Resource> resource = _get_obj().ref;
+ if (resource.is_valid()) {
+ return resource->duplicate(true);
+ }
+ }
+ */
+ return *this;
+ } break;
+ case DICTIONARY:
+ return operator Dictionary().duplicate(deep);
+ case ARRAY:
+ return operator Array().duplicate(deep);
+ default:
+ return *this;
+ }
+}
+
+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()) {
+ real_t va = a;
+ real_t vb = b;
+ r_dst = va + vb * c;
+ } else {
+ r_dst = a;
+ }
+ 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 * c + 0.5);
+ }
+ return;
+ case FLOAT: {
+ double ra = a._data._float;
+ double rb = b._data._float;
+ r_dst = ra + rb * c;
+ }
+ return;
+ case VECTOR2: {
+ r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) + *reinterpret_cast<const Vector2 *>(b._data._mem) * c;
+ }
+ return;
+ case VECTOR2I: {
+ int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
+ r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
+ }
+ return;
+ case RECT2: {
+ const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
+ const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
+ r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c);
+ }
+ return;
+ case RECT2I: {
+ const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
+ const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
+
+ int32_t vax = ra->position.x;
+ int32_t vay = ra->position.y;
+ int32_t vbx = ra->size.x;
+ int32_t vby = ra->size.y;
+ int32_t vcx = rb->position.x;
+ int32_t vcy = rb->position.y;
+ int32_t vdx = rb->size.x;
+ int32_t vdy = rb->size.y;
+
+ r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
+ }
+ return;
+ case VECTOR3: {
+ r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) + *reinterpret_cast<const Vector3 *>(b._data._mem) * c;
+ }
+ return;
+ case VECTOR3I: {
+ int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
+ int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
+ int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
+ r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
+ }
+ return;
+ case AABB: {
+ const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
+ const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
+ r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c);
+ }
+ return;
+ case QUAT: {
+ Quat empty_rot;
+ const Quat *qa = reinterpret_cast<const Quat *>(a._data._mem);
+ const Quat *qb = reinterpret_cast<const Quat *>(b._data._mem);
+ r_dst = *qa * empty_rot.slerp(*qb, c);
+ }
+ 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 * c;
+ float new_g = ca->g + cb->g * c;
+ float new_b = ca->b + cb->b * c;
+ float new_a = ca->a + cb->a * c;
+ 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 = c < 0.5 ? a : b;
+ }
+ return;
+ }
+}
+
+void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst) {
+ if (a.type != b.type) {
+ if (a.is_num() && b.is_num()) {
+ //not as efficient but..
+ real_t va = a;
+ real_t vb = b;
+ r_dst = va + (vb - va) * c;
+
+ } else {
+ r_dst = a;
+ }
+ return;
+ }
+
+ switch (a.type) {
+ case NIL: {
+ r_dst = Variant();
+ }
+ return;
+ case BOOL: {
+ r_dst = a;
+ }
+ return;
+ case INT: {
+ int64_t va = a._data._int;
+ int64_t vb = b._data._int;
+ r_dst = int(va + (vb - va) * c);
+ }
+ return;
+ case FLOAT: {
+ real_t va = a._data._float;
+ real_t vb = b._data._float;
+ r_dst = va + (vb - va) * c;
+ }
+ return;
+ case STRING: {
+ //this is pretty funny and bizarre, but artists like to use it for typewritter effects
+ String sa = *reinterpret_cast<const String *>(a._data._mem);
+ String sb = *reinterpret_cast<const String *>(b._data._mem);
+ String dst;
+ int sa_len = sa.length();
+ int sb_len = sb.length();
+ int csize = sa_len + (sb_len - sa_len) * c;
+ if (csize == 0) {
+ r_dst = "";
+ return;
+ }
+ dst.resize(csize + 1);
+ dst[csize] = 0;
+ int split = csize / 2;
+
+ for (int i = 0; i < csize; i++) {
+ char32_t chr = ' ';
+
+ if (i < split) {
+ if (i < sa.length()) {
+ chr = sa[i];
+ } else if (i < sb.length()) {
+ chr = sb[i];
+ }
+
+ } else {
+ if (i < sb.length()) {
+ chr = sb[i];
+ } else if (i < sa.length()) {
+ chr = sa[i];
+ }
+ }
+
+ dst[i] = chr;
+ }
+
+ r_dst = dst;
+ }
+ return;
+ case VECTOR2: {
+ r_dst = reinterpret_cast<const Vector2 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector2 *>(b._data._mem), c);
+ }
+ return;
+ case VECTOR2I: {
+ int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
+ r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
+ }
+ return;
+
+ case RECT2: {
+ r_dst = Rect2(reinterpret_cast<const Rect2 *>(a._data._mem)->position.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->position, c), reinterpret_cast<const Rect2 *>(a._data._mem)->size.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->size, c));
+ }
+ return;
+ case RECT2I: {
+ const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
+ const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
+
+ int32_t vax = ra->position.x;
+ int32_t vay = ra->position.y;
+ int32_t vbx = ra->size.x;
+ int32_t vby = ra->size.y;
+ int32_t vcx = rb->position.x;
+ int32_t vcy = rb->position.y;
+ int32_t vdx = rb->size.x;
+ int32_t vdy = rb->size.y;
+
+ r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
+ }
+ return;
+
+ case VECTOR3: {
+ r_dst = reinterpret_cast<const Vector3 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector3 *>(b._data._mem), c);
+ }
+ return;
+ case VECTOR3I: {
+ int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
+ int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
+ int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
+ r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
+ }
+ return;
+
+ case TRANSFORM2D: {
+ r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c);
+ }
+ return;
+ case PLANE: {
+ r_dst = a;
+ }
+ return;
+ case QUAT: {
+ r_dst = reinterpret_cast<const Quat *>(a._data._mem)->slerp(*reinterpret_cast<const Quat *>(b._data._mem), c);
+ }
+ return;
+ case AABB: {
+ r_dst = ::AABB(a._data._aabb->position.lerp(b._data._aabb->position, c), a._data._aabb->size.lerp(b._data._aabb->size, c));
+ }
+ return;
+ case BASIS: {
+ r_dst = Transform(*a._data._basis).interpolate_with(Transform(*b._data._basis), c).basis;
+ }
+ return;
+ case TRANSFORM: {
+ r_dst = a._data._transform->interpolate_with(*b._data._transform, c);
+ }
+ return;
+ case COLOR: {
+ r_dst = reinterpret_cast<const Color *>(a._data._mem)->lerp(*reinterpret_cast<const Color *>(b._data._mem), c);
+ }
+ return;
+ case STRING_NAME: {
+ r_dst = a;
+ }
+ return;
+ case NODE_PATH: {
+ r_dst = a;
+ }
+ return;
+ case _RID: {
+ r_dst = a;
+ }
+ return;
+ case OBJECT: {
+ r_dst = a;
+ }
+ return;
+ case DICTIONARY: {
+ }
+ return;
+ case ARRAY: {
+ r_dst = a;
+ }
+ return;
+ case PACKED_BYTE_ARRAY: {
+ r_dst = a;
+ }
+ return;
+ case PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr_a = &PackedArrayRef<int32_t>::get_array(a._data.packed_array);
+ const Vector<int32_t> *arr_b = &PackedArrayRef<int32_t>::get_array(b._data.packed_array);
+ int32_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<int32_t> v;
+ v.resize(sz);
+ {
+ int32_t *vw = v.ptrw();
+ const int32_t *ar = arr_a->ptr();
+ const int32_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int32_t i = 0; i < sz; i++) {
+ Variant::interpolate(ar[i], br[i], c, va);
+ vw[i] = va;
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr_a = &PackedArrayRef<int64_t>::get_array(a._data.packed_array);
+ const Vector<int64_t> *arr_b = &PackedArrayRef<int64_t>::get_array(b._data.packed_array);
+ int64_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<int64_t> v;
+ v.resize(sz);
+ {
+ int64_t *vw = v.ptrw();
+ const int64_t *ar = arr_a->ptr();
+ const int64_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int64_t i = 0; i < sz; i++) {
+ Variant::interpolate(ar[i], br[i], c, va);
+ vw[i] = va;
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr_a = &PackedArrayRef<float>::get_array(a._data.packed_array);
+ const Vector<float> *arr_b = &PackedArrayRef<float>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<float> v;
+ v.resize(sz);
+ {
+ float *vw = v.ptrw();
+ const float *ar = arr_a->ptr();
+ const float *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ Variant::interpolate(ar[i], br[i], c, va);
+ vw[i] = va;
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr_a = &PackedArrayRef<double>::get_array(a._data.packed_array);
+ const Vector<double> *arr_b = &PackedArrayRef<double>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<double> v;
+ v.resize(sz);
+ {
+ double *vw = v.ptrw();
+ const double *ar = arr_a->ptr();
+ const double *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ Variant::interpolate(ar[i], br[i], c, va);
+ vw[i] = va;
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_STRING_ARRAY: {
+ r_dst = a;
+ }
+ return;
+ case PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr_a = &PackedArrayRef<Vector2>::get_array(a._data.packed_array);
+ const Vector<Vector2> *arr_b = &PackedArrayRef<Vector2>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<Vector2> v;
+ v.resize(sz);
+ {
+ Vector2 *vw = v.ptrw();
+ const Vector2 *ar = arr_a->ptr();
+ const Vector2 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr_a = &PackedArrayRef<Vector3>::get_array(a._data.packed_array);
+ const Vector<Vector3> *arr_b = &PackedArrayRef<Vector3>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<Vector3> v;
+ v.resize(sz);
+ {
+ Vector3 *vw = v.ptrw();
+ const Vector3 *ar = arr_a->ptr();
+ const Vector3 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr_a = &PackedArrayRef<Color>::get_array(a._data.packed_array);
+ const Vector<Color> *arr_b = &PackedArrayRef<Color>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<Color> v;
+ v.resize(sz);
+ {
+ Color *vw = v.ptrw();
+ const Color *ar = arr_a->ptr();
+ const Color *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ default: {
+ r_dst = a;
+ }
+ }
+}
+
+void register_variant_setters_getters() {
+ register_named_setters_getters();
+ register_indexed_setters_getters();
+ register_keyed_setters_getters();
+}
+void unregister_variant_setters_getters() {
+ unregister_named_setters_getters();
+ unregister_indexed_setters_getters();
+}