summaryrefslogtreecommitdiff
path: root/modules/mono
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono')
-rw-r--r--modules/mono/csharp_script.cpp164
-rw-r--r--modules/mono/csharp_script.h5
-rw-r--r--modules/mono/editor/bindings_generator.cpp16
-rw-r--r--modules/mono/editor/bindings_generator.h4
-rw-r--r--modules/mono/glue/Managed/Files/DynamicObject.cs2
-rw-r--r--modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs4
-rw-r--r--modules/mono/glue/Managed/Files/MarshalUtils.cs154
-rw-r--r--modules/mono/glue/Managed/IgnoredFiles/Node.cs5
-rw-r--r--modules/mono/glue/collections_glue.cpp4
-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.cpp234
-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.cpp165
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h58
-rw-r--r--modules/mono/mono_gd/i_mono_class_member.h6
-rw-r--r--modules/mono/utils/string_utils.cpp4
20 files changed, 713 insertions, 210 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index ef09e76d11..72199281ff 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1855,6 +1855,34 @@ void CSharpInstance::_call_notification(int p_notification) {
}
}
+String CSharpInstance::to_string(bool *r_valid) {
+ MonoObject *mono_object = get_mono_object();
+
+ if (mono_object == NULL) {
+ if (r_valid)
+ *r_valid = false;
+ return String();
+ }
+
+ MonoException *exc = NULL;
+ MonoString *result = GDMonoUtils::object_to_string(mono_object, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ if (r_valid)
+ *r_valid = false;
+ return String();
+ }
+
+ if (result == NULL) {
+ if (r_valid)
+ *r_valid = false;
+ return String();
+ }
+
+ return GDMonoMarshal::mono_string_to_godot(result);
+}
+
Ref<Script> CSharpInstance::get_script() const {
return script;
@@ -2020,7 +2048,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 +2069,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 +2196,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 +2221,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 +2247,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;
+ }
- Vector<MonoClassField *> fields = type.type_class->get_enum_fields();
+ int hint_res = _try_get_member_export_hint(p_member, type, variant_type, /* allow_generics: */ true, hint, hint_string);
- MonoType *enum_basetype = mono_class_enum_basetype(type.type_class->get_mono_ptr());
+ 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 = p_type.type_class->get_enum_fields();
+
+ MonoType *enum_basetype = mono_class_enum_basetype(p_type.type_class->get_mono_ptr());
String name_only_hint_string;
@@ -2236,12 +2291,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 +2306,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..e735e0f741 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);
@@ -260,6 +261,8 @@ public:
virtual void notification(int p_notification);
void _call_notification(int p_notification);
+ virtual String to_string(bool *r_valid);
+
virtual Ref<Script> get_script() const;
virtual ScriptLanguage *get_language();
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index a408716641..cd7774e7a1 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -2300,9 +2300,14 @@ void BindingsGenerator::_populate_object_type_interfaces() {
if (method_info.name.empty())
continue;
+ String cname = method_info.name;
+
+ if (blacklisted_methods.find(itype.cname) && blacklisted_methods[itype.cname].find(cname))
+ continue;
+
MethodInterface imethod;
imethod.name = method_info.name;
- imethod.cname = imethod.name;
+ imethod.cname = cname;
if (method_info.flags & METHOD_FLAG_VIRTUAL)
imethod.is_virtual = true;
@@ -2975,6 +2980,13 @@ void BindingsGenerator::_populate_global_constants() {
}
}
+void BindingsGenerator::_initialize_blacklisted_methods() {
+
+ blacklisted_methods["Object"].push_back("to_string"); // there is already ToString
+ blacklisted_methods["Object"].push_back("_to_string"); // override ToString instead
+ blacklisted_methods["Object"].push_back("_init"); // never called in C# (TODO: implement it)
+}
+
void BindingsGenerator::_log(const char *p_format, ...) {
if (log_print_enabled) {
@@ -2992,6 +3004,8 @@ void BindingsGenerator::_initialize() {
enum_types.clear();
+ _initialize_blacklisted_methods();
+
_populate_object_type_interfaces();
_populate_builtin_type_interfaces();
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index bdba28c267..ffc73a7e3e 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -491,6 +491,10 @@ class BindingsGenerator {
List<InternalCall> core_custom_icalls;
List<InternalCall> editor_custom_icalls;
+ Map<StringName, List<StringName> > blacklisted_methods;
+
+ void _initialize_blacklisted_methods();
+
struct NameCache {
StringName type_void;
StringName type_Array;
diff --git a/modules/mono/glue/Managed/Files/DynamicObject.cs b/modules/mono/glue/Managed/Files/DynamicObject.cs
index 9860feafdd..a0f105d55e 100644
--- a/modules/mono/glue/Managed/Files/DynamicObject.cs
+++ b/modules/mono/glue/Managed/Files/DynamicObject.cs
@@ -202,7 +202,7 @@ namespace Godot
//public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes);
//public override bool TryDeleteMember(DeleteMemberBinder binder);
- // Invokation on the object itself, e.g.: obj(param)
+ // Invocation on the object itself, e.g.: obj(param)
//public override bool TryInvoke(InvokeBinder binder, object[] args, out object result);
// No unnary operations to handle
diff --git a/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs
index 366d89b1c2..5023725f17 100644
--- a/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs
+++ b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs
@@ -24,12 +24,12 @@ namespace Godot
public T GetOwner<T>() where T : class
{
- return (T)(object)GetOwner();
+ return (T)(object)Owner;
}
public T GetOwnerOrNull<T>() where T : class
{
- return GetOwner() as T;
+ return Owner as T;
}
public T GetParent<T>() where T : class
diff --git a/modules/mono/glue/Managed/Files/MarshalUtils.cs b/modules/mono/glue/Managed/Files/MarshalUtils.cs
index 7e72b0edb5..a1d63a62ef 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,151 @@ 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{TKey, TValue}"/>; 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)
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ return true;
+
+ foreach (var interfaceType in type.GetInterfaces())
+ {
+ if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ return true;
+ }
+
+ Type baseType = type.BaseType;
+
+ if (baseType == null)
+ return false;
+
+ return GenericIEnumerableIsAssignableFromType(baseType);
+ }
+
+ static bool GenericIDictionaryIsAssignableFromType(Type type)
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
+ return true;
+
+ foreach (var interfaceType in type.GetInterfaces())
+ {
+ if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
+ return true;
+ }
+
+ Type baseType = type.BaseType;
+
+ if (baseType == null)
+ return false;
+
+ return GenericIDictionaryIsAssignableFromType(baseType);
+ }
+
+ 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 +187,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/glue/Managed/IgnoredFiles/Node.cs b/modules/mono/glue/Managed/IgnoredFiles/Node.cs
index 99ba0f827a..cff61b1e0b 100644
--- a/modules/mono/glue/Managed/IgnoredFiles/Node.cs
+++ b/modules/mono/glue/Managed/IgnoredFiles/Node.cs
@@ -15,9 +15,10 @@ namespace Godot
throw new NotImplementedException();
}
- public Node GetOwner()
+ public Node Owner
{
- throw new NotImplementedException();
+ get => throw new NotImplementedException();
+ set => throw new NotImplementedException();
}
public Node GetParent()
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 4aef5684fd..47239f1260 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -162,7 +162,7 @@ MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
#ifdef DEBUG_ENABLED
CRASH_COND(!exc);
#endif
- GDMonoUtils::runtime_object_init(exc);
+ GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
GDMonoUtils::set_pending_exception((MonoException *)exc);
return NULL;
}
@@ -176,7 +176,7 @@ MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject
#ifdef DEBUG_ENABLED
CRASH_COND(!exc);
#endif
- GDMonoUtils::runtime_object_init(exc);
+ GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
GDMonoUtils::set_pending_exception((MonoException *)exc);
return NULL;
}
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..c462b8f71d 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,22 @@ 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());
+
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) {
+ return Variant::DICTIONARY;
+ }
+
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
return Variant::DICTIONARY;
}
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) {
+ return Variant::ARRAY;
+ }
+
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
return Variant::ARRAY;
}
@@ -169,71 +181,94 @@ 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);
- }
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(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);
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(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 +537,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 +654,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 +842,60 @@ 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());
+
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(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);
+ }
+
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(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)
+
+ if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(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);
+ }
+
+ if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(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 +1124,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..413c8cba85 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,27 @@ 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_GenericIEnumerableIsAssignableFromType_with_info = NULL;
+ methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info = 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 +232,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 +273,30 @@ 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", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, (GenericIDictionaryIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, (GenericIEnumerableIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, (GenericIEnumerableIsAssignableFromType_with_info)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));
@@ -271,7 +304,7 @@ void update_godot_api_cache() {
// TODO Move to CSharpLanguage::init() and do handle disposal
MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
- GDMonoUtils::runtime_object_init(task_scheduler);
+ GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler));
mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
mono_cache.godot_api_cache_updated = true;
@@ -372,11 +405,10 @@ MonoThread *get_current_thread() {
return mono_thread_current();
}
-void runtime_object_init(MonoObject *p_this_obj) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- // FIXME: Do not use mono_runtime_object_init, it aborts if an exception is thrown
- mono_runtime_object_init(p_this_obj);
- GD_MONO_END_RUNTIME_INVOKE;
+void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) {
+ GDMonoMethod *ctor = p_class->get_method(".ctor", 0);
+ ERR_FAIL_NULL(ctor);
+ ctor->invoke_raw(p_this_obj, NULL, r_exc);
}
GDMonoClass *get_object_class(MonoObject *p_object) {
@@ -438,7 +470,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
// Construct
- GDMonoUtils::runtime_object_init(mono_object);
+ GDMonoUtils::runtime_object_init(mono_object, p_class);
return mono_object;
}
@@ -448,7 +480,7 @@ MonoObject *create_managed_from(const NodePath &p_from) {
ERR_FAIL_NULL_V(mono_object, NULL);
// Construct
- GDMonoUtils::runtime_object_init(mono_object);
+ GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(NodePath));
CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
@@ -460,7 +492,7 @@ MonoObject *create_managed_from(const RID &p_from) {
ERR_FAIL_NULL_V(mono_object, NULL);
// Construct
- GDMonoUtils::runtime_object_init(mono_object);
+ GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(RID));
CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
@@ -727,4 +759,115 @@ 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) {
+ GenericIEnumerableIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType);
+ MonoException *exc = NULL;
+ MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return res;
+}
+
+MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) {
+ GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType);
+ MonoException *exc = NULL;
+ MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return res;
+}
+
+MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) {
+ GenericIEnumerableIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info);
+ 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_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info);
+ 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..ee239be959 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -60,10 +60,45 @@ 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 *, MonoException **);
+typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType)(MonoReflectionType *, MonoException **);
+typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType_with_info)(MonoReflectionType *, MonoReflectionType **, MonoException **);
+typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType_with_info)(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);
+MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_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 +149,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 +191,27 @@ 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;
+ GenericIEnumerableIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info;
+ GenericIDictionaryIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info;
+
+ 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;
@@ -205,7 +255,7 @@ _FORCE_INLINE_ bool is_main_thread() {
return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
}
-void runtime_object_init(MonoObject *p_this_obj);
+void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = NULL);
GDMonoClass *get_object_class(MonoObject *p_object);
GDMonoClass *type_get_proxy_class(const StringName &p_type);
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;
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index 1fdddd3925..877122985d 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -66,7 +66,7 @@ int sfind(const String &p_text, int p_from) {
break;
case 1: {
CharType c = src[read_pos];
- found = src[read_pos] == 's' || (c >= '0' || c <= '4');
+ found = src[read_pos] == 's' || (c >= '0' && c <= '4');
break;
}
default:
@@ -210,7 +210,7 @@ String str_format(const char *p_format, ...) {
#endif
#endif
-#if defined(MINGW_ENABLED) || defined(_MSC_VER)
+#if defined(MINGW_ENABLED) || defined(_MSC_VER) && _MSC_VER < 1900
#define vsnprintf(m_buffer, m_count, m_format, m_argptr) vsnprintf_s(m_buffer, m_count, _TRUNCATE, m_format, m_argptr)
#endif