Browse Source

Merge pull request #15880 from neikeq/better-collections

Mono: Add Dictionary and Array classes
Ignacio Etcheverry 7 years ago
parent
commit
779c9d638e

+ 5 - 0
core/dictionary.cpp

@@ -140,6 +140,11 @@ void Dictionary::erase(const Variant &p_key) {
 	_p->variant_map.erase(p_key);
 	_p->variant_map.erase(p_key);
 }
 }
 
 
+bool Dictionary::erase_checked(const Variant &p_key) {
+
+	return _p->variant_map.erase(p_key);
+}
+
 bool Dictionary::operator==(const Dictionary &p_dictionary) const {
 bool Dictionary::operator==(const Dictionary &p_dictionary) const {
 
 
 	return _p == p_dictionary._p;
 	return _p == p_dictionary._p;

+ 1 - 0
core/dictionary.h

@@ -66,6 +66,7 @@ public:
 	bool has_all(const Array &p_keys) const;
 	bool has_all(const Array &p_keys) const;
 
 
 	void erase(const Variant &p_key);
 	void erase(const Variant &p_key);
+	bool erase_checked(const Variant &p_key);
 
 
 	bool operator==(const Dictionary &p_dictionary) const;
 	bool operator==(const Dictionary &p_dictionary) const;
 
 

+ 1 - 1
modules/mono/csharp_script.cpp

@@ -1609,7 +1609,7 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati
 
 
 bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> &params) {
 bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> &params) {
 	if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
 	if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
-		MonoType *raw_type = GDMonoClass::get_raw_type(p_delegate);
+		MonoType *raw_type = p_delegate->get_mono_type();
 
 
 		if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) {
 		if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) {
 			// Arguments are accessibles as arguments of .Invoke method
 			// Arguments are accessibles as arguments of .Invoke method

+ 24 - 12
modules/mono/editor/bindings_generator.cpp

@@ -100,8 +100,6 @@
 #define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL "::mono_string_from_godot"
 #define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL "::mono_string_from_godot"
 #define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
 #define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
 #define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
 #define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
-#define C_METHOD_MANAGED_TO_DICT C_NS_MONOMARSHAL "::mono_object_to_Dictionary"
-#define C_METHOD_MANAGED_FROM_DICT C_NS_MONOMARSHAL "::Dictionary_to_mono_object"
 
 
 #define BINDINGS_GENERATOR_VERSION UINT32_C(2)
 #define BINDINGS_GENERATOR_VERSION UINT32_C(2)
 
 
@@ -1338,7 +1336,6 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
 		} else if (return_type->cs_out.empty()) {
 		} else if (return_type->cs_out.empty()) {
 			p_output.push_back("return " + im_call + ";\n");
 			p_output.push_back("return " + im_call + ";\n");
 		} else {
 		} else {
-			p_output.push_back(INDENT3);
 			p_output.push_back(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out));
 			p_output.push_back(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out));
 			p_output.push_back("\n");
 			p_output.push_back("\n");
 		}
 		}
@@ -2344,7 +2341,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
 
 
 #define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t)
 #define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t)
 
 
-	INSERT_ARRAY(Array, object);
 	INSERT_ARRAY(PoolIntArray, int);
 	INSERT_ARRAY(PoolIntArray, int);
 	INSERT_ARRAY_FULL(PoolByteArray, PoolByteArray, byte);
 	INSERT_ARRAY_FULL(PoolByteArray, PoolByteArray, byte);
 
 
@@ -2362,20 +2358,36 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
 
 
 #undef INSERT_ARRAY
 #undef INSERT_ARRAY
 
 
+	// Array
+	itype = TypeInterface();
+	itype.name = "Array";
+	itype.cname = itype.name;
+	itype.proxy_name = "Array";
+	itype.c_out = "\treturn memnew(Array(%1));\n";
+	itype.c_type = itype.name;
+	itype.c_type_in = itype.c_type + "*";
+	itype.c_type_out = itype.c_type + "*";
+	itype.cs_type = itype.proxy_name;
+	itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
+	itype.cs_out = "return new Array(%0);";
+	itype.im_type_in = "IntPtr";
+	itype.im_type_out = "IntPtr";
+	builtin_types.insert(itype.cname, itype);
+
 	// Dictionary
 	// Dictionary
 	itype = TypeInterface();
 	itype = TypeInterface();
 	itype.name = "Dictionary";
 	itype.name = "Dictionary";
 	itype.cname = itype.name;
 	itype.cname = itype.name;
-	itype.proxy_name = "Dictionary<object, object>";
-	itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_DICT "(%1);\n";
-	itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_DICT "(%1);\n";
-	itype.c_arg_in = "&%s_in";
+	itype.proxy_name = "Dictionary";
+	itype.c_out = "\treturn memnew(Dictionary(%1));\n";
 	itype.c_type = itype.name;
 	itype.c_type = itype.name;
-	itype.c_type_in = "MonoObject*";
-	itype.c_type_out = "MonoObject*";
+	itype.c_type_in = itype.c_type + "*";
+	itype.c_type_out = itype.c_type + "*";
 	itype.cs_type = itype.proxy_name;
 	itype.cs_type = itype.proxy_name;
-	itype.im_type_in = itype.proxy_name;
-	itype.im_type_out = itype.proxy_name;
+	itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
+	itype.cs_out = "return new Dictionary(%0);";
+	itype.im_type_in = "IntPtr";
+	itype.im_type_out = "IntPtr";
 	builtin_types.insert(itype.cname, itype);
 	builtin_types.insert(itype.cname, itype);
 
 
 	// void (fictitious type to represent the return type of methods that do not return anything)
 	// void (fictitious type to represent the return type of methods that do not return anything)

+ 240 - 0
modules/mono/glue/collections_glue.cpp

@@ -0,0 +1,240 @@
+/*************************************************************************/
+/*  collections_glue.cpp                                                 */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2018 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 "collections_glue.h"
+
+#include <mono/metadata/exception.h>
+
+#include "../mono_gd/gd_mono_class.h"
+
+Array *godot_icall_Array_Ctor() {
+	return memnew(Array);
+}
+
+void godot_icall_Array_Dtor(Array *ptr) {
+	memdelete(ptr);
+}
+
+MonoObject *godot_icall_Array_At(Array *ptr, int index) {
+	if (index < 0 || index > ptr->size()) {
+		GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
+		return NULL;
+	}
+	return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
+}
+
+void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
+	if (index < 0 || index > ptr->size()) {
+		GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
+		return;
+	}
+	ptr->operator[](index) = GDMonoMarshal::mono_object_to_variant(value);
+}
+
+int godot_icall_Array_Count(Array *ptr) {
+	return ptr->size();
+}
+
+void godot_icall_Array_Add(Array *ptr, MonoObject *item) {
+	ptr->append(GDMonoMarshal::mono_object_to_variant(item));
+}
+
+void godot_icall_Array_Clear(Array *ptr) {
+	ptr->clear();
+}
+
+bool godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
+	return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
+}
+
+void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) {
+	int count = ptr->size();
+
+	if (mono_array_length(array) < (array_index + count)) {
+		MonoException *exc = mono_get_exception_argument("", "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+		GDMonoUtils::set_pending_exception(exc);
+		return;
+	}
+
+	for (int i = 0; i < count; i++) {
+		MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(ptr->operator[](i));
+		mono_array_setref(array, array_index, boxed);
+		array_index++;
+	}
+}
+
+int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
+	return ptr->find(GDMonoMarshal::mono_object_to_variant(item));
+}
+
+void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) {
+	if (index < 0 || index > ptr->size()) {
+		GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
+		return;
+	}
+	ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item));
+}
+
+bool godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
+	int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item));
+	if (idx >= 0) {
+		ptr->remove(idx);
+		return true;
+	}
+	return false;
+}
+
+void godot_icall_Array_RemoveAt(Array *ptr, int index) {
+	if (index < 0 || index > ptr->size()) {
+		GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
+		return;
+	}
+	ptr->remove(index);
+}
+
+Dictionary *godot_icall_Dictionary_Ctor() {
+	return memnew(Dictionary);
+}
+
+void godot_icall_Dictionary_Dtor(Dictionary *ptr) {
+	memdelete(ptr);
+}
+
+MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
+	Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
+	if (ret == NULL) {
+		MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
+#ifdef DEBUG_ENABLED
+		CRASH_COND(!exc);
+#endif
+		GDMonoUtils::runtime_object_init(exc);
+		GDMonoUtils::set_pending_exception((MonoException *)exc);
+		return NULL;
+	}
+	return GDMonoMarshal::variant_to_mono_object(ret);
+}
+
+void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) {
+	ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value);
+}
+
+Array *godot_icall_Dictionary_Keys(Dictionary *ptr) {
+	return memnew(Array(ptr->keys()));
+}
+
+Array *godot_icall_Dictionary_Values(Dictionary *ptr) {
+	return memnew(Array(ptr->values()));
+}
+
+int godot_icall_Dictionary_Count(Dictionary *ptr) {
+	return ptr->size();
+}
+
+void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
+	Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
+	Variant *ret = ptr->getptr(varKey);
+	if (ret != NULL) {
+		GDMonoUtils::set_pending_exception(mono_get_exception_argument("key", "An element with the same key already exists"));
+		return;
+	}
+	ptr->operator[](varKey) = GDMonoMarshal::mono_object_to_variant(value);
+}
+
+void godot_icall_Dictionary_Clear(Dictionary *ptr) {
+	ptr->clear();
+}
+
+bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
+	// no dupes
+	Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
+	return ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value);
+}
+
+bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
+	return ptr->has(GDMonoMarshal::mono_object_to_variant(key));
+}
+
+bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
+	return ptr->erase_checked(GDMonoMarshal::mono_object_to_variant(key));
+}
+
+bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
+	Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
+
+	// no dupes
+	Variant *ret = ptr->getptr(varKey);
+	if (ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value)) {
+		ptr->erase_checked(varKey);
+		return true;
+	}
+
+	return false;
+}
+
+bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
+	Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
+	if (ret == NULL) {
+		*value = NULL;
+		return false;
+	}
+	*value = GDMonoMarshal::variant_to_mono_object(ret);
+	return true;
+}
+
+void godot_register_collections_icalls() {
+	mono_add_internal_call("Godot.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_At", (void *)godot_icall_Array_At);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_IndexOf", (void *)godot_icall_Array_IndexOf);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove);
+	mono_add_internal_call("Godot.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt);
+
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Count", (void *)godot_icall_Dictionary_Count);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Add", (void *)godot_icall_Dictionary_Add);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Clear", (void *)godot_icall_Dictionary_Clear);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Contains", (void *)godot_icall_Dictionary_Contains);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_ContainsKey", (void *)godot_icall_Dictionary_ContainsKey);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove);
+	mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue);
+}

+ 100 - 0
modules/mono/glue/collections_glue.h

@@ -0,0 +1,100 @@
+/*************************************************************************/
+/*  collections_glue.h                                                   */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef COLLECTIONS_GLUE_H
+#define COLLECTIONS_GLUE_H
+
+#include "core/array.h"
+
+#include "../mono_gd/gd_mono_marshal.h"
+
+// Array
+
+Array *godot_icall_Array_Ctor();
+
+void godot_icall_Array_Dtor(Array *ptr);
+
+MonoObject *godot_icall_Array_At(Array *ptr, int index);
+
+void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value);
+
+int godot_icall_Array_Count(Array *ptr);
+
+void godot_icall_Array_Add(Array *ptr, MonoObject *item);
+
+void godot_icall_Array_Clear(Array *ptr);
+
+bool godot_icall_Array_Contains(Array *ptr, MonoObject *item);
+
+void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index);
+
+int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item);
+
+void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item);
+
+bool godot_icall_Array_Remove(Array *ptr, MonoObject *item);
+
+void godot_icall_Array_RemoveAt(Array *ptr, int index);
+
+// Dictionary
+
+Dictionary *godot_icall_Dictionary_Ctor();
+
+void godot_icall_Dictionary_Dtor(Dictionary *ptr);
+
+MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key);
+
+void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value);
+
+Array *godot_icall_Dictionary_Keys(Dictionary *ptr);
+
+Array *godot_icall_Dictionary_Values(Dictionary *ptr);
+
+int godot_icall_Dictionary_Count(Dictionary *ptr);
+
+void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value);
+
+void godot_icall_Dictionary_Clear(Dictionary *ptr);
+
+bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value);
+
+bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key);
+
+bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key);
+
+bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value);
+
+bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value);
+
+// Register internal calls
+
+void godot_register_collections_icalls();
+
+#endif // COLLECTIONS_GLUE_H

+ 335 - 0
modules/mono/glue/cs_files/Array.cs

@@ -0,0 +1,335 @@
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+    class ArraySafeHandle : SafeHandle
+    {
+        public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
+        {
+            this.handle = handle;
+        }
+
+        public override bool IsInvalid
+        {
+            get
+            {
+                return handle == IntPtr.Zero;
+            }
+        }
+
+        protected override bool ReleaseHandle()
+        {
+            Array.godot_icall_Array_Dtor(handle);
+            return true;
+        }
+    }
+
+    public class Array : IList<object>, ICollection<object>, IEnumerable<object>, IDisposable
+    {
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static IntPtr godot_icall_Array_Ctor();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Array_Dtor(IntPtr ptr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static object godot_icall_Array_At(IntPtr ptr, int index);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static int godot_icall_Array_Count(IntPtr ptr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Array_Add(IntPtr ptr, object item);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Array_Clear(IntPtr ptr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, object[] array, int arrayIndex);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
+
+        ArraySafeHandle safeHandle;
+        bool disposed = false;
+
+        public Array()
+        {
+            safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
+        }
+
+        internal Array(ArraySafeHandle handle)
+        {
+            safeHandle = handle;
+        }
+
+        internal Array(IntPtr handle)
+        {
+            safeHandle = new ArraySafeHandle(handle);
+        }
+
+        internal IntPtr GetPtr()
+        {
+            return safeHandle.DangerousGetHandle();
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposed)
+                return;
+
+            if (safeHandle != null)
+            {
+                safeHandle.Dispose();
+                safeHandle = null;
+            }
+
+            disposed = true;
+        }
+
+        public object this[int index]
+        {
+            get
+            {
+                return godot_icall_Array_At(GetPtr(), index);
+            }
+            set
+            {
+                godot_icall_Array_SetAt(GetPtr(), index, value);
+            }
+        }
+
+        public int Count
+        {
+            get
+            {
+                return godot_icall_Array_Count(GetPtr());
+            }
+        }
+
+        public bool IsReadOnly
+        {
+            get
+            {
+                return false;
+            }
+        }
+
+        public void Add(object item)
+        {
+            godot_icall_Array_Add(GetPtr(), item);
+        }
+
+        public void Clear()
+        {
+            godot_icall_Array_Clear(GetPtr());
+        }
+
+        public bool Contains(object item)
+        {
+            return godot_icall_Array_Contains(GetPtr(), item);
+        }
+
+        public void CopyTo(object[] array, int arrayIndex)
+        {
+            if (array == null)
+                throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+            if (arrayIndex < 0)
+                throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
+
+            // Internal call may throw ArgumentException
+            godot_icall_Array_CopyTo(GetPtr(), array, arrayIndex);
+        }
+
+        public IEnumerator<object> GetEnumerator()
+        {
+            int count = Count;
+
+            for (int i = 0; i < count; i++)
+            {
+                yield return godot_icall_Array_At(GetPtr(), i);
+            }
+        }
+
+        public int IndexOf(object item)
+        {
+            return godot_icall_Array_IndexOf(GetPtr(), item);
+        }
+
+        public void Insert(int index, object item)
+        {
+            godot_icall_Array_Insert(GetPtr(), index, item);
+        }
+
+        public bool Remove(object item)
+        {
+            return godot_icall_Array_Remove(GetPtr(), item);
+        }
+
+        public void RemoveAt(int index)
+        {
+            godot_icall_Array_RemoveAt(GetPtr(), index);
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+
+    public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
+    {
+        Array objectArray;
+
+        public Array()
+        {
+            objectArray = new Array();
+        }
+
+        public Array(Array array)
+        {
+            objectArray = array;
+        }
+
+        internal Array(IntPtr handle)
+        {
+            objectArray = new Array(handle);
+        }
+
+        internal Array(ArraySafeHandle handle)
+        {
+            objectArray = new Array(handle);
+        }
+
+        public static explicit operator Array(Array<T> from)
+        {
+            return from.objectArray;
+        }
+
+        public T this[int index]
+        {
+            get
+            {
+                return (T)objectArray[index];
+            }
+            set
+            {
+                objectArray[index] = value;
+            }
+        }
+
+        public int Count
+        {
+            get
+            {
+                return objectArray.Count;
+            }
+        }
+
+        public bool IsReadOnly
+        {
+            get
+            {
+                return objectArray.IsReadOnly;
+            }
+        }
+
+        public void Add(T item)
+        {
+            objectArray.Add(item);
+        }
+
+        public void Clear()
+        {
+            objectArray.Clear();
+        }
+
+        public bool Contains(T item)
+        {
+            return objectArray.Contains(item);
+        }
+
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            if (array == null)
+                throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+            if (arrayIndex < 0)
+                throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
+
+            // TODO This may be quite slow because every element access is an internal call.
+            // It could be moved entirely to an internal call if we find out how to do the cast there.
+
+            int count = objectArray.Count;
+
+            if (array.Length < (arrayIndex + count))
+                throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+
+            for (int i = 0; i < count; i++)
+            {
+                array[arrayIndex] = (T)objectArray[i];
+                arrayIndex++;
+            }
+        }
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            int count = objectArray.Count;
+
+            for (int i = 0; i < count; i++)
+            {
+                yield return (T)objectArray[i];
+            }
+        }
+
+        public int IndexOf(T item)
+        {
+            return objectArray.IndexOf(item);
+        }
+
+        public void Insert(int index, T item)
+        {
+            objectArray.Insert(index, item);
+        }
+
+        public bool Remove(T item)
+        {
+            return objectArray.Remove(item);
+        }
+
+        public void RemoveAt(int index)
+        {
+            objectArray.RemoveAt(index);
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+}

+ 401 - 0
modules/mono/glue/cs_files/Dictionary.cs

@@ -0,0 +1,401 @@
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+    class DictionarySafeHandle : SafeHandle
+    {
+        public DictionarySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
+        {
+            this.handle = handle;
+        }
+
+        public override bool IsInvalid
+        {
+            get
+            {
+                return handle == IntPtr.Zero;
+            }
+        }
+
+        protected override bool ReleaseHandle()
+        {
+            Dictionary.godot_icall_Dictionary_Dtor(handle);
+            return true;
+        }
+    }
+
+    public class Dictionary :
+        IDictionary<object, object>,
+        ICollection<KeyValuePair<object, object>>,
+        IEnumerable<KeyValuePair<object, object>>,
+        IDisposable
+    {
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static IntPtr godot_icall_Dictionary_Ctor();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Dictionary_Dtor(IntPtr ptr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static IntPtr godot_icall_Dictionary_Keys(IntPtr ptr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static int godot_icall_Dictionary_Count(IntPtr ptr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static void godot_icall_Dictionary_Clear(IntPtr ptr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value);
+
+        DictionarySafeHandle safeHandle;
+        bool disposed = false;
+
+        public Dictionary()
+        {
+            safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
+        }
+
+        internal Dictionary(DictionarySafeHandle handle)
+        {
+            safeHandle = handle;
+        }
+
+        internal Dictionary(IntPtr handle)
+        {
+            safeHandle = new DictionarySafeHandle(handle);
+        }
+
+        internal IntPtr GetPtr()
+        {
+            return safeHandle.DangerousGetHandle();
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposed)
+                return;
+
+            if (safeHandle != null)
+            {
+                safeHandle.Dispose();
+                safeHandle = null;
+            }
+
+            disposed = true;
+        }
+
+        public object this[object key]
+        {
+            get
+            {
+                return godot_icall_Dictionary_GetValue(GetPtr(), key);
+            }
+            set
+            {
+                godot_icall_Dictionary_SetValue(GetPtr(), key, value);
+            }
+        }
+
+        public ICollection<object> Keys
+        {
+            get
+            {
+                IntPtr handle = godot_icall_Dictionary_Keys(GetPtr());
+                return new Array(new ArraySafeHandle(handle));
+            }
+        }
+
+        public ICollection<object> Values
+        {
+            get
+            {
+                IntPtr handle = godot_icall_Dictionary_Values(GetPtr());
+                return new Array(new ArraySafeHandle(handle));
+            }
+        }
+
+        public int Count
+        {
+            get
+            {
+                return godot_icall_Dictionary_Count(GetPtr());
+            }
+        }
+
+        public bool IsReadOnly
+        {
+            get
+            {
+                return false;
+            }
+        }
+
+        public void Add(object key, object value)
+        {
+            godot_icall_Dictionary_Add(GetPtr(), key, value);
+        }
+
+        public void Add(KeyValuePair<object, object> item)
+        {
+            Add(item.Key, item.Value);
+        }
+
+        public void Clear()
+        {
+            godot_icall_Dictionary_Clear(GetPtr());
+        }
+
+        public bool Contains(KeyValuePair<object, object> item)
+        {
+            return godot_icall_Dictionary_Contains(GetPtr(), item.Key, item.Value);
+        }
+
+        public bool ContainsKey(object key)
+        {
+            return godot_icall_Dictionary_ContainsKey(GetPtr(), key);
+        }
+
+        public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex)
+        {
+            // TODO 3 internal calls, can reduce to 1
+            Array keys = (Array)Keys;
+            Array values = (Array)Values;
+            int count = Count;
+
+            for (int i = 0; i < count; i++)
+            {
+                // TODO 2 internal calls, can reduce to 1
+                array[arrayIndex] = new KeyValuePair<object, object>(keys[i], values[i]);
+                arrayIndex++;
+            }
+        }
+
+        public IEnumerator<KeyValuePair<object, object>> GetEnumerator()
+        {
+            // TODO 3 internal calls, can reduce to 1
+            Array keys = (Array)Keys;
+            Array values = (Array)Values;
+            int count = Count;
+
+            for (int i = 0; i < count; i++)
+            {
+                // TODO 2 internal calls, can reduce to 1
+                yield return new KeyValuePair<object, object>(keys[i], values[i]);
+            }
+        }
+
+        public bool Remove(object key)
+        {
+            return godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+        }
+
+        public bool Remove(KeyValuePair<object, object> item)
+        {
+            return godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
+        }
+
+        public bool TryGetValue(object key, out object value)
+        {
+            object retValue;
+            bool found = godot_icall_Dictionary_TryGetValue(GetPtr(), key, out retValue);
+            value = found ? retValue : default(object);
+            return found;
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+
+
+    public class Dictionary<TKey, TValue> :
+        IDictionary<TKey, TValue>,
+        ICollection<KeyValuePair<TKey, TValue>>,
+        IEnumerable<KeyValuePair<TKey, TValue>>
+    {
+        Dictionary objectDict;
+
+        public Dictionary()
+        {
+            objectDict = new Dictionary();
+        }
+
+        public Dictionary(Dictionary dictionary)
+        {
+            objectDict = dictionary;
+        }
+
+        internal Dictionary(IntPtr handle)
+        {
+            objectDict = new Dictionary(handle);
+        }
+
+        internal Dictionary(DictionarySafeHandle handle)
+        {
+            objectDict = new Dictionary(handle);
+        }
+
+        public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
+        {
+            return from.objectDict;
+        }
+
+        public TValue this[TKey key]
+        {
+            get
+            {
+                return (TValue)objectDict[key];
+            }
+            set
+            {
+                objectDict[key] = value;
+            }
+        }
+
+        public ICollection<TKey> Keys
+        {
+            get
+            {
+                IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(objectDict.GetPtr());
+                return new Array<TKey>(new ArraySafeHandle(handle));
+            }
+        }
+
+        public ICollection<TValue> Values
+        {
+            get
+            {
+                IntPtr handle = Dictionary.godot_icall_Dictionary_Values(objectDict.GetPtr());
+                return new Array<TValue>(new ArraySafeHandle(handle));
+            }
+        }
+
+        public int Count
+        {
+            get
+            {
+                return objectDict.Count;
+            }
+        }
+
+        public bool IsReadOnly
+        {
+            get
+            {
+                return objectDict.IsReadOnly;
+            }
+        }
+
+        public void Add(TKey key, TValue value)
+        {
+            objectDict.Add(key, value);
+        }
+
+        public void Add(KeyValuePair<TKey, TValue> item)
+        {
+            objectDict.Add(item.Key, item.Value);
+        }
+
+        public void Clear()
+        {
+            objectDict.Clear();
+        }
+
+        public bool Contains(KeyValuePair<TKey, TValue> item)
+        {
+            return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
+        }
+
+        public bool ContainsKey(TKey key)
+        {
+            return objectDict.ContainsKey(key);
+        }
+
+        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+        {
+            // TODO 3 internal calls, can reduce to 1
+            Array<TKey> keys = (Array<TKey>)Keys;
+            Array<TValue> values = (Array<TValue>)Values;
+            int count = Count;
+
+            for (int i = 0; i < count; i++)
+            {
+                // TODO 2 internal calls, can reduce to 1
+                array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]);
+                arrayIndex++;
+            }
+        }
+
+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+        {
+            // TODO 3 internal calls, can reduce to 1
+            Array<TKey> keys = (Array<TKey>)Keys;
+            Array<TValue> values = (Array<TValue>)Values;
+            int count = Count;
+
+            for (int i = 0; i < count; i++)
+            {
+                // TODO 2 internal calls, can reduce to 1
+                yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]);
+            }
+        }
+
+        public bool Remove(TKey key)
+        {
+            return objectDict.Remove(key);
+        }
+
+        public bool Remove(KeyValuePair<TKey, TValue> item)
+        {
+            return objectDict.Remove(new KeyValuePair<object, object>(item.Key, item.Value));
+        }
+
+        public bool TryGetValue(TKey key, out TValue value)
+        {
+            object retValue;
+            bool found = objectDict.TryGetValue(key, out retValue);
+            value = found ? (TValue)retValue : default(TValue);
+            return found;
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+}

+ 5 - 24
modules/mono/glue/cs_files/MarshalUtils.cs

@@ -1,36 +1,17 @@
 using System;
 using System;
-using System.Collections.Generic;
 
 
 namespace Godot
 namespace Godot
 {
 {
-    internal static class MarshalUtils
+    static class MarshalUtils
     {
     {
-        private static Dictionary<object, object> ArraysToDictionary(object[] keys, object[] values)
+        static bool IsArrayGenericType(Type type)
         {
         {
-            var ret = new Dictionary<object, object>();
-
-            for (int i = 0; i < keys.Length; i++)
-            {
-                ret.Add(keys[i], values[i]);
-            }
-
-            return ret;
-        }
-
-        private static void DictionaryToArrays(Dictionary<object, object> from, out object[] keysTo, out object[] valuesTo)
-        {
-            var keys = from.Keys;
-            keysTo = new object[keys.Count];
-            keys.CopyTo(keysTo, 0);
-
-            var values = from.Values;
-            valuesTo = new object[values.Count];
-            values.CopyTo(valuesTo, 0);
+            return type.GetGenericTypeDefinition() == typeof(Array<>);
         }
         }
 
 
-        private static Type GetDictionaryType()
+        static bool IsDictionaryGenericType(Type type)
         {
         {
-            return typeof(Dictionary<object, object>);
+            return type.GetGenericTypeDefinition() == typeof(Dictionary<, >);
         }
         }
     }
     }
 }
 }

+ 2 - 0
modules/mono/glue/glue_header.h

@@ -29,6 +29,7 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "builtin_types_glue.h"
 #include "builtin_types_glue.h"
+#include "collections_glue.h"
 
 
 #include "../csharp_script.h"
 #include "../csharp_script.h"
 #include "../mono_gd/gd_mono_class.h"
 #include "../mono_gd/gd_mono_class.h"
@@ -308,4 +309,5 @@ MonoObject *godot_icall_Godot_weakref(Object *p_obj) {
 
 
 void godot_register_header_icalls() {
 void godot_register_header_icalls() {
 	godot_register_builtin_type_icalls();
 	godot_register_builtin_type_icalls();
+	godot_register_collections_icalls();
 }
 }

+ 23 - 9
modules/mono/mono_gd/gd_mono_class.cpp

@@ -33,23 +33,37 @@
 #include <mono/metadata/attrdefs.h>
 #include <mono/metadata/attrdefs.h>
 
 
 #include "gd_mono_assembly.h"
 #include "gd_mono_assembly.h"
+#include "gd_mono_marshal.h"
 
 
-MonoType *GDMonoClass::get_raw_type(GDMonoClass *p_class) {
+String GDMonoClass::get_full_name(MonoClass *p_mono_class) {
+	// mono_type_get_full_name is not exposed to embedders, but this seems to do the job
+	MonoReflectionType *type_obj = mono_type_get_object(mono_domain_get(), get_mono_type(p_mono_class));
 
 
-	return mono_class_get_type(p_class->get_mono_ptr());
-}
+	MonoException *exc = NULL;
+	GD_MONO_BEGIN_RUNTIME_INVOKE;
+	MonoString *str = mono_object_to_string((MonoObject *)type_obj, (MonoObject **)&exc);
+	GD_MONO_END_RUNTIME_INVOKE;
+	UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 
-bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
+	return GDMonoMarshal::mono_string_to_godot(str);
+}
 
 
-	return mono_class_is_assignable_from(mono_class, p_from->mono_class);
+MonoType *GDMonoClass::get_mono_type(MonoClass *p_mono_class) {
+	return mono_class_get_type(p_mono_class);
 }
 }
 
 
 String GDMonoClass::get_full_name() const {
 String GDMonoClass::get_full_name() const {
+	return get_full_name(mono_class);
+}
 
 
-	String res = namespace_name;
-	if (res.length())
-		res += ".";
-	return res + class_name;
+MonoType *GDMonoClass::get_mono_type() {
+	// Care, you cannot compare MonoType pointers
+	return get_mono_type(mono_class);
+}
+
+bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
+
+	return mono_class_is_assignable_from(mono_class, p_from->mono_class);
 }
 }
 
 
 GDMonoClass *GDMonoClass::get_parent_class() {
 GDMonoClass *GDMonoClass::get_parent_class() {

+ 5 - 3
modules/mono/mono_gd/gd_mono_class.h

@@ -98,7 +98,11 @@ class GDMonoClass {
 	GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
 	GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
 
 
 public:
 public:
-	static MonoType *get_raw_type(GDMonoClass *p_class);
+	static String get_full_name(MonoClass *p_mono_class);
+	static MonoType *get_mono_type(MonoClass *p_mono_class);
+
+	String get_full_name() const;
+	MonoType *get_mono_type();
 
 
 	bool is_assignable_from(GDMonoClass *p_from) const;
 	bool is_assignable_from(GDMonoClass *p_from) const;
 
 
@@ -108,8 +112,6 @@ public:
 	_FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; }
 	_FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; }
 	_FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
 	_FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
 
 
-	String get_full_name() const;
-
 	GDMonoClass *get_parent_class();
 	GDMonoClass *get_parent_class();
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED

+ 40 - 5
modules/mono/mono_gd/gd_mono_field.cpp

@@ -148,7 +148,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 
 
 		case MONO_TYPE_ARRAY:
 		case MONO_TYPE_ARRAY:
 		case MONO_TYPE_SZARRAY: {
 		case MONO_TYPE_SZARRAY: {
-			MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class));
+			MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
 
 
 			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
 			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
 				SET_FROM_ARRAY_AND_BREAK(Array);
 				SET_FROM_ARRAY_AND_BREAK(Array);
@@ -200,6 +200,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 				break;
 				break;
 			}
 			}
 
 
+			if (CACHED_CLASS(Dictionary) == type_class) {
+				MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+				mono_field_set_value(p_object, mono_field, managed);
+				break;
+			}
+
+			if (CACHED_CLASS(Array) == type_class) {
+				MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+				mono_field_set_value(p_object, mono_field, managed);
+				break;
+			}
+
 			ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
 			ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
 			ERR_FAIL();
 			ERR_FAIL();
 		} break;
 		} break;
@@ -248,10 +260,13 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 					break;
 					break;
 				}
 				}
 				case Variant::DICTIONARY: {
 				case Variant::DICTIONARY: {
-					MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
+					MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+					mono_field_set_value(p_object, mono_field, managed);
+				} break;
+				case Variant::ARRAY: {
+					MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
 					mono_field_set_value(p_object, mono_field, managed);
 					mono_field_set_value(p_object, mono_field, managed);
 				} break;
 				} break;
-				case Variant::ARRAY: SET_FROM_ARRAY_AND_BREAK(Array);
 				case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
 				case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
 				case Variant::POOL_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
 				case Variant::POOL_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
 				case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
 				case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
@@ -265,8 +280,28 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 		} break;
 		} break;
 
 
 		case MONO_TYPE_GENERICINST: {
 		case MONO_TYPE_GENERICINST: {
-			if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) {
-				MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
+			MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
+
+			MonoException *exc = NULL;
+
+			GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
+			MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+			UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+			if (is_dict) {
+				MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class);
+				mono_field_set_value(p_object, mono_field, managed);
+				break;
+			}
+
+			exc = NULL;
+
+			GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
+			MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+			UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+			if (is_array) {
+				MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class);
 				mono_field_set_value(p_object, mono_field, managed);
 				mono_field_set_value(p_object, mono_field, managed);
 				break;
 				break;
 			}
 			}

+ 2 - 1
modules/mono/mono_gd/gd_mono_header.h

@@ -45,7 +45,8 @@ struct ManagedType {
 	GDMonoClass *type_class;
 	GDMonoClass *type_class;
 
 
 	ManagedType() {
 	ManagedType() {
-		type_class = 0;
+		type_encoding = 0;
+		type_class = NULL;
 	}
 	}
 };
 };
 
 

+ 100 - 73
modules/mono/mono_gd/gd_mono_marshal.cpp

@@ -120,7 +120,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
 
 
 		case MONO_TYPE_ARRAY:
 		case MONO_TYPE_ARRAY:
 		case MONO_TYPE_SZARRAY: {
 		case MONO_TYPE_SZARRAY: {
-			MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
+			MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
 
 
 			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
 			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
 				return Variant::ARRAY;
 				return Variant::ARRAY;
@@ -162,12 +162,36 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
 			if (CACHED_CLASS(RID) == type_class) {
 			if (CACHED_CLASS(RID) == type_class) {
 				return Variant::_RID;
 				return Variant::_RID;
 			}
 			}
+
+			if (CACHED_CLASS(Dictionary) == type_class) {
+				return Variant::DICTIONARY;
+			}
+
+			if (CACHED_CLASS(Array) == type_class) {
+				return Variant::ARRAY;
+			}
 		} break;
 		} break;
 
 
 		case MONO_TYPE_GENERICINST: {
 		case MONO_TYPE_GENERICINST: {
-			if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
+			MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
+
+			MonoException *exc = NULL;
+			GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
+			MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+			UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+			if (is_dict) {
 				return Variant::DICTIONARY;
 				return Variant::DICTIONARY;
 			}
 			}
+
+			exc = NULL;
+			GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
+			MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+			UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+			if (is_array) {
+				return Variant::ARRAY;
+			}
 		} break;
 		} break;
 
 
 		default: {
 		default: {
@@ -216,6 +240,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var) {
 	ManagedType type;
 	ManagedType type;
 
 
 	type.type_encoding = MONO_TYPE_OBJECT;
 	type.type_encoding = MONO_TYPE_OBJECT;
+	// type.type_class is not needed when we specify the MONO_TYPE_OBJECT encoding
 
 
 	return variant_to_mono_object(p_var, type);
 	return variant_to_mono_object(p_var, type);
 }
 }
@@ -315,7 +340,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 
 
 		case MONO_TYPE_ARRAY:
 		case MONO_TYPE_ARRAY:
 		case MONO_TYPE_SZARRAY: {
 		case MONO_TYPE_SZARRAY: {
-			MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
+			MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
 
 
 			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
 			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
 				return (MonoObject *)Array_to_mono_array(p_var->operator Array());
 				return (MonoObject *)Array_to_mono_array(p_var->operator Array());
@@ -360,6 +385,14 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 			if (CACHED_CLASS(RID) == type_class) {
 			if (CACHED_CLASS(RID) == type_class) {
 				return GDMonoUtils::create_managed_from(p_var->operator RID());
 				return GDMonoUtils::create_managed_from(p_var->operator RID());
 			}
 			}
+
+			if (CACHED_CLASS(Dictionary) == type_class) {
+				return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+			}
+
+			if (CACHED_CLASS(Array) == type_class) {
+				return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+			}
 		} break;
 		} break;
 		case MONO_TYPE_OBJECT: {
 		case MONO_TYPE_OBJECT: {
 			// Variant
 			// Variant
@@ -411,9 +444,9 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 					return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
 					return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
 				}
 				}
 				case Variant::DICTIONARY:
 				case Variant::DICTIONARY:
-					return Dictionary_to_mono_object(p_var->operator Dictionary());
+					return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
 				case Variant::ARRAY:
 				case Variant::ARRAY:
-					return (MonoObject *)Array_to_mono_array(p_var->operator Array());
+					return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
 				case Variant::POOL_BYTE_ARRAY:
 				case Variant::POOL_BYTE_ARRAY:
 					return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray());
 					return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray());
 				case Variant::POOL_INT_ARRAY:
 				case Variant::POOL_INT_ARRAY:
@@ -433,8 +466,24 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 			}
 			}
 			break;
 			break;
 			case MONO_TYPE_GENERICINST: {
 			case MONO_TYPE_GENERICINST: {
-				if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
-					return Dictionary_to_mono_object(p_var->operator Dictionary());
+				MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
+
+				MonoException *exc = NULL;
+				GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
+				MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+				if (is_dict) {
+					return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class);
+				}
+
+				exc = NULL;
+				GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
+				MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+				if (is_array) {
+					return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
 				}
 				}
 			} break;
 			} break;
 		} break;
 		} break;
@@ -452,7 +501,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 	GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
 	GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
 	ERR_FAIL_COND_V(!tclass, Variant());
 	ERR_FAIL_COND_V(!tclass, Variant());
 
 
-	MonoType *raw_type = tclass->get_raw_type(tclass);
+	MonoType *raw_type = tclass->get_mono_type();
 
 
 	ManagedType type;
 	ManagedType type;
 
 
@@ -531,7 +580,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 
 
 		case MONO_TYPE_ARRAY:
 		case MONO_TYPE_ARRAY:
 		case MONO_TYPE_SZARRAY: {
 		case MONO_TYPE_SZARRAY: {
-			MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class));
+			MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
 
 
 			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
 			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
 				return mono_array_to_Array((MonoArray *)p_obj);
 				return mono_array_to_Array((MonoArray *)p_obj);
@@ -579,11 +628,51 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 				RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj));
 				RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj));
 				return ptr ? Variant(*ptr) : Variant();
 				return ptr ? Variant(*ptr) : Variant();
 			}
 			}
+
+			if (CACHED_CLASS(Array) == type_class) {
+				MonoException *exc = NULL;
+				GDMonoUtils::Array_GetPtr get_ptr = CACHED_METHOD_THUNK(Array, GetPtr);
+				Array *ptr = get_ptr(p_obj, (MonoObject **)&exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+				return ptr ? Variant(*ptr) : Variant();
+			}
+
+			if (CACHED_CLASS(Dictionary) == type_class) {
+				MonoException *exc = NULL;
+				GDMonoUtils::Dictionary_GetPtr get_ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr);
+				Dictionary *ptr = get_ptr(p_obj, (MonoObject **)&exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+				return ptr ? Variant(*ptr) : Variant();
+			}
 		} break;
 		} break;
 
 
 		case MONO_TYPE_GENERICINST: {
 		case MONO_TYPE_GENERICINST: {
-			if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) {
-				return mono_object_to_Dictionary(p_obj);
+			MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
+
+			MonoException *exc = NULL;
+
+			GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
+			MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+			UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+			if (is_dict) {
+				MonoException *exc = NULL;
+				MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+				return *unbox<Dictionary *>(ret);
+			}
+
+			exc = NULL;
+
+			GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
+			MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+			UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+			if (is_array) {
+				MonoException *exc = NULL;
+				MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+				return *unbox<Array *>(ret);
 			}
 			}
 		} break;
 		} break;
 	}
 	}
@@ -822,66 +911,4 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) {
 
 
 	return ret;
 	return ret;
 }
 }
-
-MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict) {
-	MonoArray *keys = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size());
-	MonoArray *values = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size());
-
-	int i = 0;
-	const Variant *dkey = NULL;
-	while ((dkey = p_dict.next(dkey))) {
-		mono_array_set(keys, MonoObject *, i, variant_to_mono_object(dkey));
-		mono_array_set(values, MonoObject *, i, variant_to_mono_object(p_dict[*dkey]));
-		i++;
-	}
-
-	GDMonoUtils::MarshalUtils_ArraysToDict arrays_to_dict = CACHED_METHOD_THUNK(MarshalUtils, ArraysToDictionary);
-
-	MonoException *exc = NULL;
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	MonoObject *ret = arrays_to_dict(keys, values, (MonoObject **)&exc);
-	GD_MONO_END_RUNTIME_INVOKE;
-
-	if (exc) {
-		GDMonoUtils::set_pending_exception(exc);
-		ERR_FAIL_V(NULL);
-	}
-
-	return ret;
-}
-
-Dictionary mono_object_to_Dictionary(MonoObject *p_dict) {
-	Dictionary ret;
-
-	if (!p_dict)
-		return ret;
-
-	GDMonoUtils::MarshalUtils_DictToArrays dict_to_arrays = CACHED_METHOD_THUNK(MarshalUtils, DictionaryToArrays);
-
-	MonoArray *keys = NULL;
-	MonoArray *values = NULL;
-	MonoException *exc = NULL;
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	dict_to_arrays(p_dict, &keys, &values, (MonoObject **)&exc);
-	GD_MONO_END_RUNTIME_INVOKE;
-
-	if (exc) {
-		GDMonoUtils::set_pending_exception(exc);
-		ERR_FAIL_V(Dictionary());
-	}
-
-	int length = mono_array_length(keys);
-
-	for (int i = 0; i < length; i++) {
-		MonoObject *key_obj = mono_array_get(keys, MonoObject *, i);
-		MonoObject *value_obj = mono_array_get(values, MonoObject *, i);
-
-		Variant key = key_obj ? mono_object_to_variant(key_obj) : Variant();
-		Variant value = value_obj ? mono_object_to_variant(value_obj) : Variant();
-
-		ret[key] = value;
-	}
-
-	return ret;
-}
 } // namespace GDMonoMarshal
 } // namespace GDMonoMarshal

+ 0 - 5
modules/mono/mono_gd/gd_mono_marshal.h

@@ -143,11 +143,6 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array);
 MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
 MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
 PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array);
 PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array);
 
 
-// Dictionary
-
-MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict);
-Dictionary mono_object_to_Dictionary(MonoObject *p_dict);
-
 #ifdef YOLO_COPY
 #ifdef YOLO_COPY
 #define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in;
 #define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in;
 #define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in);
 #define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in);

+ 2 - 17
modules/mono/mono_gd/gd_mono_property.cpp

@@ -139,23 +139,8 @@ bool GDMonoProperty::has_setter() {
 }
 }
 
 
 void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
 void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
-	MonoMethod *prop_method = mono_property_get_set_method(mono_property);
-
-	MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
-	mono_array_set(params, MonoObject *, 0, p_value);
-
-	MonoException *exc = NULL;
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	mono_runtime_invoke_array(prop_method, p_object, params, (MonoObject **)&exc);
-	GD_MONO_END_RUNTIME_INVOKE;
-
-	if (exc) {
-		if (r_exc) {
-			*r_exc = exc;
-		} else {
-			GDMonoUtils::set_pending_exception(exc);
-		}
-	}
+	void *params[1] = { p_value };
+	set_value(p_object, params, r_exc);
 }
 }
 
 
 void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {
 void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {

+ 102 - 27
modules/mono/mono_gd/gd_mono_utils.cpp

@@ -87,6 +87,8 @@ void MonoCache::clear_members() {
 	method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL;
 	method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL;
 #endif
 #endif
 
 
+	class_KeyNotFoundException = NULL;
+
 	rawclass_Dictionary = NULL;
 	rawclass_Dictionary = NULL;
 
 
 	class_Vector2 = NULL;
 	class_Vector2 = NULL;
@@ -107,6 +109,8 @@ void MonoCache::clear_members() {
 	class_Control = NULL;
 	class_Control = NULL;
 	class_Spatial = NULL;
 	class_Spatial = NULL;
 	class_WeakRef = NULL;
 	class_WeakRef = NULL;
+	class_Array = NULL;
+	class_Dictionary = NULL;
 	class_MarshalUtils = NULL;
 	class_MarshalUtils = NULL;
 
 
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
@@ -134,8 +138,10 @@ void MonoCache::clear_members() {
 	field_Image_ptr = NULL;
 	field_Image_ptr = NULL;
 	field_RID_ptr = NULL;
 	field_RID_ptr = NULL;
 
 
-	methodthunk_MarshalUtils_DictionaryToArrays = NULL;
-	methodthunk_MarshalUtils_ArraysToDictionary = NULL;
+	methodthunk_Array_GetPtr = NULL;
+	methodthunk_Dictionary_GetPtr = NULL;
+	methodthunk_MarshalUtils_IsArrayGenericType = NULL;
+	methodthunk_MarshalUtils_IsDictionaryGenericType = NULL;
 	methodthunk_SignalAwaiter_SignalCallback = NULL;
 	methodthunk_SignalAwaiter_SignalCallback = NULL;
 	methodthunk_SignalAwaiter_FailureCallback = NULL;
 	methodthunk_SignalAwaiter_FailureCallback = NULL;
 	methodthunk_GodotTaskScheduler_Activate = NULL;
 	methodthunk_GodotTaskScheduler_Activate = NULL;
@@ -175,6 +181,8 @@ void update_corlib_cache() {
 	CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
 	CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
 #endif
 #endif
 
 
+	CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException"));
+
 	mono_cache.corlib_cache_updated = true;
 	mono_cache.corlib_cache_updated = true;
 }
 }
 
 
@@ -198,6 +206,8 @@ void update_godot_api_cache() {
 	CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
 	CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
 	CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
 	CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
 	CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
 	CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
+	CACHE_CLASS_AND_CHECK(Array, GODOT_API_CLASS(Array));
+	CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_CLASS(Dictionary));
 	CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
 	CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
 
 
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
@@ -224,8 +234,10 @@ void update_godot_api_cache() {
 	CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
 	CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
 	CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
 	CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
 
 
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryToArrays, (MarshalUtils_DictToArrays)CACHED_CLASS(MarshalUtils)->get_method("DictionaryToArrays", 3)->get_thunk());
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArraysToDictionary, (MarshalUtils_ArraysToDict)CACHED_CLASS(MarshalUtils)->get_method("ArraysToDictionary", 2)->get_thunk());
+	CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_CLASS(Array)->get_method("GetPtr", 0)->get_thunk());
+	CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_CLASS(Dictionary)->get_method("GetPtr", 0)->get_thunk());
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method("IsArrayGenericType", 1)->get_thunk());
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method("IsDictionaryGenericType", 1)->get_thunk());
 	CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)->get_thunk());
 	CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)->get_thunk());
 	CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk());
 	CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk());
 	CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk());
 	CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk());
@@ -234,24 +246,9 @@ void update_godot_api_cache() {
 	CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)->get_thunk());
 	CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)->get_thunk());
 #endif
 #endif
 
 
-	{
-		/*
-		 * TODO Right now we only support Dictionary<object, object>.
-		 * It would be great if we could support other key/value types
-		 * without forcing the user to copy the entries.
-		 */
-		GDMonoMethod *method_get_dict_type = CACHED_CLASS(MarshalUtils)->get_method("GetDictionaryType", 0);
-		ERR_FAIL_NULL(method_get_dict_type);
-		MonoReflectionType *dict_refl_type = (MonoReflectionType *)method_get_dict_type->invoke(NULL);
-		ERR_FAIL_NULL(dict_refl_type);
-		MonoType *dict_type = mono_reflection_type_get_type(dict_refl_type);
-		ERR_FAIL_NULL(dict_type);
-
-		CACHE_RAW_MONO_CLASS_AND_CHECK(Dictionary, mono_class_from_mono_type(dict_type));
-	}
-
+	// TODO Move to CSharpLanguage::init()
 	MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
 	MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
-	mono_runtime_object_init(task_scheduler);
+	GDMonoUtils::runtime_object_init(task_scheduler);
 	mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
 	mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
 
 
 	mono_cache.godot_api_cache_updated = true;
 	mono_cache.godot_api_cache_updated = true;
@@ -304,6 +301,12 @@ MonoThread *get_current_thread() {
 	return mono_thread_current();
 	return mono_thread_current();
 }
 }
 
 
+void runtime_object_init(MonoObject *p_this_obj) {
+	GD_MONO_BEGIN_RUNTIME_INVOKE;
+	mono_runtime_object_init(p_this_obj);
+	GD_MONO_END_RUNTIME_INVOKE;
+}
+
 GDMonoClass *get_object_class(MonoObject *p_object) {
 GDMonoClass *get_object_class(MonoObject *p_object) {
 	return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
 	return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
 }
 }
@@ -358,7 +361,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
 	CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
 	CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
 
 
 	// Construct
 	// Construct
-	mono_runtime_object_init(mono_object);
+	GDMonoUtils::runtime_object_init(mono_object);
 
 
 	return mono_object;
 	return mono_object;
 }
 }
@@ -368,7 +371,7 @@ MonoObject *create_managed_from(const NodePath &p_from) {
 	ERR_FAIL_NULL_V(mono_object, NULL);
 	ERR_FAIL_NULL_V(mono_object, NULL);
 
 
 	// Construct
 	// Construct
-	mono_runtime_object_init(mono_object);
+	GDMonoUtils::runtime_object_init(mono_object);
 
 
 	CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
 	CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
 
 
@@ -380,13 +383,73 @@ MonoObject *create_managed_from(const RID &p_from) {
 	ERR_FAIL_NULL_V(mono_object, NULL);
 	ERR_FAIL_NULL_V(mono_object, NULL);
 
 
 	// Construct
 	// Construct
-	mono_runtime_object_init(mono_object);
+	GDMonoUtils::runtime_object_init(mono_object);
 
 
 	CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
 	CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
 
 
 	return mono_object;
 	return mono_object;
 }
 }
 
 
+MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) {
+	MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
+	ERR_FAIL_NULL_V(mono_object, NULL);
+
+	// Search constructor that takes a pointer as parameter
+	MonoMethod *m;
+	void *iter = NULL;
+	while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
+		if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
+			MonoMethodSignature *sig = mono_method_signature(m);
+			void *front = NULL;
+			if (mono_signature_get_param_count(sig) == 1 &&
+					mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
+				break;
+			}
+		}
+	}
+
+	CRASH_COND(m == NULL);
+
+	Array *new_array = memnew(Array(p_from));
+	void *args[1] = { &new_array };
+
+	MonoException *exc = NULL;
+	mono_runtime_invoke(m, mono_object, args, (MonoObject **)&exc);
+	UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+	return mono_object;
+}
+
+MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) {
+	MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
+	ERR_FAIL_NULL_V(mono_object, NULL);
+
+	// Search constructor that takes a pointer as parameter
+	MonoMethod *m;
+	void *iter = NULL;
+	while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
+		if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
+			MonoMethodSignature *sig = mono_method_signature(m);
+			void *front = NULL;
+			if (mono_signature_get_param_count(sig) == 1 &&
+					mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
+				break;
+			}
+		}
+	}
+
+	CRASH_COND(m == NULL);
+
+	Dictionary *new_dict = memnew(Dictionary(p_from));
+	void *args[1] = { &new_dict };
+
+	MonoException *exc = NULL;
+	mono_runtime_invoke(m, mono_object, args, (MonoObject **)&exc);
+	UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+	return mono_object;
+}
+
 MonoDomain *create_domain(const String &p_friendly_name) {
 MonoDomain *create_domain(const String &p_friendly_name) {
 	MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
 	MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
 
 
@@ -400,10 +463,10 @@ MonoDomain *create_domain(const String &p_friendly_name) {
 	return domain;
 	return domain;
 }
 }
 
 
-String get_exception_name_and_message(MonoException *p_ex) {
+String get_exception_name_and_message(MonoException *p_exc) {
 	String res;
 	String res;
 
 
-	MonoClass *klass = mono_object_get_class((MonoObject *)p_ex);
+	MonoClass *klass = mono_object_get_class((MonoObject *)p_exc);
 	MonoType *type = mono_class_get_type(klass);
 	MonoType *type = mono_class_get_type(klass);
 
 
 	char *full_name = mono_type_full_name(type);
 	char *full_name = mono_type_full_name(type);
@@ -413,12 +476,24 @@ String get_exception_name_and_message(MonoException *p_ex) {
 	res += ": ";
 	res += ": ";
 
 
 	MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
 	MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
-	MonoString *msg = (MonoString *)mono_property_get_value(prop, (MonoObject *)p_ex, NULL, NULL);
+	GD_MONO_BEGIN_RUNTIME_INVOKE;
+	MonoString *msg = (MonoString *)mono_property_get_value(prop, (MonoObject *)p_exc, NULL, NULL);
+	GD_MONO_END_RUNTIME_INVOKE;
 	res += GDMonoMarshal::mono_string_to_godot(msg);
 	res += GDMonoMarshal::mono_string_to_godot(msg);
 
 
 	return res;
 	return res;
 }
 }
 
 
+void set_exception_message(MonoException *p_exc, String message) {
+	MonoClass *klass = mono_object_get_class((MonoObject *)p_exc);
+	MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
+	MonoString *msg = GDMonoMarshal::mono_string_from_godot(message);
+	void *params[1] = { msg };
+	GD_MONO_BEGIN_RUNTIME_INVOKE;
+	mono_property_set_value(prop, (MonoObject *)p_exc, params, NULL);
+	GD_MONO_END_RUNTIME_INVOKE;
+}
+
 void debug_print_unhandled_exception(MonoException *p_exc) {
 void debug_print_unhandled_exception(MonoException *p_exc) {
 	print_unhandled_exception(p_exc);
 	print_unhandled_exception(p_exc);
 	debug_send_unhandled_exception_error(p_exc);
 	debug_send_unhandled_exception_error(p_exc);

+ 26 - 5
modules/mono/mono_gd/gd_mono_utils.h

@@ -41,14 +41,24 @@
 #include "object.h"
 #include "object.h"
 #include "reference.h"
 #include "reference.h"
 
 
+#define UNLIKELY_UNHANDLED_EXCEPTION(m_exc)            \
+	if (unlikely(m_exc != NULL)) {                     \
+		GDMonoUtils::debug_unhandled_exception(m_exc); \
+		_UNREACHABLE_();                               \
+	}
+
 namespace GDMonoUtils {
 namespace GDMonoUtils {
 
 
-typedef MonoObject *(*MarshalUtils_DictToArrays)(MonoObject *, MonoArray **, MonoArray **, MonoObject **);
-typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoObject **);
+typedef Array *(*Array_GetPtr)(MonoObject *, MonoObject **);
+typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoObject **);
 typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
 typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
 typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
 typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
 typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
 typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
 typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
 typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
+typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
+typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
+typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
+typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
 typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **);
 typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **);
 
 
 struct MonoCache {
 struct MonoCache {
@@ -79,6 +89,8 @@ struct MonoCache {
 	GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
 	GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
 #endif
 #endif
 
 
+	GDMonoClass *class_KeyNotFoundException;
+
 	MonoClass *rawclass_Dictionary;
 	MonoClass *rawclass_Dictionary;
 	// -----------------------------------------------
 	// -----------------------------------------------
 
 
@@ -100,6 +112,8 @@ struct MonoCache {
 	GDMonoClass *class_Control;
 	GDMonoClass *class_Control;
 	GDMonoClass *class_Spatial;
 	GDMonoClass *class_Spatial;
 	GDMonoClass *class_WeakRef;
 	GDMonoClass *class_WeakRef;
+	GDMonoClass *class_Array;
+	GDMonoClass *class_Dictionary;
 	GDMonoClass *class_MarshalUtils;
 	GDMonoClass *class_MarshalUtils;
 
 
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
@@ -127,8 +141,10 @@ struct MonoCache {
 	GDMonoField *field_Image_ptr;
 	GDMonoField *field_Image_ptr;
 	GDMonoField *field_RID_ptr;
 	GDMonoField *field_RID_ptr;
 
 
-	MarshalUtils_DictToArrays methodthunk_MarshalUtils_DictionaryToArrays;
-	MarshalUtils_ArraysToDict methodthunk_MarshalUtils_ArraysToDictionary;
+	Array_GetPtr methodthunk_Array_GetPtr;
+	Dictionary_GetPtr methodthunk_Dictionary_GetPtr;
+	IsArrayGenericType methodthunk_MarshalUtils_IsArrayGenericType;
+	IsDictionaryGenericType methodthunk_MarshalUtils_IsDictionaryGenericType;
 	SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
 	SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
 	SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
 	SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
 	GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
 	GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
@@ -175,6 +191,8 @@ _FORCE_INLINE_ bool is_main_thread() {
 	return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
 	return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
 }
 }
 
 
+void runtime_object_init(MonoObject *p_this_obj);
+
 GDMonoClass *get_object_class(MonoObject *p_object);
 GDMonoClass *get_object_class(MonoObject *p_object);
 GDMonoClass *type_get_proxy_class(const StringName &p_type);
 GDMonoClass *type_get_proxy_class(const StringName &p_type);
 GDMonoClass *get_class_native_base(GDMonoClass *p_class);
 GDMonoClass *get_class_native_base(GDMonoClass *p_class);
@@ -183,10 +201,13 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
 
 
 MonoObject *create_managed_from(const NodePath &p_from);
 MonoObject *create_managed_from(const NodePath &p_from);
 MonoObject *create_managed_from(const RID &p_from);
 MonoObject *create_managed_from(const RID &p_from);
+MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class);
+MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class);
 
 
 MonoDomain *create_domain(const String &p_friendly_name);
 MonoDomain *create_domain(const String &p_friendly_name);
 
 
-String get_exception_name_and_message(MonoException *p_ex);
+String get_exception_name_and_message(MonoException *p_exc);
+void set_exception_message(MonoException *p_exc, String message);
 
 
 void debug_print_unhandled_exception(MonoException *p_exc);
 void debug_print_unhandled_exception(MonoException *p_exc);
 void debug_send_unhandled_exception_error(MonoException *p_exc);
 void debug_send_unhandled_exception_error(MonoException *p_exc);