Browse Source

Refactored Variant Operators.

-Using classes to call and a table
-For typed code (GDS or GDNative), can obtain functions to call prevalidated or ptr.
reduz 5 years ago
parent
commit
f2397809a8

+ 31 - 0
core/array.cpp

@@ -98,6 +98,37 @@ bool Array::operator==(const Array &p_array) const {
 	return _p == p_array._p;
 	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 Array::hash() const {
 	uint32_t h = hash_djb2_one_32(0);
 	uint32_t h = hash_djb2_one_32(0);
 
 

+ 6 - 0
core/array.h

@@ -61,6 +61,7 @@ public:
 	void clear();
 	void clear();
 
 
 	bool operator==(const Array &p_array) const;
 	bool operator==(const Array &p_array) const;
+	bool operator!=(const Array &p_array) const;
 
 
 	uint32_t hash() const;
 	uint32_t hash() const;
 	void operator=(const Array &p_array);
 	void operator=(const Array &p_array);
@@ -98,6 +99,11 @@ public:
 
 
 	Array slice(int p_begin, int p_end, int p_step = 1, bool p_deep = false) const;
 	Array slice(int p_begin, int p_end, int 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 min() const;
 	Variant max() const;
 	Variant max() const;
 
 

+ 4 - 4
core/color.cpp

@@ -493,7 +493,7 @@ Color Color::operator*(const Color &p_color) const {
 			a * p_color.a);
 			a * p_color.a);
 }
 }
 
 
-Color Color::operator*(const real_t &rvalue) const {
+Color Color::operator*(real_t rvalue) const {
 	return Color(
 	return Color(
 			r * rvalue,
 			r * rvalue,
 			g * rvalue,
 			g * rvalue,
@@ -508,7 +508,7 @@ void Color::operator*=(const Color &p_color) {
 	a = a * p_color.a;
 	a = a * p_color.a;
 }
 }
 
 
-void Color::operator*=(const real_t &rvalue) {
+void Color::operator*=(real_t rvalue) {
 	r = r * rvalue;
 	r = r * rvalue;
 	g = g * rvalue;
 	g = g * rvalue;
 	b = b * rvalue;
 	b = b * rvalue;
@@ -523,7 +523,7 @@ Color Color::operator/(const Color &p_color) const {
 			a / p_color.a);
 			a / p_color.a);
 }
 }
 
 
-Color Color::operator/(const real_t &rvalue) const {
+Color Color::operator/(real_t rvalue) const {
 	return Color(
 	return Color(
 			r / rvalue,
 			r / rvalue,
 			g / rvalue,
 			g / rvalue,
@@ -538,7 +538,7 @@ void Color::operator/=(const Color &p_color) {
 	a = a / p_color.a;
 	a = a / p_color.a;
 }
 }
 
 
-void Color::operator/=(const real_t &rvalue) {
+void Color::operator/=(real_t rvalue) {
 	if (rvalue == 0) {
 	if (rvalue == 0) {
 		r = 1.0;
 		r = 1.0;
 		g = 1.0;
 		g = 1.0;

+ 5 - 5
core/color.h

@@ -79,14 +79,14 @@ struct Color {
 	void operator-=(const Color &p_color);
 	void operator-=(const Color &p_color);
 
 
 	Color operator*(const Color &p_color) const;
 	Color operator*(const Color &p_color) const;
-	Color operator*(const real_t &rvalue) const;
+	Color operator*(real_t rvalue) const;
 	void operator*=(const Color &p_color);
 	void operator*=(const Color &p_color);
-	void operator*=(const real_t &rvalue);
+	void operator*=(real_t rvalue);
 
 
 	Color operator/(const Color &p_color) const;
 	Color operator/(const Color &p_color) const;
-	Color operator/(const real_t &rvalue) const;
+	Color operator/(real_t rvalue) const;
 	void operator/=(const Color &p_color);
 	void operator/=(const Color &p_color);
-	void operator/=(const real_t &rvalue);
+	void operator/=(real_t rvalue);
 
 
 	bool is_equal_approx(const Color &p_color) const;
 	bool is_equal_approx(const Color &p_color) const;
 
 
@@ -232,7 +232,7 @@ bool Color::operator<(const Color &p_color) const {
 	}
 	}
 }
 }
 
 
-_FORCE_INLINE_ Color operator*(const real_t &p_real, const Color &p_color) {
+_FORCE_INLINE_ Color operator*(real_t p_real, const Color &p_color) {
 	return p_color * p_real;
 	return p_color * p_real;
 }
 }
 
 

+ 0 - 1
core/global_constants.cpp

@@ -638,7 +638,6 @@ void register_global_constants() {
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE);
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE);
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE);
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE);
-	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_STRING_CONCAT", Variant::OP_STRING_CONCAT);
 	//bitwise
 	//bitwise
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);
 	BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);

+ 4 - 0
core/math/quat.h

@@ -91,6 +91,10 @@ public:
 		return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
 		return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
 	}
 	}
 
 
+	_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &v) const {
+		return inverse().xform(v);
+	}
+
 	_FORCE_INLINE_ void operator+=(const Quat &q);
 	_FORCE_INLINE_ void operator+=(const Quat &q);
 	_FORCE_INLINE_ void operator-=(const Quat &q);
 	_FORCE_INLINE_ void operator-=(const Quat &q);
 	_FORCE_INLINE_ void operator*=(const real_t &s);
 	_FORCE_INLINE_ void operator*=(const real_t &s);

+ 13 - 0
core/math/vector2.cpp

@@ -233,6 +233,19 @@ void Vector2i::operator/=(const int &rvalue) {
 	y /= rvalue;
 	y /= rvalue;
 }
 }
 
 
+Vector2i Vector2i::operator%(const Vector2i &p_v1) const {
+	return Vector2i(x % p_v1.x, y % p_v1.y);
+}
+
+Vector2i Vector2i::operator%(const int &rvalue) const {
+	return Vector2i(x % rvalue, y % rvalue);
+}
+
+void Vector2i::operator%=(const int &rvalue) {
+	x %= rvalue;
+	y %= rvalue;
+}
+
 Vector2i Vector2i::operator-() const {
 Vector2i Vector2i::operator-() const {
 	return Vector2i(-x, -y);
 	return Vector2i(-x, -y);
 }
 }

+ 4 - 2
core/math/vector2.h

@@ -290,11 +290,13 @@ struct Vector2i {
 	void operator*=(const int &rvalue);
 	void operator*=(const int &rvalue);
 
 
 	Vector2i operator/(const Vector2i &p_v1) const;
 	Vector2i operator/(const Vector2i &p_v1) const;
-
 	Vector2i operator/(const int &rvalue) const;
 	Vector2i operator/(const int &rvalue) const;
-
 	void operator/=(const int &rvalue);
 	void operator/=(const int &rvalue);
 
 
+	Vector2i operator%(const Vector2i &p_v1) const;
+	Vector2i operator%(const int &rvalue) const;
+	void operator%=(const int &rvalue);
+
 	Vector2i operator-() const;
 	Vector2i operator-() const;
 	bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
 	bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
 	bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); }
 	bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); }

+ 26 - 0
core/math/vector3i.h

@@ -80,11 +80,15 @@ struct Vector3i {
 	_FORCE_INLINE_ Vector3i operator*(const Vector3i &p_v) const;
 	_FORCE_INLINE_ Vector3i operator*(const Vector3i &p_v) const;
 	_FORCE_INLINE_ Vector3i &operator/=(const Vector3i &p_v);
 	_FORCE_INLINE_ Vector3i &operator/=(const Vector3i &p_v);
 	_FORCE_INLINE_ Vector3i operator/(const Vector3i &p_v) const;
 	_FORCE_INLINE_ Vector3i operator/(const Vector3i &p_v) const;
+	_FORCE_INLINE_ Vector3i &operator%=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator%(const Vector3i &p_v) const;
 
 
 	_FORCE_INLINE_ Vector3i &operator*=(int32_t p_scalar);
 	_FORCE_INLINE_ Vector3i &operator*=(int32_t p_scalar);
 	_FORCE_INLINE_ Vector3i operator*(int32_t p_scalar) const;
 	_FORCE_INLINE_ Vector3i operator*(int32_t p_scalar) const;
 	_FORCE_INLINE_ Vector3i &operator/=(int32_t p_scalar);
 	_FORCE_INLINE_ Vector3i &operator/=(int32_t p_scalar);
 	_FORCE_INLINE_ Vector3i operator/(int32_t p_scalar) const;
 	_FORCE_INLINE_ Vector3i operator/(int32_t p_scalar) const;
+	_FORCE_INLINE_ Vector3i &operator%=(int32_t p_scalar);
+	_FORCE_INLINE_ Vector3i operator%(int32_t p_scalar) const;
 
 
 	_FORCE_INLINE_ Vector3i operator-() const;
 	_FORCE_INLINE_ Vector3i operator-() const;
 
 
@@ -159,6 +163,17 @@ Vector3i Vector3i::operator/(const Vector3i &p_v) const {
 	return Vector3i(x / p_v.x, y / p_v.y, z / p_v.z);
 	return Vector3i(x / p_v.x, y / p_v.y, z / p_v.z);
 }
 }
 
 
+Vector3i &Vector3i::operator%=(const Vector3i &p_v) {
+	x %= p_v.x;
+	y %= p_v.y;
+	z %= p_v.z;
+	return *this;
+}
+
+Vector3i Vector3i::operator%(const Vector3i &p_v) const {
+	return Vector3i(x % p_v.x, y % p_v.y, z % p_v.z);
+}
+
 Vector3i &Vector3i::operator*=(int32_t p_scalar) {
 Vector3i &Vector3i::operator*=(int32_t p_scalar) {
 	x *= p_scalar;
 	x *= p_scalar;
 	y *= p_scalar;
 	y *= p_scalar;
@@ -185,6 +200,17 @@ Vector3i Vector3i::operator/(int32_t p_scalar) const {
 	return Vector3i(x / p_scalar, y / p_scalar, z / p_scalar);
 	return Vector3i(x / p_scalar, y / p_scalar, z / p_scalar);
 }
 }
 
 
+Vector3i &Vector3i::operator%=(int32_t p_scalar) {
+	x %= p_scalar;
+	y %= p_scalar;
+	z %= p_scalar;
+	return *this;
+}
+
+Vector3i Vector3i::operator%(int32_t p_scalar) const {
+	return Vector3i(x % p_scalar, y % p_scalar, z % p_scalar);
+}
+
 Vector3i Vector3i::operator-() const {
 Vector3i Vector3i::operator-() const {
 	return Vector3i(-x, -y, -z);
 	return Vector3i(-x, -y, -z);
 }
 }

+ 4 - 0
core/register_core_types.cpp

@@ -99,6 +99,8 @@ extern void register_global_constants();
 extern void unregister_global_constants();
 extern void unregister_global_constants();
 extern void register_variant_methods();
 extern void register_variant_methods();
 extern void unregister_variant_methods();
 extern void unregister_variant_methods();
+extern void register_variant_operators();
+extern void unregister_variant_operators();
 
 
 void register_core_types() {
 void register_core_types() {
 	//consistency check
 	//consistency check
@@ -112,6 +114,7 @@ void register_core_types() {
 
 
 	register_global_constants();
 	register_global_constants();
 	register_variant_methods();
 	register_variant_methods();
+	register_variant_operators();
 
 
 	CoreStringNames::create();
 	CoreStringNames::create();
 
 
@@ -319,6 +322,7 @@ void unregister_core_types() {
 	ClassDB::cleanup_defaults();
 	ClassDB::cleanup_defaults();
 	ObjectDB::cleanup();
 	ObjectDB::cleanup();
 
 
+	unregister_variant_operators();
 	unregister_variant_methods();
 	unregister_variant_methods();
 	unregister_global_constants();
 	unregister_global_constants();
 
 

+ 3 - 0
core/rid.h

@@ -52,6 +52,9 @@ public:
 	_FORCE_INLINE_ bool operator>(const RID &p_rid) const {
 	_FORCE_INLINE_ bool operator>(const RID &p_rid) const {
 		return _id > p_rid._id;
 		return _id > p_rid._id;
 	}
 	}
+	_FORCE_INLINE_ bool operator>=(const RID &p_rid) const {
+		return _id >= p_rid._id;
+	}
 	_FORCE_INLINE_ bool operator!=(const RID &p_rid) const {
 	_FORCE_INLINE_ bool operator!=(const RID &p_rid) const {
 		return _id != p_rid._id;
 		return _id != p_rid._id;
 	}
 	}

+ 14 - 0
core/string_name.cpp

@@ -377,3 +377,17 @@ StringName StringName::search(const String &p_name) {
 StringName::~StringName() {
 StringName::~StringName() {
 	unref();
 	unref();
 }
 }
+
+bool operator==(const String &p_name, const StringName &p_string_name) {
+	return p_name == p_string_name.operator String();
+}
+bool operator!=(const String &p_name, const StringName &p_string_name) {
+	return p_name != p_string_name.operator String();
+}
+
+bool operator==(const char *p_name, const StringName &p_string_name) {
+	return p_name == p_string_name.operator String();
+}
+bool operator!=(const char *p_name, const StringName &p_string_name) {
+	return p_name != p_string_name.operator String();
+}

+ 5 - 0
core/string_name.h

@@ -155,6 +155,11 @@ public:
 	~StringName();
 	~StringName();
 };
 };
 
 
+bool operator==(const String &p_name, const StringName &p_string_name);
+bool operator!=(const String &p_name, const StringName &p_string_name);
+bool operator==(const char *p_name, const StringName &p_string_name);
+bool operator!=(const char *p_name, const StringName &p_string_name);
+
 StringName _scs_create(const char *p_chr);
 StringName _scs_create(const char *p_chr);
 
 
 #endif // STRING_NAME_H
 #endif // STRING_NAME_H

+ 28 - 3
core/ustring.cpp

@@ -637,6 +637,20 @@ bool operator==(const wchar_t *p_chr, const String &p_str) {
 #endif
 #endif
 }
 }
 
 
+bool operator!=(const char *p_chr, const String &p_str) {
+	return !(p_str == p_chr);
+}
+
+bool operator!=(const wchar_t *p_chr, const String &p_str) {
+#ifdef WINDOWS_ENABLED
+	// wchar_t is 16-bit
+	return !(p_str == String::utf16((const char16_t *)p_chr));
+#else
+	// wchar_t is 32-bi
+	return !(p_str == String((const char32_t *)p_chr));
+#endif
+}
+
 bool String::operator!=(const char *p_str) const {
 bool String::operator!=(const char *p_str) const {
 	return (!(*this == p_str));
 	return (!(*this == p_str));
 }
 }
@@ -654,7 +668,14 @@ bool String::operator!=(const String &p_str) const {
 }
 }
 
 
 bool String::operator<=(const String &p_str) const {
 bool String::operator<=(const String &p_str) const {
-	return (*this < p_str) || (*this == p_str);
+	return !(p_str < *this);
+}
+
+bool String::operator>(const String &p_str) const {
+	return p_str < *this;
+}
+bool String::operator>=(const String &p_str) const {
+	return !(*this < p_str);
 }
 }
 
 
 bool String::operator<(const char *p_str) const {
 bool String::operator<(const char *p_str) const {
@@ -4455,7 +4476,9 @@ String String::sprintf(const Array &values, bool *error) const {
 	bool left_justified = false;
 	bool left_justified = false;
 	bool show_sign = false;
 	bool show_sign = false;
 
 
-	*error = true;
+	if (error) {
+		*error = true;
+	}
 
 
 	for (; *self; self++) {
 	for (; *self; self++) {
 		const char32_t c = *self;
 		const char32_t c = *self;
@@ -4716,7 +4739,9 @@ String String::sprintf(const Array &values, bool *error) const {
 		return "not all arguments converted during string formatting";
 		return "not all arguments converted during string formatting";
 	}
 	}
 
 
-	*error = false;
+	if (error) {
+		*error = false;
+	}
 	return formatted;
 	return formatted;
 }
 }
 
 

+ 4 - 0
core/ustring.h

@@ -254,6 +254,8 @@ public:
 
 
 	bool operator<(const String &p_str) const;
 	bool operator<(const String &p_str) const;
 	bool operator<=(const String &p_str) const;
 	bool operator<=(const String &p_str) const;
+	bool operator>(const String &p_str) const;
+	bool operator>=(const String &p_str) const;
 
 
 	signed char casecmp_to(const String &p_str) const;
 	signed char casecmp_to(const String &p_str) const;
 	signed char nocasecmp_to(const String &p_str) const;
 	signed char nocasecmp_to(const String &p_str) const;
@@ -456,6 +458,8 @@ public:
 
 
 bool operator==(const char *p_chr, const String &p_str);
 bool operator==(const char *p_chr, const String &p_str);
 bool operator==(const wchar_t *p_chr, const String &p_str);
 bool operator==(const wchar_t *p_chr, const String &p_str);
+bool operator!=(const char *p_chr, const String &p_str);
+bool operator!=(const wchar_t *p_chr, const String &p_str);
 
 
 String operator+(const char *p_chr, const String &p_str);
 String operator+(const char *p_chr, const String &p_str);
 String operator+(const wchar_t *p_chr, const String &p_str);
 String operator+(const wchar_t *p_chr, const String &p_str);

+ 8 - 1
core/variant.h

@@ -381,7 +381,6 @@ public:
 		OP_NEGATE,
 		OP_NEGATE,
 		OP_POSITIVE,
 		OP_POSITIVE,
 		OP_MODULE,
 		OP_MODULE,
-		OP_STRING_CONCAT,
 		//bitwise
 		//bitwise
 		OP_SHIFT_LEFT,
 		OP_SHIFT_LEFT,
 		OP_SHIFT_RIGHT,
 		OP_SHIFT_RIGHT,
@@ -409,6 +408,14 @@ public:
 		return res;
 		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();
 	void zero();
 	Variant duplicate(bool deep = false) const;
 	Variant duplicate(bool deep = false) const;
 	static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
 	static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);

File diff suppressed because it is too large
+ 1933 - 4426
core/variant_op.cpp


+ 3132 - 0
core/variant_setget.cpp

@@ -0,0 +1,3132 @@
+/*************************************************************************/
+/*  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/class_db.h"
+#include "core/core_string_names.h"
+#include "core/debugger/engine_debugger.h"
+
+void Variant::set_named(const StringName &p_index, const Variant &p_value, bool *r_valid) {
+	bool valid = false;
+	switch (type) {
+		case VECTOR2: {
+			if (p_value.type == Variant::INT) {
+				Vector2 *v = reinterpret_cast<Vector2 *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._int;
+					valid = true;
+				}
+			} else if (p_value.type == Variant::FLOAT) {
+				Vector2 *v = reinterpret_cast<Vector2 *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._float;
+					valid = true;
+				}
+			}
+
+		} break;
+		case VECTOR2I: {
+			if (p_value.type == Variant::INT) {
+				Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._int;
+					valid = true;
+				}
+			} else if (p_value.type == Variant::FLOAT) {
+				Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._float;
+					valid = true;
+				}
+			}
+
+		} break;
+		case RECT2: {
+			if (p_value.type == Variant::VECTOR2) {
+				Rect2 *v = reinterpret_cast<Rect2 *>(_data._mem);
+				//scalar name
+				if (p_index == CoreStringNames::singleton->position) {
+					v->position = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->size) {
+					v->size = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->end) {
+					v->size = *reinterpret_cast<const Vector2 *>(p_value._data._mem) - v->position;
+					valid = true;
+				}
+			}
+		} break;
+		case RECT2I: {
+			if (p_value.type == Variant::VECTOR2I) {
+				Rect2i *v = reinterpret_cast<Rect2i *>(_data._mem);
+				//scalar name
+				if (p_index == CoreStringNames::singleton->position) {
+					v->position = *reinterpret_cast<const Vector2i *>(p_value._data._mem);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->size) {
+					v->size = *reinterpret_cast<const Vector2i *>(p_value._data._mem);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->end) {
+					v->size = *reinterpret_cast<const Vector2i *>(p_value._data._mem) - v->position;
+					valid = true;
+				}
+			}
+		} break;
+		case TRANSFORM2D: {
+			if (p_value.type == Variant::VECTOR2) {
+				Transform2D *v = _data._transform2d;
+				if (p_index == CoreStringNames::singleton->x) {
+					v->elements[0] = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->elements[1] = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->origin) {
+					v->elements[2] = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
+					valid = true;
+				}
+			}
+
+		} break;
+		case VECTOR3: {
+			if (p_value.type == Variant::INT) {
+				Vector3 *v = reinterpret_cast<Vector3 *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->z) {
+					v->z = p_value._data._int;
+					valid = true;
+				}
+			} else if (p_value.type == Variant::FLOAT) {
+				Vector3 *v = reinterpret_cast<Vector3 *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->z) {
+					v->z = p_value._data._float;
+					valid = true;
+				}
+			}
+
+		} break;
+		case VECTOR3I: {
+			if (p_value.type == Variant::INT) {
+				Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->z) {
+					v->z = p_value._data._int;
+					valid = true;
+				}
+			} else if (p_value.type == Variant::FLOAT) {
+				Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->z) {
+					v->z = p_value._data._float;
+					valid = true;
+				}
+			}
+
+		} break;
+		case PLANE: {
+			if (p_value.type == Variant::INT) {
+				Plane *v = reinterpret_cast<Plane *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->normal.x = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->normal.y = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->z) {
+					v->normal.z = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->d) {
+					v->d = p_value._data._int;
+					valid = true;
+				}
+			} else if (p_value.type == Variant::FLOAT) {
+				Plane *v = reinterpret_cast<Plane *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->normal.x = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->normal.y = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->z) {
+					v->normal.z = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->d) {
+					v->d = p_value._data._float;
+					valid = true;
+				}
+
+			} else if (p_value.type == Variant::VECTOR3) {
+				Plane *v = reinterpret_cast<Plane *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->normal) {
+					v->normal = *reinterpret_cast<const Vector3 *>(p_value._data._mem);
+					valid = true;
+				}
+			}
+
+		} break;
+		case QUAT: {
+			if (p_value.type == Variant::INT) {
+				Quat *v = reinterpret_cast<Quat *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->z) {
+					v->z = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->w) {
+					v->w = p_value._data._int;
+					valid = true;
+				}
+			} else if (p_value.type == Variant::FLOAT) {
+				Quat *v = reinterpret_cast<Quat *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->x) {
+					v->x = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->y = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->z) {
+					v->z = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->w) {
+					v->w = p_value._data._float;
+					valid = true;
+				}
+			}
+
+		} break;
+		case AABB: {
+			if (p_value.type == Variant::VECTOR3) {
+				::AABB *v = _data._aabb;
+				//scalar name
+				if (p_index == CoreStringNames::singleton->position) {
+					v->position = *reinterpret_cast<const Vector3 *>(p_value._data._mem);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->size) {
+					v->size = *reinterpret_cast<const Vector3 *>(p_value._data._mem);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->end) {
+					v->size = *reinterpret_cast<const Vector3 *>(p_value._data._mem) - v->position;
+					valid = true;
+				}
+			}
+		} break;
+		case BASIS: {
+			if (p_value.type == Variant::VECTOR3) {
+				Basis *v = _data._basis;
+				//scalar name
+				if (p_index == CoreStringNames::singleton->x) {
+					v->set_axis(0, *reinterpret_cast<const Vector3 *>(p_value._data._mem));
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->y) {
+					v->set_axis(1, *reinterpret_cast<const Vector3 *>(p_value._data._mem));
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->z) {
+					v->set_axis(2, *reinterpret_cast<const Vector3 *>(p_value._data._mem));
+					valid = true;
+				}
+			}
+		} break;
+		case TRANSFORM: {
+			if (p_value.type == Variant::BASIS && p_index == CoreStringNames::singleton->basis) {
+				_data._transform->basis = *p_value._data._basis;
+				valid = true;
+			} else if (p_value.type == Variant::VECTOR3 && p_index == CoreStringNames::singleton->origin) {
+				_data._transform->origin = *reinterpret_cast<const Vector3 *>(p_value._data._mem);
+				valid = true;
+			}
+
+		} break;
+		case COLOR: {
+			if (p_value.type == Variant::INT) {
+				Color *v = reinterpret_cast<Color *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->r) {
+					v->r = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->g) {
+					v->g = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->b) {
+					v->b = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->a) {
+					v->a = p_value._data._int;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->r8) {
+					v->r = p_value._data._int / 255.0;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->g8) {
+					v->g = p_value._data._int / 255.0;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->b8) {
+					v->b = p_value._data._int / 255.0;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->a8) {
+					v->a = p_value._data._int / 255.0;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->h) {
+					v->set_hsv(p_value._data._int, v->get_s(), v->get_v(), v->a);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->s) {
+					v->set_hsv(v->get_h(), p_value._data._int, v->get_v(), v->a);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->v) {
+					v->set_hsv(v->get_h(), v->get_v(), p_value._data._int, v->a);
+					valid = true;
+				}
+			} else if (p_value.type == Variant::FLOAT) {
+				Color *v = reinterpret_cast<Color *>(_data._mem);
+				if (p_index == CoreStringNames::singleton->r) {
+					v->r = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->g) {
+					v->g = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->b) {
+					v->b = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->a) {
+					v->a = p_value._data._float;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->r8) {
+					v->r = p_value._data._float / 255.0;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->g8) {
+					v->g = p_value._data._float / 255.0;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->b8) {
+					v->b = p_value._data._float / 255.0;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->a8) {
+					v->a = p_value._data._float / 255.0;
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->h) {
+					v->set_hsv(p_value._data._float, v->get_s(), v->get_v(), v->a);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->s) {
+					v->set_hsv(v->get_h(), p_value._data._float, v->get_v(), v->a);
+					valid = true;
+				} else if (p_index == CoreStringNames::singleton->v) {
+					v->set_hsv(v->get_h(), v->get_s(), p_value._data._float, v->a);
+					valid = true;
+				}
+			}
+		} break;
+		case OBJECT: {
+#ifdef DEBUG_ENABLED
+			if (!_get_obj().obj) {
+				break;
+			} else if (EngineDebugger::is_active() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+				break;
+			}
+
+#endif
+			_get_obj().obj->set(p_index, p_value, &valid);
+
+		} break;
+		default: {
+			set(p_index.operator String(), p_value, &valid);
+		} break;
+	}
+
+	if (r_valid) {
+		*r_valid = valid;
+	}
+}
+
+Variant Variant::get_named(const StringName &p_index, bool *r_valid) const {
+	if (r_valid) {
+		*r_valid = true;
+	}
+
+	switch (type) {
+		case VECTOR2: {
+			const Vector2 *v = reinterpret_cast<const Vector2 *>(_data._mem);
+			if (p_index == CoreStringNames::singleton->x) {
+				return v->x;
+			} else if (p_index == CoreStringNames::singleton->y) {
+				return v->y;
+			}
+
+		} break;
+		case VECTOR2I: {
+			const Vector2i *v = reinterpret_cast<const Vector2i *>(_data._mem);
+			if (p_index == CoreStringNames::singleton->x) {
+				return v->x;
+			} else if (p_index == CoreStringNames::singleton->y) {
+				return v->y;
+			}
+
+		} break;
+		case RECT2: {
+			const Rect2 *v = reinterpret_cast<const Rect2 *>(_data._mem);
+			//scalar name
+			if (p_index == CoreStringNames::singleton->position) {
+				return v->position;
+			} else if (p_index == CoreStringNames::singleton->size) {
+				return v->size;
+			} else if (p_index == CoreStringNames::singleton->end) {
+				return v->size + v->position;
+			}
+		} break;
+		case RECT2I: {
+			const Rect2i *v = reinterpret_cast<const Rect2i *>(_data._mem);
+			//scalar name
+			if (p_index == CoreStringNames::singleton->position) {
+				return v->position;
+			} else if (p_index == CoreStringNames::singleton->size) {
+				return v->size;
+			} else if (p_index == CoreStringNames::singleton->end) {
+				return v->size + v->position;
+			}
+		} break;
+		case TRANSFORM2D: {
+			const Transform2D *v = _data._transform2d;
+			if (p_index == CoreStringNames::singleton->x) {
+				return v->elements[0];
+			} else if (p_index == CoreStringNames::singleton->y) {
+				return v->elements[1];
+			} else if (p_index == CoreStringNames::singleton->origin) {
+				return v->elements[2];
+			}
+
+		} break;
+		case VECTOR3: {
+			const Vector3 *v = reinterpret_cast<const Vector3 *>(_data._mem);
+			if (p_index == CoreStringNames::singleton->x) {
+				return v->x;
+			} else if (p_index == CoreStringNames::singleton->y) {
+				return v->y;
+			} else if (p_index == CoreStringNames::singleton->z) {
+				return v->z;
+			}
+
+		} break;
+		case VECTOR3I: {
+			const Vector3i *v = reinterpret_cast<const Vector3i *>(_data._mem);
+			if (p_index == CoreStringNames::singleton->x) {
+				return v->x;
+			} else if (p_index == CoreStringNames::singleton->y) {
+				return v->y;
+			} else if (p_index == CoreStringNames::singleton->z) {
+				return v->z;
+			}
+
+		} break;
+		case PLANE: {
+			const Plane *v = reinterpret_cast<const Plane *>(_data._mem);
+			if (p_index == CoreStringNames::singleton->x) {
+				return v->normal.x;
+			} else if (p_index == CoreStringNames::singleton->y) {
+				return v->normal.y;
+			} else if (p_index == CoreStringNames::singleton->z) {
+				return v->normal.z;
+			} else if (p_index == CoreStringNames::singleton->d) {
+				return v->d;
+			} else if (p_index == CoreStringNames::singleton->normal) {
+				return v->normal;
+			}
+
+		} break;
+		case QUAT: {
+			const Quat *v = reinterpret_cast<const Quat *>(_data._mem);
+			if (p_index == CoreStringNames::singleton->x) {
+				return v->x;
+			} else if (p_index == CoreStringNames::singleton->y) {
+				return v->y;
+			} else if (p_index == CoreStringNames::singleton->z) {
+				return v->z;
+			} else if (p_index == CoreStringNames::singleton->w) {
+				return v->w;
+			}
+
+		} break;
+		case AABB: {
+			const ::AABB *v = _data._aabb;
+			//scalar name
+			if (p_index == CoreStringNames::singleton->position) {
+				return v->position;
+			} else if (p_index == CoreStringNames::singleton->size) {
+				return v->size;
+			} else if (p_index == CoreStringNames::singleton->end) {
+				return v->size + v->position;
+			}
+		} break;
+		case BASIS: {
+			const Basis *v = _data._basis;
+			//scalar name
+			if (p_index == CoreStringNames::singleton->x) {
+				return v->get_axis(0);
+			} else if (p_index == CoreStringNames::singleton->y) {
+				return v->get_axis(1);
+			} else if (p_index == CoreStringNames::singleton->z) {
+				return v->get_axis(2);
+			}
+
+		} break;
+		case TRANSFORM: {
+			if (p_index == CoreStringNames::singleton->basis) {
+				return _data._transform->basis;
+			} else if (p_index == CoreStringNames::singleton->origin) {
+				return _data._transform->origin;
+			}
+
+		} break;
+		case COLOR: {
+			const Color *v = reinterpret_cast<const Color *>(_data._mem);
+			if (p_index == CoreStringNames::singleton->r) {
+				return v->r;
+			} else if (p_index == CoreStringNames::singleton->g) {
+				return v->g;
+			} else if (p_index == CoreStringNames::singleton->b) {
+				return v->b;
+			} else if (p_index == CoreStringNames::singleton->a) {
+				return v->a;
+			} else if (p_index == CoreStringNames::singleton->r8) {
+				return int(Math::round(v->r * 255.0));
+			} else if (p_index == CoreStringNames::singleton->g8) {
+				return int(Math::round(v->g * 255.0));
+			} else if (p_index == CoreStringNames::singleton->b8) {
+				return int(Math::round(v->b * 255.0));
+			} else if (p_index == CoreStringNames::singleton->a8) {
+				return int(Math::round(v->a * 255.0));
+			} else if (p_index == CoreStringNames::singleton->h) {
+				return v->get_h();
+			} else if (p_index == CoreStringNames::singleton->s) {
+				return v->get_s();
+			} else if (p_index == CoreStringNames::singleton->v) {
+				return v->get_v();
+			}
+		} break;
+		case OBJECT: {
+#ifdef DEBUG_ENABLED
+			if (!_get_obj().obj) {
+				if (r_valid) {
+					*r_valid = false;
+				}
+				return "Instance base is null.";
+			} else {
+				if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+					if (r_valid) {
+						*r_valid = false;
+					}
+					return "Attempted use of stray pointer object.";
+				}
+			}
+
+#endif
+
+			return _get_obj().obj->get(p_index, r_valid);
+
+		} break;
+		default: {
+			return get(p_index.operator String(), r_valid);
+		}
+	}
+
+	if (r_valid) {
+		*r_valid = false;
+	}
+	return Variant();
+}
+
+#define DEFAULT_OP_ARRAY_CMD(m_name, m_type, skip_test, cmd)                              \
+	case m_name: {                                                                        \
+		skip_test;                                                                        \
+                                                                                          \
+		if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) { \
+			int index = p_index;                                                          \
+			m_type *arr = reinterpret_cast<m_type *>(_data._mem);                         \
+                                                                                          \
+			if (index < 0)                                                                \
+				index += arr->size();                                                     \
+			if (index >= 0 && index < arr->size()) {                                      \
+				valid = true;                                                             \
+				cmd;                                                                      \
+			}                                                                             \
+		}                                                                                 \
+	} break;
+
+#define DEFAULT_OP_DVECTOR_SET(m_name, m_type, skip_cond)                                    \
+	case m_name: {                                                                           \
+		if (skip_cond)                                                                       \
+			return;                                                                          \
+                                                                                             \
+		if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {    \
+			int index = p_index;                                                             \
+			Vector<m_type> *arr = PackedArrayRef<m_type>::get_array_ptr(_data.packed_array); \
+                                                                                             \
+			if (index < 0)                                                                   \
+				index += arr->size();                                                        \
+			if (index >= 0 && index < arr->size()) {                                         \
+				valid = true;                                                                \
+				arr->set(index, p_value);                                                    \
+			}                                                                                \
+		}                                                                                    \
+	} break;
+
+#define DEFAULT_OP_DVECTOR_GET(m_name, m_type)                                                  \
+	case m_name: {                                                                              \
+		if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {       \
+			int index = p_index;                                                                \
+			const Vector<m_type> *arr = &PackedArrayRef<m_type>::get_array(_data.packed_array); \
+                                                                                                \
+			if (index < 0)                                                                      \
+				index += arr->size();                                                           \
+			if (index >= 0 && index < arr->size()) {                                            \
+				valid = true;                                                                   \
+				return arr->get(index);                                                         \
+			}                                                                                   \
+		}                                                                                       \
+	} break;
+
+void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) {
+	static bool _dummy = false;
+
+	bool &valid = r_valid ? *r_valid : _dummy;
+	valid = false;
+
+	switch (type) {
+		case NIL: {
+			return;
+		} break;
+		case BOOL: {
+			return;
+		} break;
+		case INT: {
+			return;
+		} break;
+		case FLOAT: {
+			return;
+		} break;
+		case STRING: {
+			if (p_index.type != Variant::INT && p_index.type != Variant::FLOAT) {
+				return;
+			}
+
+			int idx = p_index;
+			String *str = reinterpret_cast<String *>(_data._mem);
+			int len = str->length();
+			if (idx < 0) {
+				idx += len;
+			}
+			if (idx < 0 || idx >= len) {
+				return;
+			}
+
+			String chr;
+			if (p_value.type == Variant::INT || p_value.type == Variant::FLOAT) {
+				chr = String::chr(p_value);
+			} else if (p_value.type == Variant::STRING) {
+				chr = p_value;
+			} else {
+				return;
+			}
+
+			*str = str->substr(0, idx) + chr + str->substr(idx + 1, len);
+			valid = true;
+			return;
+
+		} break;
+		case VECTOR2: {
+			if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				// scalar index
+				int idx = p_index;
+
+				if (idx < 0) {
+					idx += 2;
+				}
+				if (idx >= 0 && idx < 2) {
+					Vector2 *v = reinterpret_cast<Vector2 *>(_data._mem);
+					valid = true;
+					(*v)[idx] = p_value;
+					return;
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Vector2 *v = reinterpret_cast<Vector2 *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					v->x = p_value;
+					return;
+				} else if (*str == "y") {
+					valid = true;
+					v->y = p_value;
+					return;
+				}
+			}
+
+		} break;
+		case VECTOR2I: {
+			if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				// scalar index
+				int idx = p_index;
+
+				if (idx < 0) {
+					idx += 2;
+				}
+				if (idx >= 0 && idx < 2) {
+					Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem);
+					valid = true;
+					(*v)[idx] = p_value;
+					return;
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					v->x = p_value;
+					return;
+				} else if (*str == "y") {
+					valid = true;
+					v->y = p_value;
+					return;
+				}
+			}
+
+		} break;
+		case RECT2: {
+			if (p_value.type != Variant::VECTOR2) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Rect2 *v = reinterpret_cast<Rect2 *>(_data._mem);
+				if (*str == "position") {
+					valid = true;
+					v->position = p_value;
+					return;
+				} else if (*str == "size") {
+					valid = true;
+					v->size = p_value;
+					return;
+				} else if (*str == "end") {
+					valid = true;
+					v->size = Vector2(p_value) - v->position;
+					return;
+				}
+			}
+		} break;
+		case RECT2I: {
+			if (p_value.type != Variant::VECTOR2I) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Rect2i *v = reinterpret_cast<Rect2i *>(_data._mem);
+				if (*str == "position") {
+					valid = true;
+					v->position = p_value;
+					return;
+				} else if (*str == "size") {
+					valid = true;
+					v->size = p_value;
+					return;
+				} else if (*str == "end") {
+					valid = true;
+					v->size = Vector2i(p_value) - v->position;
+					return;
+				}
+			}
+		} break;
+		case TRANSFORM2D: {
+			if (p_value.type != Variant::VECTOR2) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				int index = p_index;
+
+				if (index < 0) {
+					index += 3;
+				}
+				if (index >= 0 && index < 3) {
+					Transform2D *v = _data._transform2d;
+
+					valid = true;
+					v->elements[index] = p_value;
+					return;
+				}
+			} else if (p_index.get_type() == Variant::STRING && p_value.get_type() == Variant::VECTOR2) {
+				//scalar name
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Transform2D *v = _data._transform2d;
+				if (*str == "x") {
+					valid = true;
+					v->elements[0] = p_value;
+					return;
+				} else if (*str == "y") {
+					valid = true;
+					v->elements[1] = p_value;
+					return;
+				} else if (*str == "origin") {
+					valid = true;
+					v->elements[2] = p_value;
+					return;
+				}
+			}
+
+		} break;
+		case VECTOR3: {
+			if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				//scalar index
+				int idx = p_index;
+				if (idx < 0) {
+					idx += 3;
+				}
+				if (idx >= 0 && idx < 3) {
+					Vector3 *v = reinterpret_cast<Vector3 *>(_data._mem);
+					valid = true;
+					(*v)[idx] = p_value;
+					return;
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Vector3 *v = reinterpret_cast<Vector3 *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					v->x = p_value;
+					return;
+				} else if (*str == "y") {
+					valid = true;
+					v->y = p_value;
+					return;
+				} else if (*str == "z") {
+					valid = true;
+					v->z = p_value;
+					return;
+				}
+			}
+
+		} break;
+		case VECTOR3I: {
+			if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				//scalar index
+				int idx = p_index;
+				if (idx < 0) {
+					idx += 3;
+				}
+				if (idx >= 0 && idx < 3) {
+					Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem);
+					valid = true;
+					(*v)[idx] = p_value;
+					return;
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					v->x = p_value;
+					return;
+				} else if (*str == "y") {
+					valid = true;
+					v->y = p_value;
+					return;
+				} else if (*str == "z") {
+					valid = true;
+					v->z = p_value;
+					return;
+				}
+			}
+
+		} break;
+		case PLANE: {
+			if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Plane *v = reinterpret_cast<Plane *>(_data._mem);
+				if (*str == "x") {
+					if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
+						return;
+					}
+
+					valid = true;
+					v->normal.x = p_value;
+					return;
+				} else if (*str == "y") {
+					if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
+						return;
+					}
+
+					valid = true;
+					v->normal.y = p_value;
+					return;
+				} else if (*str == "z") {
+					if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
+						return;
+					}
+
+					valid = true;
+					v->normal.z = p_value;
+					return;
+				} else if (*str == "normal") {
+					if (p_value.type != Variant::VECTOR3) {
+						return;
+					}
+
+					valid = true;
+					v->normal = p_value;
+					return;
+				} else if (*str == "d") {
+					valid = true;
+					v->d = p_value;
+					return;
+				}
+			}
+
+		} break;
+		case QUAT: {
+			if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::STRING) {
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Quat *v = reinterpret_cast<Quat *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					v->x = p_value;
+					return;
+				} else if (*str == "y") {
+					valid = true;
+					v->y = p_value;
+					return;
+				} else if (*str == "z") {
+					valid = true;
+					v->z = p_value;
+					return;
+				} else if (*str == "w") {
+					valid = true;
+					v->w = p_value;
+					return;
+				}
+			}
+
+		} break;
+		case AABB: {
+			if (p_value.type != Variant::VECTOR3) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				::AABB *v = _data._aabb;
+				if (*str == "position") {
+					valid = true;
+					v->position = p_value;
+					return;
+				} else if (*str == "size") {
+					valid = true;
+					v->size = p_value;
+					return;
+				} else if (*str == "end") {
+					valid = true;
+					v->size = Vector3(p_value) - v->position;
+					return;
+				}
+			}
+		} break;
+		case BASIS: {
+			if (p_value.type != Variant::VECTOR3) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				int index = p_index;
+
+				if (index < 0) {
+					index += 3;
+				}
+				if (index >= 0 && index < 3) {
+					Basis *v = _data._basis;
+
+					valid = true;
+					v->set_axis(index, p_value);
+					return;
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Basis *v = _data._basis;
+
+				if (*str == "x") {
+					valid = true;
+					v->set_axis(0, p_value);
+					return;
+				} else if (*str == "y") {
+					valid = true;
+					v->set_axis(1, p_value);
+					return;
+				} else if (*str == "z") {
+					valid = true;
+					v->set_axis(2, p_value);
+					return;
+				}
+			}
+
+		} break;
+		case TRANSFORM: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				if (p_value.type != Variant::VECTOR3) {
+					return;
+				}
+
+				int index = p_index;
+
+				if (index < 0) {
+					index += 4;
+				}
+				if (index >= 0 && index < 4) {
+					Transform *v = _data._transform;
+					valid = true;
+					if (index == 3) {
+						v->origin = p_value;
+					} else {
+						v->basis.set_axis(index, p_value);
+					}
+					return;
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				Transform *v = _data._transform;
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+
+				if (*str == "basis") {
+					if (p_value.type != Variant::BASIS) {
+						return;
+					}
+					valid = true;
+					v->basis = p_value;
+					return;
+				}
+				if (*str == "origin") {
+					if (p_value.type != Variant::VECTOR3) {
+						return;
+					}
+					valid = true;
+					v->origin = p_value;
+					return;
+				}
+			}
+
+		} break;
+		case COLOR: {
+			if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
+				return;
+			}
+
+			if (p_index.get_type() == Variant::STRING) {
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				Color *v = reinterpret_cast<Color *>(_data._mem);
+				if (*str == "r") {
+					valid = true;
+					v->r = p_value;
+					return;
+				} else if (*str == "g") {
+					valid = true;
+					v->g = p_value;
+					return;
+				} else if (*str == "b") {
+					valid = true;
+					v->b = p_value;
+					return;
+				} else if (*str == "a") {
+					valid = true;
+					v->a = p_value;
+					return;
+				} else if (*str == "h") {
+					valid = true;
+					v->set_hsv(p_value, v->get_s(), v->get_v(), v->a);
+					return;
+				} else if (*str == "s") {
+					valid = true;
+					v->set_hsv(v->get_h(), p_value, v->get_v(), v->a);
+					return;
+				} else if (*str == "v") {
+					valid = true;
+					v->set_hsv(v->get_h(), v->get_s(), p_value, v->a);
+					return;
+				} else if (*str == "r8") {
+					valid = true;
+					v->r = float(p_value) / 255.0;
+					return;
+				} else if (*str == "g8") {
+					valid = true;
+					v->g = float(p_value) / 255.0;
+					return;
+				} else if (*str == "b8") {
+					valid = true;
+					v->b = float(p_value) / 255.0;
+					return;
+				} else if (*str == "a8") {
+					valid = true;
+					v->a = float(p_value) / 255.0;
+					return;
+				}
+			} else if (p_index.get_type() == Variant::INT) {
+				int idx = p_index;
+				if (idx < 0) {
+					idx += 4;
+				}
+				if (idx >= 0 && idx < 4) {
+					Color *v = reinterpret_cast<Color *>(_data._mem);
+					(*v)[idx] = p_value;
+					valid = true;
+				}
+			}
+
+		} break;
+		case STRING_NAME: {
+		} break;
+		case NODE_PATH: {
+		} break;
+		case _RID: {
+		} break;
+		case OBJECT: {
+			Object *obj = _get_obj().obj;
+			//only if debugging!
+
+			if (obj) {
+#ifdef DEBUG_ENABLED
+				if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+					WARN_PRINT("Attempted use of previously freed pointer object.");
+					valid = false;
+					return;
+				}
+#endif
+
+				if (p_index.get_type() != Variant::STRING_NAME && p_index.get_type() != Variant::STRING) {
+					obj->setvar(p_index, p_value, r_valid);
+					return;
+				}
+
+				obj->set(p_index, p_value, r_valid);
+				return;
+			}
+		} break;
+		case DICTIONARY: {
+			Dictionary *dic = reinterpret_cast<Dictionary *>(_data._mem);
+			dic->operator[](p_index) = p_value;
+			valid = true; //always valid, i guess? should this really be ok?
+			return;
+		} break;
+			DEFAULT_OP_ARRAY_CMD(ARRAY, Array, ;, (*arr)[index] = p_value; return )
+			DEFAULT_OP_DVECTOR_SET(PACKED_BYTE_ARRAY, uint8_t, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
+			DEFAULT_OP_DVECTOR_SET(PACKED_INT32_ARRAY, int32_t, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
+			DEFAULT_OP_DVECTOR_SET(PACKED_INT64_ARRAY, int64_t, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
+			DEFAULT_OP_DVECTOR_SET(PACKED_FLOAT32_ARRAY, float, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
+			DEFAULT_OP_DVECTOR_SET(PACKED_FLOAT64_ARRAY, double, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
+			DEFAULT_OP_DVECTOR_SET(PACKED_STRING_ARRAY, String, p_value.type != Variant::STRING)
+			DEFAULT_OP_DVECTOR_SET(PACKED_VECTOR2_ARRAY, Vector2, p_value.type != Variant::VECTOR2)
+			DEFAULT_OP_DVECTOR_SET(PACKED_VECTOR3_ARRAY, Vector3, p_value.type != Variant::VECTOR3)
+			DEFAULT_OP_DVECTOR_SET(PACKED_COLOR_ARRAY, Color, p_value.type != Variant::COLOR)
+		default:
+			return;
+	}
+}
+
+Variant Variant::get(const Variant &p_index, bool *r_valid) const {
+	static bool _dummy = false;
+
+	bool &valid = r_valid ? *r_valid : _dummy;
+
+	valid = false;
+
+	switch (type) {
+		case NIL: {
+			return Variant();
+		} break;
+		case BOOL: {
+			return Variant();
+		} break;
+		case INT: {
+			return Variant();
+		} break;
+		case FLOAT: {
+			return Variant();
+		} break;
+		case STRING: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				//string index
+
+				int idx = p_index;
+				const String *str = reinterpret_cast<const String *>(_data._mem);
+				if (idx < 0) {
+					idx += str->length();
+				}
+				if (idx >= 0 && idx < str->length()) {
+					valid = true;
+					return str->substr(idx, 1);
+				}
+			}
+
+		} break;
+		case VECTOR2: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				// scalar index
+				int idx = p_index;
+				if (idx < 0) {
+					idx += 2;
+				}
+				if (idx >= 0 && idx < 2) {
+					const Vector2 *v = reinterpret_cast<const Vector2 *>(_data._mem);
+					valid = true;
+					return (*v)[idx];
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Vector2 *v = reinterpret_cast<const Vector2 *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					return v->x;
+				} else if (*str == "y") {
+					valid = true;
+					return v->y;
+				}
+			}
+
+		} break;
+		case VECTOR2I: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				// scalar index
+				int idx = p_index;
+				if (idx < 0) {
+					idx += 2;
+				}
+				if (idx >= 0 && idx < 2) {
+					const Vector2i *v = reinterpret_cast<const Vector2i *>(_data._mem);
+					valid = true;
+					return (*v)[idx];
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Vector2i *v = reinterpret_cast<const Vector2i *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					return v->x;
+				} else if (*str == "y") {
+					valid = true;
+					return v->y;
+				}
+			}
+
+		} break;
+		case RECT2: {
+			if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Rect2 *v = reinterpret_cast<const Rect2 *>(_data._mem);
+				if (*str == "position") {
+					valid = true;
+					return v->position;
+				} else if (*str == "size") {
+					valid = true;
+					return v->size;
+				} else if (*str == "end") {
+					valid = true;
+					return v->size + v->position;
+				}
+			}
+		} break;
+		case RECT2I: {
+			if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Rect2i *v = reinterpret_cast<const Rect2i *>(_data._mem);
+				if (*str == "position") {
+					valid = true;
+					return v->position;
+				} else if (*str == "size") {
+					valid = true;
+					return v->size;
+				} else if (*str == "end") {
+					valid = true;
+					return v->size + v->position;
+				}
+			}
+		} break;
+		case VECTOR3: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				//scalar index
+				int idx = p_index;
+				if (idx < 0) {
+					idx += 3;
+				}
+				if (idx >= 0 && idx < 3) {
+					const Vector3 *v = reinterpret_cast<const Vector3 *>(_data._mem);
+					valid = true;
+					return (*v)[idx];
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Vector3 *v = reinterpret_cast<const Vector3 *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					return v->x;
+				} else if (*str == "y") {
+					valid = true;
+					return v->y;
+				} else if (*str == "z") {
+					valid = true;
+					return v->z;
+				}
+			}
+
+		} break;
+		case VECTOR3I: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				//scalar index
+				int idx = p_index;
+				if (idx < 0) {
+					idx += 3;
+				}
+				if (idx >= 0 && idx < 3) {
+					const Vector3i *v = reinterpret_cast<const Vector3i *>(_data._mem);
+					valid = true;
+					return (*v)[idx];
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Vector3i *v = reinterpret_cast<const Vector3i *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					return v->x;
+				} else if (*str == "y") {
+					valid = true;
+					return v->y;
+				} else if (*str == "z") {
+					valid = true;
+					return v->z;
+				}
+			}
+
+		} break;
+		case TRANSFORM2D: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				int index = p_index;
+
+				if (index < 0) {
+					index += 3;
+				}
+				if (index >= 0 && index < 3) {
+					const Transform2D *v = _data._transform2d;
+
+					valid = true;
+					return v->elements[index];
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Transform2D *v = _data._transform2d;
+				if (*str == "x") {
+					valid = true;
+					return v->elements[0];
+				} else if (*str == "y") {
+					valid = true;
+					return v->elements[1];
+				} else if (*str == "origin") {
+					valid = true;
+					return v->elements[2];
+				}
+			}
+
+		} break;
+		case PLANE: {
+			if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Plane *v = reinterpret_cast<const Plane *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					return v->normal.x;
+				} else if (*str == "y") {
+					valid = true;
+					return v->normal.y;
+				} else if (*str == "z") {
+					valid = true;
+					return v->normal.z;
+				} else if (*str == "normal") {
+					valid = true;
+					return v->normal;
+				} else if (*str == "d") {
+					valid = true;
+					return v->d;
+				}
+			}
+
+		} break;
+		case QUAT: {
+			if (p_index.get_type() == Variant::STRING) {
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Quat *v = reinterpret_cast<const Quat *>(_data._mem);
+				if (*str == "x") {
+					valid = true;
+					return v->x;
+				} else if (*str == "y") {
+					valid = true;
+					return v->y;
+				} else if (*str == "z") {
+					valid = true;
+					return v->z;
+				} else if (*str == "w") {
+					valid = true;
+					return v->w;
+				}
+			}
+
+		} break;
+		case AABB: {
+			if (p_index.get_type() == Variant::STRING) {
+				//scalar name
+
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const ::AABB *v = _data._aabb;
+				if (*str == "position") {
+					valid = true;
+					return v->position;
+				} else if (*str == "size") {
+					valid = true;
+					return v->size;
+				} else if (*str == "end") {
+					valid = true;
+					return v->size + v->position;
+				}
+			}
+		} break;
+		case BASIS: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				int index = p_index;
+				if (index < 0) {
+					index += 3;
+				}
+				if (index >= 0 && index < 3) {
+					const Basis *v = _data._basis;
+
+					valid = true;
+					return v->get_axis(index);
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Basis *v = _data._basis;
+
+				if (*str == "x") {
+					valid = true;
+					return v->get_axis(0);
+				} else if (*str == "y") {
+					valid = true;
+					return v->get_axis(1);
+				} else if (*str == "z") {
+					valid = true;
+					return v->get_axis(2);
+				}
+			}
+
+		} break;
+		case TRANSFORM: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				int index = p_index;
+				if (index < 0) {
+					index += 4;
+				}
+				if (index >= 0 && index < 4) {
+					const Transform *v = _data._transform;
+					valid = true;
+					return index == 3 ? v->origin : v->basis.get_axis(index);
+				}
+			} else if (p_index.get_type() == Variant::STRING) {
+				const Transform *v = _data._transform;
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+
+				if (*str == "basis") {
+					valid = true;
+					return v->basis;
+				}
+				if (*str == "origin") {
+					valid = true;
+					return v->origin;
+				}
+			}
+
+		} break;
+		case COLOR: {
+			if (p_index.get_type() == Variant::STRING) {
+				const String *str = reinterpret_cast<const String *>(p_index._data._mem);
+				const Color *v = reinterpret_cast<const Color *>(_data._mem);
+				if (*str == "r") {
+					valid = true;
+					return v->r;
+				} else if (*str == "g") {
+					valid = true;
+					return v->g;
+				} else if (*str == "b") {
+					valid = true;
+					return v->b;
+				} else if (*str == "a") {
+					valid = true;
+					return v->a;
+				} else if (*str == "h") {
+					valid = true;
+					return v->get_h();
+				} else if (*str == "s") {
+					valid = true;
+					return v->get_s();
+				} else if (*str == "v") {
+					valid = true;
+					return v->get_v();
+				} else if (*str == "r8") {
+					valid = true;
+					return (int)Math::round(v->r * 255.0);
+				} else if (*str == "g8") {
+					valid = true;
+					return (int)Math::round(v->g * 255.0);
+				} else if (*str == "b8") {
+					valid = true;
+					return (int)Math::round(v->b * 255.0);
+				} else if (*str == "a8") {
+					valid = true;
+					return (int)Math::round(v->a * 255.0);
+				}
+			} else if (p_index.get_type() == Variant::INT) {
+				int idx = p_index;
+				if (idx < 0) {
+					idx += 4;
+				}
+				if (idx >= 0 && idx < 4) {
+					const Color *v = reinterpret_cast<const Color *>(_data._mem);
+					valid = true;
+					return (*v)[idx];
+				}
+			}
+
+		} break;
+		case STRING_NAME: {
+		} break;
+		case NODE_PATH: {
+		} break;
+		case _RID: {
+		} break;
+		case OBJECT: {
+			Object *obj = _get_obj().obj;
+			if (obj) {
+#ifdef DEBUG_ENABLED
+
+				if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+					valid = false;
+					return "Attempted get on previously freed instance.";
+				}
+#endif
+
+				if (p_index.get_type() != Variant::STRING) {
+					return obj->getvar(p_index, r_valid);
+				}
+
+				return obj->get(p_index, r_valid);
+			}
+
+		} break;
+		case DICTIONARY: {
+			const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
+			const Variant *res = dic->getptr(p_index);
+			if (res) {
+				valid = true;
+				return *res;
+			}
+		} break;
+			DEFAULT_OP_ARRAY_CMD(ARRAY, const Array, ;, return (*arr)[index])
+			DEFAULT_OP_DVECTOR_GET(PACKED_BYTE_ARRAY, uint8_t)
+			DEFAULT_OP_DVECTOR_GET(PACKED_INT32_ARRAY, int32_t)
+			DEFAULT_OP_DVECTOR_GET(PACKED_INT64_ARRAY, int64_t)
+			DEFAULT_OP_DVECTOR_GET(PACKED_FLOAT32_ARRAY, float)
+			DEFAULT_OP_DVECTOR_GET(PACKED_FLOAT64_ARRAY, double)
+			DEFAULT_OP_DVECTOR_GET(PACKED_STRING_ARRAY, String)
+			DEFAULT_OP_DVECTOR_GET(PACKED_VECTOR2_ARRAY, Vector2)
+			DEFAULT_OP_DVECTOR_GET(PACKED_VECTOR3_ARRAY, Vector3)
+			DEFAULT_OP_DVECTOR_GET(PACKED_COLOR_ARRAY, Color)
+		default:
+			return Variant();
+	}
+
+	return Variant();
+}
+
+bool Variant::in(const Variant &p_index, bool *r_valid) const {
+	if (r_valid) {
+		*r_valid = true;
+	}
+
+	switch (type) {
+		case STRING: {
+			if (p_index.get_type() == Variant::STRING) {
+				//string index
+				String idx = p_index;
+				const String *str = reinterpret_cast<const String *>(_data._mem);
+
+				return str->find(idx) != -1;
+			}
+
+		} break;
+		case OBJECT: {
+			Object *obj = _get_obj().obj;
+			if (obj) {
+				bool valid = false;
+#ifdef DEBUG_ENABLED
+
+				if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+					if (r_valid) {
+						*r_valid = false;
+					}
+					return true; // Attempted get on stray pointer.
+				}
+
+#endif
+
+				if (p_index.get_type() != Variant::STRING) {
+					obj->getvar(p_index, &valid);
+				} else {
+					obj->get(p_index, &valid);
+				}
+
+				return valid;
+			} else {
+				if (r_valid) {
+					*r_valid = false;
+				}
+			}
+			return false;
+		} break;
+		case DICTIONARY: {
+			const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
+			return dic->has(p_index);
+
+		} break;
+		case ARRAY: {
+			const Array *arr = reinterpret_cast<const Array *>(_data._mem);
+			int l = arr->size();
+			if (l) {
+				for (int i = 0; i < l; i++) {
+					if (evaluate(OP_EQUAL, (*arr)[i], p_index)) {
+						return true;
+					}
+				}
+			}
+
+			return false;
+
+		} break;
+		case PACKED_BYTE_ARRAY: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				int index = p_index;
+				const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
+				int l = arr->size();
+				if (l) {
+					const uint8_t *r = arr->ptr();
+					for (int i = 0; i < l; i++) {
+						if (r[i] == index) {
+							return true;
+						}
+					}
+				}
+
+				return false;
+			}
+
+		} break;
+		case PACKED_INT32_ARRAY: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				int32_t index = p_index;
+				const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
+				int32_t l = arr->size();
+				if (l) {
+					const int32_t *r = arr->ptr();
+					for (int32_t i = 0; i < l; i++) {
+						if (r[i] == index) {
+							return true;
+						}
+					}
+				}
+
+				return false;
+			}
+		} break;
+		case PACKED_INT64_ARRAY: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				int64_t index = p_index;
+				const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
+				int64_t l = arr->size();
+				if (l) {
+					const int64_t *r = arr->ptr();
+					for (int64_t i = 0; i < l; i++) {
+						if (r[i] == index) {
+							return true;
+						}
+					}
+				}
+
+				return false;
+			}
+		} break;
+		case PACKED_FLOAT32_ARRAY: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				real_t index = p_index;
+				const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
+				int l = arr->size();
+				if (l) {
+					const float *r = arr->ptr();
+					for (int i = 0; i < l; i++) {
+						if (r[i] == index) {
+							return true;
+						}
+					}
+				}
+
+				return false;
+			}
+
+		} break;
+		case PACKED_FLOAT64_ARRAY: {
+			if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
+				real_t index = p_index;
+				const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
+				int l = arr->size();
+				if (l) {
+					const double *r = arr->ptr();
+					for (int i = 0; i < l; i++) {
+						if (r[i] == index) {
+							return true;
+						}
+					}
+				}
+
+				return false;
+			}
+
+		} break;
+		case PACKED_STRING_ARRAY: {
+			if (p_index.get_type() == Variant::STRING) {
+				String index = p_index;
+				const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
+
+				int l = arr->size();
+				if (l) {
+					const String *r = arr->ptr();
+					for (int i = 0; i < l; i++) {
+						if (r[i] == index) {
+							return true;
+						}
+					}
+				}
+
+				return false;
+			}
+
+		} break; //25
+		case PACKED_VECTOR2_ARRAY: {
+			if (p_index.get_type() == Variant::VECTOR2) {
+				Vector2 index = p_index;
+				const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
+
+				int l = arr->size();
+				if (l) {
+					const Vector2 *r = arr->ptr();
+					for (int i = 0; i < l; i++) {
+						if (r[i] == index) {
+							return true;
+						}
+					}
+				}
+
+				return false;
+			}
+
+		} break;
+		case PACKED_VECTOR3_ARRAY: {
+			if (p_index.get_type() == Variant::VECTOR3) {
+				Vector3 index = p_index;
+				const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
+
+				int l = arr->size();
+				if (l) {
+					const Vector3 *r = arr->ptr();
+					for (int i = 0; i < l; i++) {
+						if (r[i] == index) {
+							return true;
+						}
+					}
+				}
+
+				return false;
+			}
+
+		} break;
+		case PACKED_COLOR_ARRAY: {
+			if (p_index.get_type() == Variant::COLOR) {
+				Color index = p_index;
+				const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
+
+				int l = arr->size();
+				if (l) {
+					const Color *r = arr->ptr();
+					for (int i = 0; i < l; i++) {
+						if (r[i] == index) {
+							return true;
+						}
+					}
+				}
+
+				return false;
+			}
+		} break;
+		default: {
+		}
+	}
+
+	if (r_valid) {
+		*r_valid = false;
+	}
+	return false;
+}
+
+void Variant::get_property_list(List<PropertyInfo> *p_list) const {
+	switch (type) {
+		case VECTOR2: {
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "x"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "y"));
+
+		} break;
+		case VECTOR2I: {
+			p_list->push_back(PropertyInfo(Variant::INT, "x"));
+			p_list->push_back(PropertyInfo(Variant::INT, "y"));
+
+		} break;
+		case RECT2: {
+			p_list->push_back(PropertyInfo(Variant::VECTOR2, "position"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR2, "size"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR2, "end"));
+
+		} break;
+		case RECT2I: {
+			p_list->push_back(PropertyInfo(Variant::VECTOR2I, "position"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR2I, "end"));
+
+		} break;
+		case VECTOR3: {
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "x"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "y"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "z"));
+
+		} break;
+		case VECTOR3I: {
+			p_list->push_back(PropertyInfo(Variant::INT, "x"));
+			p_list->push_back(PropertyInfo(Variant::INT, "y"));
+			p_list->push_back(PropertyInfo(Variant::INT, "z"));
+
+		} break;
+		case TRANSFORM2D: {
+			p_list->push_back(PropertyInfo(Variant::VECTOR2, "x"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR2, "y"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR2, "origin"));
+
+		} break;
+		case PLANE: {
+			p_list->push_back(PropertyInfo(Variant::VECTOR3, "normal"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "x"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "y"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "z"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "d"));
+
+		} break;
+		case QUAT: {
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "x"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "y"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "z"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "w"));
+
+		} break;
+		case AABB: {
+			p_list->push_back(PropertyInfo(Variant::VECTOR3, "position"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR3, "size"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR3, "end"));
+		} break;
+		case BASIS: {
+			p_list->push_back(PropertyInfo(Variant::VECTOR3, "x"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR3, "y"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR3, "z"));
+
+		} break;
+		case TRANSFORM: {
+			p_list->push_back(PropertyInfo(Variant::BASIS, "basis"));
+			p_list->push_back(PropertyInfo(Variant::VECTOR3, "origin"));
+
+		} break;
+		case COLOR: {
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "r"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "g"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "b"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "a"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "h"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "s"));
+			p_list->push_back(PropertyInfo(Variant::FLOAT, "v"));
+			p_list->push_back(PropertyInfo(Variant::INT, "r8"));
+			p_list->push_back(PropertyInfo(Variant::INT, "g8"));
+			p_list->push_back(PropertyInfo(Variant::INT, "b8"));
+			p_list->push_back(PropertyInfo(Variant::INT, "a8"));
+
+		} break;
+		case STRING_NAME: {
+		} break;
+		case NODE_PATH: {
+		} break;
+		case _RID: {
+		} break;
+		case OBJECT: {
+			Object *obj = _get_obj().obj;
+			if (obj) {
+#ifdef DEBUG_ENABLED
+
+				if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+					WARN_PRINT("Attempted get_property list on previously freed instance.");
+					return;
+				}
+
+#endif
+
+				obj->get_property_list(p_list);
+			}
+
+		} break;
+		case 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()));
+				}
+			}
+		} break;
+		case ARRAY:
+		case PACKED_BYTE_ARRAY:
+		case PACKED_INT32_ARRAY:
+		case PACKED_INT64_ARRAY:
+		case PACKED_FLOAT32_ARRAY:
+		case PACKED_FLOAT64_ARRAY:
+		case PACKED_STRING_ARRAY:
+		case PACKED_VECTOR2_ARRAY:
+		case PACKED_VECTOR3_ARRAY:
+		case PACKED_COLOR_ARRAY: {
+			//nothing
+		} break;
+		default: {
+		}
+	}
+}
+
+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;
+		}
+	}
+}

+ 26 - 0
core/vector.h

@@ -157,6 +157,32 @@ public:
 		return slice;
 		return slice;
 	}
 	}
 
 
+	bool operator==(const Vector<T> &p_arr) const {
+		int s = size();
+		if (s != p_arr.size()) {
+			return false;
+		}
+		for (int i = 0; i < s; i++) {
+			if (operator[](i) != p_arr[i]) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	bool operator!=(const Vector<T> &p_arr) const {
+		int s = size();
+		if (s != p_arr.size()) {
+			return true;
+		}
+		for (int i = 0; i < s; i++) {
+			if (operator[](i) != p_arr[i]) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	_FORCE_INLINE_ Vector() {}
 	_FORCE_INLINE_ Vector() {}
 	_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
 	_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
 
 

+ 8 - 8
editor/dependency_editor.cpp

@@ -471,28 +471,28 @@ void DependencyRemoveDialog::ok_pressed() {
 
 
 		// If the file we are deleting for e.g. the main scene, default environment,
 		// If the file we are deleting for e.g. the main scene, default environment,
 		// or audio bus layout, we must clear its definition in Project Settings.
 		// or audio bus layout, we must clear its definition in Project Settings.
-		if (files_to_delete[i] == ProjectSettings::get_singleton()->get("application/config/icon")) {
+		if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("application/config/icon"))) {
 			ProjectSettings::get_singleton()->set("application/config/icon", "");
 			ProjectSettings::get_singleton()->set("application/config/icon", "");
 		}
 		}
-		if (files_to_delete[i] == ProjectSettings::get_singleton()->get("application/run/main_scene")) {
+		if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("application/run/main_scene"))) {
 			ProjectSettings::get_singleton()->set("application/run/main_scene", "");
 			ProjectSettings::get_singleton()->set("application/run/main_scene", "");
 		}
 		}
-		if (files_to_delete[i] == ProjectSettings::get_singleton()->get("application/boot_splash/image")) {
+		if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("application/boot_splash/image"))) {
 			ProjectSettings::get_singleton()->set("application/boot_splash/image", "");
 			ProjectSettings::get_singleton()->set("application/boot_splash/image", "");
 		}
 		}
-		if (files_to_delete[i] == ProjectSettings::get_singleton()->get("rendering/environment/default_environment")) {
+		if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("rendering/environment/default_environment"))) {
 			ProjectSettings::get_singleton()->set("rendering/environment/default_environment", "");
 			ProjectSettings::get_singleton()->set("rendering/environment/default_environment", "");
 		}
 		}
-		if (files_to_delete[i] == ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image")) {
+		if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image"))) {
 			ProjectSettings::get_singleton()->set("display/mouse_cursor/custom_image", "");
 			ProjectSettings::get_singleton()->set("display/mouse_cursor/custom_image", "");
 		}
 		}
-		if (files_to_delete[i] == ProjectSettings::get_singleton()->get("gui/theme/custom")) {
+		if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("gui/theme/custom"))) {
 			ProjectSettings::get_singleton()->set("gui/theme/custom", "");
 			ProjectSettings::get_singleton()->set("gui/theme/custom", "");
 		}
 		}
-		if (files_to_delete[i] == ProjectSettings::get_singleton()->get("gui/theme/custom_font")) {
+		if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("gui/theme/custom_font"))) {
 			ProjectSettings::get_singleton()->set("gui/theme/custom_font", "");
 			ProjectSettings::get_singleton()->set("gui/theme/custom_font", "");
 		}
 		}
-		if (files_to_delete[i] == ProjectSettings::get_singleton()->get("audio/default_bus_layout")) {
+		if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("audio/default_bus_layout"))) {
 			ProjectSettings::get_singleton()->set("audio/default_bus_layout", "");
 			ProjectSettings::get_singleton()->set("audio/default_bus_layout", "");
 		}
 		}
 
 

+ 1 - 1
editor/plugins/node_3d_editor_plugin.cpp

@@ -4687,7 +4687,7 @@ void Node3DEditor::set_state(const Dictionary &p_state) {
 			}
 			}
 			int state = EditorNode3DGizmoPlugin::VISIBLE;
 			int state = EditorNode3DGizmoPlugin::VISIBLE;
 			for (int i = 0; i < keys.size(); i++) {
 			for (int i = 0; i < keys.size(); i++) {
-				if (gizmo_plugins_by_name.write[j]->get_name() == keys[i]) {
+				if (gizmo_plugins_by_name.write[j]->get_name() == String(keys[i])) {
 					state = gizmos_status[keys[i]];
 					state = gizmos_status[keys[i]];
 					break;
 					break;
 				}
 				}

+ 1 - 1
editor/plugins/script_editor_plugin.cpp

@@ -2397,7 +2397,7 @@ void ScriptEditor::_editor_settings_changed() {
 
 
 	if (current_theme == "") {
 	if (current_theme == "") {
 		current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
 		current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
-	} else if (current_theme != EditorSettings::get_singleton()->get("text_editor/theme/color_theme")) {
+	} else if (current_theme != String(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))) {
 		current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
 		current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
 		EditorSettings::get_singleton()->load_text_editor_theme();
 		EditorSettings::get_singleton()->load_text_editor_theme();
 	}
 	}

+ 2 - 1
editor/plugins/texture_region_editor_plugin.cpp

@@ -875,7 +875,8 @@ void TextureRegionEditor::_changed_callback(Object *p_changed, const char *p_pro
 	if (!is_visible()) {
 	if (!is_visible()) {
 		return;
 		return;
 	}
 	}
-	if (p_prop == StringName("atlas") || p_prop == StringName("texture") || p_prop == StringName("region")) {
+	String prop = p_prop;
+	if (prop == "atlas" || prop == "texture" || prop == "region") {
 		_edit_region();
 		_edit_region();
 	}
 	}
 }
 }

+ 1 - 1
main/main.cpp

@@ -2232,7 +2232,7 @@ bool Main::start() {
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 			if (editor) {
 			if (editor) {
-				if (game_path != GLOBAL_GET("application/run/main_scene") || !editor_node->has_scenes_in_session()) {
+				if (game_path != String(GLOBAL_GET("application/run/main_scene")) || !editor_node->has_scenes_in_session()) {
 					Error serr = editor_node->load_scene(local_game_path);
 					Error serr = editor_node->load_scene(local_game_path);
 					if (serr != OK) {
 					if (serr != OK) {
 						ERR_PRINT("Failed to load scene");
 						ERR_PRINT("Failed to load scene");

+ 0 - 3
modules/visual_script/visual_script_nodes.cpp

@@ -828,7 +828,6 @@ PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const {
 		{ Variant::NIL, Variant::NIL }, //OP_NEGATE,
 		{ Variant::NIL, Variant::NIL }, //OP_NEGATE,
 		{ Variant::NIL, Variant::NIL }, //OP_POSITIVE,
 		{ Variant::NIL, Variant::NIL }, //OP_POSITIVE,
 		{ Variant::INT, Variant::INT }, //OP_MODULE,
 		{ Variant::INT, Variant::INT }, //OP_MODULE,
-		{ Variant::STRING, Variant::STRING }, //OP_STRING_CONCAT,
 		//bitwise
 		//bitwise
 		{ Variant::INT, Variant::INT }, //OP_SHIFT_LEFT,
 		{ Variant::INT, Variant::INT }, //OP_SHIFT_LEFT,
 		{ Variant::INT, Variant::INT }, //OP_SHIFT_RIGHT,
 		{ Variant::INT, Variant::INT }, //OP_SHIFT_RIGHT,
@@ -873,7 +872,6 @@ PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const {
 		Variant::NIL, //OP_NEGATE,
 		Variant::NIL, //OP_NEGATE,
 		Variant::NIL, //OP_POSITIVE,
 		Variant::NIL, //OP_POSITIVE,
 		Variant::INT, //OP_MODULE,
 		Variant::INT, //OP_MODULE,
-		Variant::STRING, //OP_STRING_CONCAT,
 		//bitwise
 		//bitwise
 		Variant::INT, //OP_SHIFT_LEFT,
 		Variant::INT, //OP_SHIFT_LEFT,
 		Variant::INT, //OP_SHIFT_RIGHT,
 		Variant::INT, //OP_SHIFT_RIGHT,
@@ -3881,7 +3879,6 @@ void register_visual_script_nodes() {
 	VisualScriptLanguage::singleton->add_register_func("operators/math/negate", create_op_node<Variant::OP_NEGATE>);
 	VisualScriptLanguage::singleton->add_register_func("operators/math/negate", create_op_node<Variant::OP_NEGATE>);
 	VisualScriptLanguage::singleton->add_register_func("operators/math/positive", create_op_node<Variant::OP_POSITIVE>);
 	VisualScriptLanguage::singleton->add_register_func("operators/math/positive", create_op_node<Variant::OP_POSITIVE>);
 	VisualScriptLanguage::singleton->add_register_func("operators/math/remainder", create_op_node<Variant::OP_MODULE>);
 	VisualScriptLanguage::singleton->add_register_func("operators/math/remainder", create_op_node<Variant::OP_MODULE>);
-	VisualScriptLanguage::singleton->add_register_func("operators/math/string_concat", create_op_node<Variant::OP_STRING_CONCAT>);
 	//bitwise
 	//bitwise
 	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_left", create_op_node<Variant::OP_SHIFT_LEFT>);
 	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_left", create_op_node<Variant::OP_SHIFT_LEFT>);
 	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_right", create_op_node<Variant::OP_SHIFT_RIGHT>);
 	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_right", create_op_node<Variant::OP_SHIFT_RIGHT>);

+ 3 - 3
tests/test_expression.h

@@ -381,7 +381,7 @@ TEST_CASE("[Expression] Unusual expressions") {
 
 
 	ERR_PRINT_OFF;
 	ERR_PRINT_OFF;
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
-			expression.parse("$1.00 + 5") == OK,
+			expression.parse("$1.00 + ???5") == OK,
 			"The expression should parse successfully.");
 			"The expression should parse successfully.");
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
 			int(expression.execute()) == 0,
 			int(expression.execute()) == 0,
@@ -410,8 +410,8 @@ TEST_CASE("[Expression] Unusual expressions") {
 			"The expression should parse successfully.");
 			"The expression should parse successfully.");
 	ERR_PRINT_OFF;
 	ERR_PRINT_OFF;
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
-			Math::is_zero_approx(float(expression.execute())),
-			"`-25.4 / 0` should return 0.");
+			Math::is_inf(float(expression.execute())),
+			"`-25.4 / 0` should return inf.");
 	ERR_PRINT_ON;
 	ERR_PRINT_ON;
 
 
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(

Some files were not shown because too many files changed in this diff