summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/mono/csharp_script.cpp136
-rw-r--r--modules/mono/csharp_script.h3
-rw-r--r--modules/mono/glue/Managed/Files/MarshalUtils.cs116
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp52
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp242
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h24
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp128
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h50
-rw-r--r--modules/mono/mono_gd/i_mono_class_member.h6
13 files changed, 589 insertions, 190 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index ef09e76d11..bfbd6ca80e 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -2020,7 +2020,7 @@ bool CSharpScript::_update_exports() {
for (int i = fields.size() - 1; i >= 0; i--) {
GDMonoField *field = fields[i];
- if (_get_member_export(top, field, prop_info, exported)) {
+ if (_get_member_export(field, prop_info, exported)) {
StringName name = field->get_name();
if (exported) {
@@ -2041,7 +2041,7 @@ bool CSharpScript::_update_exports() {
for (int i = properties.size() - 1; i >= 0; i--) {
GDMonoProperty *property = properties[i];
- if (_get_member_export(top, property, prop_info, exported)) {
+ if (_get_member_export(property, prop_info, exported)) {
StringName name = property->get_name();
if (exported) {
@@ -2168,17 +2168,19 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve
* Returns false if there was an error, otherwise true.
* If there was an error, r_prop_info and r_exported are not assigned any value.
*/
-bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) {
+bool CSharpScript::_get_member_export(IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) {
- StringName name = p_member->get_name();
+ // Goddammit, C++. All I wanted was some nested functions.
+#define MEMBER_FULL_QUALIFIED_NAME(m_member) \
+ (m_member->get_enclosing_class()->get_full_name() + "." + (String)m_member->get_name())
if (p_member->is_static()) {
if (p_member->has_attribute(CACHED_CLASS(ExportAttribute)))
- ERR_PRINTS("Cannot export member because it is static: " + p_class->get_full_name() + "." + name.operator String());
+ ERR_PRINTS("Cannot export member because it is static: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
return false;
}
- if (member_info.has(name))
+ if (member_info.has(p_member->get_name()))
return false;
ManagedType type;
@@ -2191,19 +2193,22 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
CRASH_NOW();
}
- GDMonoMarshal::ExportInfo export_info;
- Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type, &export_info);
+ Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type);
if (!p_member->has_attribute(CACHED_CLASS(ExportAttribute))) {
- r_prop_info = PropertyInfo(variant_type, name.operator String(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
+ r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
r_exported = false;
return true;
}
if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) {
GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
- if (!property->has_getter() || !property->has_setter()) {
- ERR_PRINTS("Cannot export property because it does not provide a getter or a setter: " + p_class->get_full_name() + "." + name.operator String());
+ if (!property->has_getter()) {
+ ERR_PRINTS("Read-only property cannot be exported: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
+ return false;
+ }
+ if (!property->has_setter()) {
+ ERR_PRINTS("Set-only property (without getter) cannot be exported: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
return false;
}
}
@@ -2214,16 +2219,38 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
String hint_string;
if (variant_type == Variant::NIL) {
- ERR_PRINTS("Unknown type of exported member: " + p_class->get_full_name() + "." + name.operator String());
+ ERR_PRINTS("Unknown exported member type: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
return false;
- } else if (variant_type == Variant::INT && type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(type.type_class->get_mono_ptr())) {
- // TODO: Move to ExportInfo?
- variant_type = Variant::INT;
- hint = PROPERTY_HINT_ENUM;
+ }
+
+ int hint_res = _try_get_member_export_hint(p_member, type, variant_type, /* allow_generics: */ true, hint, hint_string);
+
+ if (hint_res == -1) {
+ ERR_EXPLAIN("Error while trying to determine information about the exported member: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
+ ERR_FAIL_V(false);
+ }
+
+ if (hint_res == 0) {
+ hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
+ hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
+ }
+
+ r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE);
+ r_exported = true;
+
+ return true;
+
+#undef MEMBER_FULL_QUALIFIED_NAME
+}
+
+int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) {
+
+ if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) {
+ r_hint = PROPERTY_HINT_ENUM;
- Vector<MonoClassField *> fields = type.type_class->get_enum_fields();
+ Vector<MonoClassField *> fields = p_type.type_class->get_enum_fields();
- MonoType *enum_basetype = mono_class_enum_basetype(type.type_class->get_mono_ptr());
+ MonoType *enum_basetype = mono_class_enum_basetype(p_type.type_class->get_mono_ptr());
String name_only_hint_string;
@@ -2236,12 +2263,12 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
MonoClassField *field = fields[i];
if (i > 0) {
- hint_string += ",";
+ r_hint_string += ",";
name_only_hint_string += ",";
}
String enum_field_name = mono_field_get_name(field);
- hint_string += enum_field_name;
+ r_hint_string += enum_field_name;
name_only_hint_string += enum_field_name;
// TODO:
@@ -2251,54 +2278,73 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
MonoObject *val_obj = mono_field_get_value_object(mono_domain_get(), field, NULL);
if (val_obj == NULL) {
- ERR_PRINTS("Failed to get '" + enum_field_name + "' constant enum value of exported member: " +
- p_class->get_full_name() + "." + name.operator String());
- return false;
+ ERR_EXPLAIN("Failed to get '" + enum_field_name + "' constant enum value");
+ ERR_FAIL_V(-1);
}
bool r_error;
uint64_t val = GDMonoUtils::unbox_enum_value(val_obj, enum_basetype, r_error);
if (r_error) {
- ERR_PRINTS("Failed to unbox '" + enum_field_name + "' constant enum value of exported member: " +
- p_class->get_full_name() + "." + name.operator String());
- return false;
+ ERR_EXPLAIN("Failed to unbox '" + enum_field_name + "' constant enum value");
+ ERR_FAIL_V(-1);
}
if (val != (unsigned int)i) {
uses_default_values = false;
}
- hint_string += ":";
- hint_string += String::num_uint64(val);
+ r_hint_string += ":";
+ r_hint_string += String::num_uint64(val);
}
if (uses_default_values) {
// If we use the format NAME:VAL, that's what the editor displays.
// That's annoying if the user is not using custom values for the enum constants.
// This may not be needed in the future if the editor is changed to not display values.
- hint_string = name_only_hint_string;
+ r_hint_string = name_only_hint_string;
}
- } else if (variant_type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(type.type_class)) {
- GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(type.type_class);
+ } else if (p_variant_type == Variant::OBJECT && CACHED_CLASS(GodotResource)->is_assignable_from(p_type.type_class)) {
+ GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(p_type.type_class);
CRASH_COND(field_native_class == NULL);
- hint = PROPERTY_HINT_RESOURCE_TYPE;
- hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class);
- } else if (variant_type == Variant::ARRAY && export_info.array.element_type != Variant::NIL) {
- String elem_type_str = itos(export_info.array.element_type);
- hint = PROPERTY_HINT_TYPE_STRING;
- hint_string = elem_type_str + "/" + elem_type_str + ":" + export_info.array.element_native_name;
- } else if (variant_type == Variant::DICTIONARY && export_info.dictionary.key_type != Variant::NIL && export_info.dictionary.value_type != Variant::NIL) {
- // TODO: There is no hint for this yet
+ r_hint = PROPERTY_HINT_RESOURCE_TYPE;
+ r_hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class);
+ } else if (p_allow_generics && p_variant_type == Variant::ARRAY) {
+ // Nested arrays are not supported in the inspector
+
+ ManagedType elem_type;
+
+ if (!GDMonoMarshal::try_get_array_element_type(p_type, elem_type))
+ return 0;
+
+ Variant::Type elem_variant_type = GDMonoMarshal::managed_to_variant_type(elem_type);
+
+ PropertyHint elem_hint = PROPERTY_HINT_NONE;
+ String elem_hint_string;
+
+ if (elem_variant_type == Variant::NIL) {
+ ERR_EXPLAIN("Unknown array element type");
+ ERR_FAIL_V(-1);
+ }
+
+ int hint_res = _try_get_member_export_hint(p_member, elem_type, elem_variant_type, /* allow_generics: */ false, elem_hint, elem_hint_string);
+
+ if (hint_res == -1) {
+ ERR_EXPLAIN("Error while trying to determine information about the array element type");
+ ERR_FAIL_V(-1);
+ }
+
+ // Format: type/hint:hint_string
+ r_hint_string = itos(elem_variant_type) + "/" + itos(elem_hint) + ":" + elem_hint_string;
+ r_hint = PROPERTY_HINT_TYPE_STRING;
+
+ } else if (p_allow_generics && p_variant_type == Variant::DICTIONARY) {
+ // TODO: Dictionaries are not supported in the inspector
} else {
- hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
- hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
+ return 0;
}
- r_prop_info = PropertyInfo(variant_type, name.operator String(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE);
- r_exported = true;
-
- return true;
+ return 1;
}
#endif
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index fe4eed2e24..298d55c4df 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -127,7 +127,8 @@ class CSharpScript : public Script {
bool _update_exports();
#ifdef TOOLS_ENABLED
- bool _get_member_export(GDMonoClass *p_class, IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported);
+ bool _get_member_export(IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported);
+ static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string);
#endif
CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error);
diff --git a/modules/mono/glue/Managed/Files/MarshalUtils.cs b/modules/mono/glue/Managed/Files/MarshalUtils.cs
index 7e72b0edb5..730a1e1585 100644
--- a/modules/mono/glue/Managed/Files/MarshalUtils.cs
+++ b/modules/mono/glue/Managed/Files/MarshalUtils.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections;
+using System.Collections.Generic;
namespace Godot
{
@@ -8,29 +9,113 @@ namespace Godot
static class MarshalUtils
{
+ /// <summary>
+ /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
+ /// is <see cref="Godot.Collections.Array{T}"/>; otherwise returns <see langword="false"/>.
+ /// </summary>
+ /// <exception cref="System.InvalidOperationException">
+ /// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
+ /// </exception>
static bool TypeIsGenericArray(Type type)
{
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
}
+ /// <summary>
+ /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
+ /// is <see cref="Godot.Collections.Dictionary{T}"/>; otherwise returns <see langword="false"/>.
+ /// </summary>
+ /// <exception cref="System.InvalidOperationException">
+ /// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
+ /// </exception>
static bool TypeIsGenericDictionary(Type type)
{
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
}
- static void ArrayGetElementType(Type type, out Type elementType)
+ static void ArrayGetElementType(Type arrayType, out Type elementType)
{
- elementType = type.GetGenericArguments()[0];
+ elementType = arrayType.GetGenericArguments()[0];
}
- static void DictionaryGetKeyValueTypes(Type type, out Type keyType, out Type valueType)
+ static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType)
{
- var genericArgs = type.GetGenericArguments();
-
+ var genericArgs = dictionaryType.GetGenericArguments();
keyType = genericArgs[0];
valueType = genericArgs[1];
}
+ static bool GenericIEnumerableIsAssignableFromType(Type type, out Type elementType)
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ {
+ elementType = type.GetGenericArguments()[0];
+ return true;
+ }
+
+ foreach (var interfaceType in type.GetInterfaces())
+ {
+ if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ {
+ elementType = interfaceType.GetGenericArguments()[0];
+ return true;
+ }
+ }
+
+ Type baseType = type.BaseType;
+
+ if (baseType == null)
+ {
+ elementType = null;
+ return false;
+ }
+
+ return GenericIEnumerableIsAssignableFromType(baseType, out elementType);
+ }
+
+ static bool GenericIDictionaryIsAssignableFromType(Type type, out Type keyType, out Type valueType)
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
+ {
+ var genericArgs = type.GetGenericArguments();
+ keyType = genericArgs[0];
+ valueType = genericArgs[1];
+ return true;
+ }
+
+ foreach (var interfaceType in type.GetInterfaces())
+ {
+ if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
+ {
+ var genericArgs = interfaceType.GetGenericArguments();
+ keyType = genericArgs[0];
+ valueType = genericArgs[1];
+ return true;
+ }
+ }
+
+ Type baseType = type.BaseType;
+
+ if (baseType == null)
+ {
+ keyType = null;
+ valueType = null;
+ return false;
+ }
+
+ return GenericIDictionaryIsAssignableFromType(baseType, out keyType, out valueType);
+ }
+
+ static Type MakeGenericArrayType(Type elemType)
+ {
+ return typeof(Godot.Collections.Array<>).MakeGenericType(elemType);
+ }
+
+ static Type MakeGenericDictionaryType(Type keyType, Type valueType)
+ {
+ return typeof(Godot.Collections.Dictionary<,>).MakeGenericType(keyType, valueType);
+ }
+
// TODO Add support for IEnumerable<T> and IDictionary<TKey, TValue>
// TODO: EnumerableToArray and IDictionaryToDictionary can be optimized
@@ -64,5 +149,26 @@ namespace Godot
Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
}
}
+
+ internal static void GenericIDictionaryToDictionary(object dictionary, IntPtr godotDictionaryPtr)
+ {
+#if DEBUG
+ if (!GenericIDictionaryIsAssignableFromType(dictionary.GetType()))
+ throw new InvalidOperationException("The type does not implement IDictionary<,>");
+#endif
+
+ // TODO: Can we optimize this?
+
+ var keys = ((IEnumerable)dictionary.GetType().GetProperty("Keys").GetValue(dictionary)).GetEnumerator();
+ var values = ((IEnumerable)dictionary.GetType().GetProperty("Values").GetValue(dictionary)).GetEnumerator();
+
+ while (keys.MoveNext() && values.MoveNext())
+ {
+ object key = keys.Current;
+ object value = values.Current;
+
+ Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, key, value);
+ }
+ }
}
}
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 9779797d1a..2e79f87625 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -313,12 +313,32 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ // The order in which we check the following interfaces is very important (dictionaries and generics first)
+
+ MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type());
+
+ MonoReflectionType *key_reftype, *value_reftype;
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(),
+ GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
mono_field_set_value(p_object, mono_field, managed);
break;
}
+ MonoReflectionType *elem_reftype;
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(),
+ GDMonoUtils::Marshal::make_generic_array_type(elem_reftype));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
mono_field_set_value(p_object, mono_field, managed);
@@ -432,26 +452,24 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
- MonoException *exc = NULL;
-
- GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
-
- if (is_dict) {
+ if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
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;
+ if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class);
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
- GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ // The order in which we check the following interfaces is very important (dictionaries and generics first)
- if (is_array) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class);
+ MonoReflectionType *key_reftype, *value_reftype;
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(),
+ GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype));
mono_field_set_value(p_object, mono_field, managed);
break;
}
@@ -462,6 +480,14 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ MonoReflectionType *elem_reftype;
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(),
+ GDMonoUtils::Marshal::make_generic_array_type(elem_reftype));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
mono_field_set_value(p_object, mono_field, managed);
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
index e348583370..a7727ddf34 100644
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ b/modules/mono/mono_gd/gd_mono_field.h
@@ -47,9 +47,11 @@ class GDMonoField : public IMonoClassMember {
MonoCustomAttrInfo *attributes;
public:
- virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_FIELD; }
+ virtual GDMonoClass *get_enclosing_class() const GD_FINAL { return owner; }
- virtual StringName get_name() GD_FINAL { return name; }
+ virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_FIELD; }
+
+ virtual StringName get_name() const GD_FINAL { return name; }
virtual bool is_static() GD_FINAL;
virtual Visibility get_visibility() GD_FINAL;
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index d586b73cf9..461dcf3ec0 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -35,7 +35,7 @@
namespace GDMonoMarshal {
-Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info) {
+Variant::Type managed_to_variant_type(const ManagedType &p_type) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
return Variant::BOOL;
@@ -157,10 +157,24 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_e
return Variant::ARRAY;
}
+ // The order in which we check the following interfaces is very important (dictionaries and generics first)
+
+ MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type());
+
+ MonoReflectionType *key_reftype, *value_reftype;
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
+ return Variant::DICTIONARY;
+ }
+
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
return Variant::DICTIONARY;
}
+ MonoReflectionType *elem_reftype;
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
+ return Variant::ARRAY;
+ }
+
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
return Variant::ARRAY;
}
@@ -169,71 +183,96 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_e
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
- MonoException *exc = NULL;
- GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
-
- if (is_dict) {
- if (r_export_info) {
- MonoReflectionType *key_reftype;
- MonoReflectionType *value_reftype;
+ if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
+ return Variant::DICTIONARY;
+ }
- exc = NULL;
- invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes),
- reftype, &key_reftype, &value_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
+ return Variant::ARRAY;
+ }
- ManagedType key_type = ManagedType::from_reftype(key_reftype);
- ManagedType value_type = ManagedType::from_reftype(value_reftype);
+ // The order in which we check the following interfaces is very important (dictionaries and generics first)
- r_export_info->dictionary.key_type = managed_to_variant_type(key_type);
- r_export_info->dictionary.key_native_name = NATIVE_GDMONOCLASS_NAME(key_type.type_class);
- r_export_info->dictionary.value_type = managed_to_variant_type(value_type);
- r_export_info->dictionary.value_native_name = NATIVE_GDMONOCLASS_NAME(value_type.type_class);
- }
+ MonoReflectionType *key_reftype, *value_reftype;
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype))
+ return Variant::DICTIONARY;
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
return Variant::DICTIONARY;
}
- exc = NULL;
- GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ MonoReflectionType *elem_reftype;
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype))
+ return Variant::ARRAY;
- if (is_array) {
- if (r_export_info) {
- MonoReflectionType *elem_reftype;
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return Variant::ARRAY;
+ }
+ } break;
+
+ default: {
+ } break;
+ }
- exc = NULL;
- invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType),
- reftype, &elem_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ // Unknown
+ return Variant::NIL;
+}
- ManagedType elem_type = ManagedType::from_reftype(elem_reftype);
+bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) {
+ switch (p_array_type.type_encoding) {
+ case MONO_TYPE_GENERICINST: {
+ MonoReflectionType *array_reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_array_type.type_class->get_mono_type());
- r_export_info->array.element_type = managed_to_variant_type(elem_type);
- r_export_info->array.element_native_name = NATIVE_GDMONOCLASS_NAME(elem_type.type_class);
- }
+ if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype)) {
+ MonoReflectionType *elem_reftype;
- return Variant::ARRAY;
- }
+ GDMonoUtils::Marshal::array_get_element_type(array_reftype, &elem_reftype);
- if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
- return Variant::DICTIONARY;
+ r_elem_type = ManagedType::from_reftype(elem_reftype);
+ return true;
}
- if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
- return Variant::ARRAY;
+ MonoReflectionType *elem_reftype;
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(array_reftype, &elem_reftype)) {
+ r_elem_type = ManagedType::from_reftype(elem_reftype);
+ return true;
}
} break;
+ default: {
+ } break;
+ }
+
+ return false;
+}
+bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, ManagedType &r_key_type, ManagedType &r_value_type) {
+ switch (p_dictionary_type.type_encoding) {
+ case MONO_TYPE_GENERICINST: {
+ MonoReflectionType *dict_reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_dictionary_type.type_class->get_mono_type());
+
+ if (GDMonoUtils::Marshal::type_is_generic_dictionary(dict_reftype)) {
+ MonoReflectionType *key_reftype;
+ MonoReflectionType *value_reftype;
+
+ GDMonoUtils::Marshal::dictionary_get_key_value_types(dict_reftype, &key_reftype, &value_reftype);
+
+ r_key_type = ManagedType::from_reftype(key_reftype);
+ r_value_type = ManagedType::from_reftype(value_reftype);
+ return true;
+ }
+
+ MonoReflectionType *key_reftype, *value_reftype;
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(dict_reftype, &key_reftype, &value_reftype)) {
+ r_key_type = ManagedType::from_reftype(key_reftype);
+ r_value_type = ManagedType::from_reftype(value_reftype);
+ return true;
+ }
+ } break;
default: {
} break;
}
- // Unknown
- return Variant::NIL;
+ return false;
}
String mono_to_utf8_string(MonoString *p_mono_string) {
@@ -502,10 +541,26 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
}
+ // The order in which we check the following interfaces is very important (dictionaries and generics first)
+
+ MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type());
+
+ MonoReflectionType *key_reftype, *value_reftype;
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(),
+ GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype));
+ }
+
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
}
+ MonoReflectionType *elem_reftype;
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(),
+ GDMonoUtils::Marshal::make_generic_array_type(elem_reftype));
+ }
+
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
}
@@ -603,28 +658,32 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
- MonoException *exc = NULL;
- GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
-
- if (is_dict) {
+ if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class);
}
- exc = NULL;
- GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
-
- if (is_array) {
+ if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
}
+ // The order in which we check the following interfaces is very important (dictionaries and generics first)
+
+ MonoReflectionType *key_reftype, *value_reftype;
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(),
+ GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype));
+ }
+
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
}
+ MonoReflectionType *elem_reftype;
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(),
+ GDMonoUtils::Marshal::make_generic_array_type(elem_reftype));
+ }
+
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
}
@@ -787,66 +846,64 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
return ptr ? Variant(*ptr) : Variant();
}
+ // The order in which we check the following interfaces is very important (dictionaries and generics first)
+
+ MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type());
+
+ MonoReflectionType *key_reftype, *value_reftype;
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
+ return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj);
+ }
+
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
- Dictionary dict;
- MonoException *exc = NULL;
- invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return dict;
+ return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj);
+ }
+
+ MonoReflectionType *elem_reftype;
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
+ return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
}
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
- Array array;
- MonoException *exc = NULL;
- invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return array;
+ return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
}
} break;
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
- MonoException *exc = NULL;
-
- GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
-
- if (is_dict) {
- exc = NULL;
+ if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
+ 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::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
-
- if (is_array) {
- exc = NULL;
+ if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
+ MonoException *exc = NULL;
MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return *unbox<Array *>(ret);
}
+ // The order in which we check the following interfaces is very important (dictionaries and generics first)
+
+ MonoReflectionType *key_reftype, *value_reftype;
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
+ return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj);
+ }
+
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
- Dictionary dict;
- exc = NULL;
- invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return dict;
+ return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj);
+ }
+
+ MonoReflectionType *elem_reftype;
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
+ return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
}
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
- Array array;
- exc = NULL;
- invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return array;
+ return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
}
} break;
}
@@ -1075,4 +1132,5 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) {
return ret;
}
+
} // namespace GDMonoMarshal
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 8d3fd4b349..3fa958ac32 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -57,28 +57,10 @@ T unbox(MonoObject *p_obj) {
#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x)
#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x)
-// FIXME: Made this struct in a hurry. It could be done differently.
-struct ExportInfo {
- struct ArrayInfo {
- Variant::Type element_type;
- String element_native_name;
-
- ArrayInfo() :
- element_type(Variant::NIL) {}
- } array;
- struct DictionaryInfo {
- Variant::Type key_type;
- String key_native_name;
- Variant::Type value_type;
- String value_native_name;
-
- DictionaryInfo() :
- key_type(Variant::NIL),
- value_type(Variant::NIL) {}
- } dictionary;
-};
+Variant::Type managed_to_variant_type(const ManagedType &p_type);
-Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info = NULL);
+bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type);
+bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, ManagedType &r_key_type, ManagedType &r_value_type);
// String
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index 7f11e4671d..f290c6c8ac 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -74,6 +74,10 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
method_info = MethodInfo();
}
+GDMonoClass *GDMonoMethod::get_enclosing_class() const {
+ return GDMono::get_singleton()->get_class(mono_method_get_class(mono_method));
+}
+
bool GDMonoMethod::is_static() {
return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC;
}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index f74cef438d..2fc8628f27 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -57,9 +57,11 @@ class GDMonoMethod : public IMonoClassMember {
MonoMethod *mono_method;
public:
- virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_METHOD; }
+ virtual GDMonoClass *get_enclosing_class() const GD_FINAL;
- virtual StringName get_name() GD_FINAL { return name; }
+ virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_METHOD; }
+
+ virtual StringName get_name() const GD_FINAL { return name; }
virtual bool is_static() GD_FINAL;
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index 2700c460b0..d6efa60412 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -47,9 +47,11 @@ class GDMonoProperty : public IMonoClassMember {
MonoCustomAttrInfo *attributes;
public:
- virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_PROPERTY; }
+ virtual GDMonoClass *get_enclosing_class() const GD_FINAL { return owner; }
- virtual StringName get_name() GD_FINAL { return name; }
+ virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_PROPERTY; }
+
+ virtual StringName get_name() const GD_FINAL { return name; }
virtual bool is_static() GD_FINAL;
virtual Visibility get_visibility() GD_FINAL;
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index bcf5712d16..5236e43c90 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -109,7 +109,7 @@ void MonoCache::clear_members() {
class_NodePath = NULL;
class_RID = NULL;
class_GodotObject = NULL;
- class_GodotReference = NULL;
+ class_GodotResource = NULL;
class_Node = NULL;
class_Control = NULL;
class_Spatial = NULL;
@@ -151,12 +151,25 @@ void MonoCache::clear_members() {
methodthunk_SignalAwaiter_FailureCallback = NULL;
methodthunk_GodotTaskScheduler_Activate = NULL;
+ // Start of MarshalUtils methods
+
methodthunk_MarshalUtils_TypeIsGenericArray = NULL;
methodthunk_MarshalUtils_TypeIsGenericDictionary = NULL;
+
methodthunk_MarshalUtils_ArrayGetElementType = NULL;
methodthunk_MarshalUtils_DictionaryGetKeyValueTypes = NULL;
+
+ methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType = NULL;
+ methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType = NULL;
+
+ methodthunk_MarshalUtils_MakeGenericArrayType = NULL;
+ methodthunk_MarshalUtils_MakeGenericDictionaryType = NULL;
+
methodthunk_MarshalUtils_EnumerableToArray = NULL;
methodthunk_MarshalUtils_IDictionaryToDictionary = NULL;
+ methodthunk_MarshalUtils_GenericIDictionaryToDictionary = NULL;
+
+ // End of MarshalUtils methods
task_scheduler_handle = Ref<MonoGCHandle>();
}
@@ -217,7 +230,7 @@ void update_godot_api_cache() {
CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID));
CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
- CACHE_CLASS_AND_CHECK(GodotReference, GODOT_API_CLASS(Reference));
+ CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource));
CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
@@ -258,12 +271,28 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0));
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0));
+ // Start of MarshalUtils methods
+
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, (TypeIsGenericArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericArray", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, (TypeIsGenericDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericDictionary", 1));
+
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3));
+
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3));
+
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, (GenericIEnumerableIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, (GenericIDictionaryIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 3));
+
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, (MakeGenericArrayType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericArrayType", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, (MakeGenericDictionaryType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericDictionaryType", 2));
+
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, (EnumerableToArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("EnumerableToArray", 2));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, (IDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IDictionaryToDictionary", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryToDictionary, (GenericIDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryToDictionary", 2));
+
+ // End of MarshalUtils methods
#ifdef DEBUG_ENABLED
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4));
@@ -727,4 +756,99 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, r_exc);
}
+namespace Marshal {
+
+MonoBoolean type_is_generic_array(MonoReflectionType *p_reftype) {
+ TypeIsGenericArray thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoException *exc = NULL;
+ MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return res;
+}
+
+MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype) {
+ TypeIsGenericDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoException *exc = NULL;
+ MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return res;
+}
+
+void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
+ ArrayGetElementType thunk = CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType);
+ MonoException *exc = NULL;
+ invoke_method_thunk(thunk, p_array_reftype, r_elem_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+}
+
+void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
+ DictionaryGetKeyValueTypes thunk = CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes);
+ MonoException *exc = NULL;
+ invoke_method_thunk(thunk, p_dict_reftype, r_key_reftype, r_value_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+}
+
+MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) {
+ GenericIEnumerableIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType);
+ MonoException *exc = NULL;
+ MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_elem_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return res;
+}
+
+MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
+ GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType);
+ MonoException *exc = NULL;
+ MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_key_reftype, r_value_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return res;
+}
+
+Array enumerable_to_array(MonoObject *p_enumerable) {
+ Array result;
+ EnumerableToArray thunk = CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray);
+ MonoException *exc = NULL;
+ invoke_method_thunk(thunk, p_enumerable, &result, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return result;
+}
+
+Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) {
+ Dictionary result;
+ IDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary);
+ MonoException *exc = NULL;
+ invoke_method_thunk(thunk, p_idictionary, &result, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return result;
+}
+
+Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) {
+ Dictionary result;
+ GenericIDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary);
+ MonoException *exc = NULL;
+ invoke_method_thunk(thunk, p_generic_idictionary, &result, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return result;
+}
+
+GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) {
+ MakeGenericArrayType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType);
+ MonoException *exc = NULL;
+ MonoReflectionType *reftype = invoke_method_thunk(thunk, p_elem_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
+}
+
+GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
+ MakeGenericDictionaryType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType);
+ MonoException *exc = NULL;
+ MonoReflectionType *reftype = invoke_method_thunk(thunk, p_key_reftype, p_value_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
+}
+
+} // namespace Marshal
+
+// namespace Marshal
+
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 87610e286c..081a8a9813 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -60,10 +60,41 @@ typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, Mo
typedef MonoBoolean (*TypeIsGenericArray)(MonoReflectionType *, MonoException **);
typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoException **);
-typedef MonoBoolean (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **);
-typedef MonoBoolean (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **);
+
+typedef void (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **);
+typedef void (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **);
+
+typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType)(MonoReflectionType *, MonoReflectionType **, MonoException **);
+typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **);
+
+typedef MonoReflectionType *(*MakeGenericArrayType)(MonoReflectionType *, MonoException **);
+typedef MonoReflectionType *(*MakeGenericDictionaryType)(MonoReflectionType *, MonoReflectionType *, MonoException **);
+
typedef void (*EnumerableToArray)(MonoObject *, Array *, MonoException **);
typedef void (*IDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **);
+typedef void (*GenericIDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **);
+
+namespace Marshal {
+
+MonoBoolean type_is_generic_array(MonoReflectionType *p_reftype);
+MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype);
+
+void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype);
+void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);
+
+MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype);
+MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);
+
+GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype);
+GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
+
+Array enumerable_to_array(MonoObject *p_enumerable);
+Dictionary idictionary_to_dictionary(MonoObject *p_idictionary);
+Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary);
+
+} // namespace Marshal
+
+// End of MarshalUtils methods
struct MonoCache {
@@ -114,7 +145,7 @@ struct MonoCache {
GDMonoClass *class_NodePath;
GDMonoClass *class_RID;
GDMonoClass *class_GodotObject;
- GDMonoClass *class_GodotReference;
+ GDMonoClass *class_GodotResource;
GDMonoClass *class_Node;
GDMonoClass *class_Control;
GDMonoClass *class_Spatial;
@@ -156,12 +187,25 @@ struct MonoCache {
SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
+ // Start of MarshalUtils methods
+
TypeIsGenericArray methodthunk_MarshalUtils_TypeIsGenericArray;
TypeIsGenericDictionary methodthunk_MarshalUtils_TypeIsGenericDictionary;
+
ArrayGetElementType methodthunk_MarshalUtils_ArrayGetElementType;
DictionaryGetKeyValueTypes methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
+
+ GenericIEnumerableIsAssignableFromType methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType;
+ GenericIDictionaryIsAssignableFromType methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType;
+
+ MakeGenericArrayType methodthunk_MarshalUtils_MakeGenericArrayType;
+ MakeGenericDictionaryType methodthunk_MarshalUtils_MakeGenericDictionaryType;
+
EnumerableToArray methodthunk_MarshalUtils_EnumerableToArray;
IDictionaryToDictionary methodthunk_MarshalUtils_IDictionaryToDictionary;
+ GenericIDictionaryToDictionary methodthunk_MarshalUtils_GenericIDictionaryToDictionary;
+
+ // End of MarshalUtils methods
Ref<MonoGCHandle> task_scheduler_handle;
diff --git a/modules/mono/mono_gd/i_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h
index 553d9edc72..f4de4e3230 100644
--- a/modules/mono/mono_gd/i_mono_class_member.h
+++ b/modules/mono/mono_gd/i_mono_class_member.h
@@ -53,9 +53,11 @@ public:
virtual ~IMonoClassMember() {}
- virtual MemberType get_member_type() = 0;
+ virtual GDMonoClass *get_enclosing_class() const = 0;
- virtual StringName get_name() = 0;
+ virtual MemberType get_member_type() const = 0;
+
+ virtual StringName get_name() const = 0;
virtual bool is_static() = 0;