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