diff options
Diffstat (limited to 'modules/mono')
-rw-r--r-- | modules/mono/csharp_script.cpp | 195 | ||||
-rw-r--r-- | modules/mono/csharp_script.h | 17 | ||||
-rw-r--r-- | modules/mono/editor/bindings_generator.cpp | 12 | ||||
-rw-r--r-- | modules/mono/editor/bindings_generator.h | 2 | ||||
-rw-r--r-- | modules/mono/editor/code_completion.cpp | 2 | ||||
-rw-r--r-- | modules/mono/editor/editor_internal_calls.cpp | 2 | ||||
-rw-r--r-- | modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs | 19 | ||||
-rw-r--r-- | modules/mono/glue/base_object_glue.cpp | 10 | ||||
-rw-r--r-- | modules/mono/glue/string_glue.cpp | 6 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono.cpp | 54 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono.h | 16 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono_internals.cpp | 13 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono_marshal.cpp | 8 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono_utils.cpp | 19 | ||||
-rw-r--r-- | modules/mono/register_types.cpp | 8 |
15 files changed, 213 insertions, 170 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 520262c0eb..1f7f1390ea 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -82,6 +82,12 @@ static bool _create_project_solution_if_needed() { CSharpLanguage *CSharpLanguage::singleton = nullptr; +GDNativeInstanceBindingCallbacks CSharpLanguage::_instance_binding_callbacks = { + &_instance_binding_create_callback, + &_instance_binding_free_callback, + &_instance_binding_reference_callback +}; + String CSharpLanguage::get_name() const { return "C#"; } @@ -542,10 +548,10 @@ String CSharpLanguage::make_function(const String &, const String &, const Packe String CSharpLanguage::_get_indentation() const { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", 0); + bool use_space_indentation = EDITOR_DEF("text_editor/behavior/indent/type", 0); if (use_space_indentation) { - int indent_size = EDITOR_DEF("text_editor/indent/size", 4); + int indent_size = EDITOR_DEF("text_editor/behavior/indent/size", 4); String space_indent = ""; for (int i = 0; i < indent_size; i++) { @@ -1444,46 +1450,46 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b return true; } -void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) { - MutexLock lock(language_bind_mutex); +Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) { + return script_bindings.insert(p_object, p_script_binding); +} + +void *CSharpLanguage::_instance_binding_create_callback(void *, void *p_instance) { + CSharpLanguage *csharp_lang = CSharpLanguage::get_singleton(); - Map<Object *, CSharpScriptBinding>::Element *match = script_bindings.find(p_object); + MutexLock lock(csharp_lang->language_bind_mutex); + + Map<Object *, CSharpScriptBinding>::Element *match = csharp_lang->script_bindings.find((Object *)p_instance); if (match) { return (void *)match; } CSharpScriptBinding script_binding; - if (!setup_csharp_script_binding(script_binding, p_object)) { - return nullptr; - } - - return (void *)insert_script_binding(p_object, script_binding); + return (void *)csharp_lang->insert_script_binding((Object *)p_instance, script_binding); } -Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) { - return script_bindings.insert(p_object, p_script_binding); -} +void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_binding) { + CSharpLanguage *csharp_lang = CSharpLanguage::get_singleton(); -void CSharpLanguage::free_instance_binding_data(void *p_data) { if (GDMono::get_singleton() == nullptr) { #ifdef DEBUG_ENABLED - CRASH_COND(!script_bindings.is_empty()); + CRASH_COND(!csharp_lang->script_bindings.is_empty()); #endif // Mono runtime finalized, all the gchandle bindings were already released return; } - if (finalizing) { + if (csharp_lang->finalizing) { return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there } GD_MONO_ASSERT_THREAD_ATTACHED; { - MutexLock lock(language_bind_mutex); + MutexLock lock(csharp_lang->language_bind_mutex); - Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data; + Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_binding; CSharpScriptBinding &script_binding = data->value(); @@ -1497,92 +1503,110 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) { script_binding.gchandle.release(); } - script_bindings.erase(data); + csharp_lang->script_bindings.erase(data); } } -void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { -#if 0 - RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object); +GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference) { + CRASH_COND(!p_binding); + + CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)p_binding)->get(); + + RefCounted *rc_owner = Object::cast_to<RefCounted>(script_binding.owner); #ifdef DEBUG_ENABLED CRASH_COND(!rc_owner); - CRASH_COND(!p_object->has_script_instance_binding(get_language_index())); #endif - void *data = p_object->get_script_instance_binding(get_language_index()); - CRASH_COND(!data); - - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); MonoGCHandleData &gchandle = script_binding.gchandle; + int refcount = rc_owner->reference_get_count(); + if (!script_binding.inited) { - return; + return refcount == 0; } - if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 - GD_MONO_SCOPE_THREAD_ATTACH; + if (p_reference) { + // Refcount incremented + if (refcount > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + GD_MONO_SCOPE_THREAD_ATTACH; - // The reference count was increased after the managed side was the only one referencing our owner. - // This means the owner is being referenced again by the unmanaged side, - // so the owner must hold the managed side alive again to avoid it from being GCed. + // The reference count was increased after the managed side was the only one referencing our owner. + // This means the owner is being referenced again by the unmanaged side, + // so the owner must hold the managed side alive again to avoid it from being GCed. + + MonoObject *target = gchandle.get_target(); + if (!target) { + return false; // Called after the managed side was collected, so nothing to do here + } - MonoObject *target = gchandle.get_target(); - if (!target) { - return; // Called after the managed side was collected, so nothing to do here + // Release the current weak handle and replace it with a strong handle. + MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(target); + gchandle.release(); + gchandle = strong_gchandle; } - // Release the current weak handle and replace it with a strong handle. - MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(target); - gchandle.release(); - gchandle = strong_gchandle; - } -#endif -} + return false; + } else { + // Refcount decremented + if (refcount == 1 && !gchandle.is_released() && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + GD_MONO_SCOPE_THREAD_ATTACH; -bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { -#if 0 - RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object); + // If owner owner is no longer referenced by the unmanaged side, + // the managed instance takes responsibility of deleting the owner when GCed. -#ifdef DEBUG_ENABLED - CRASH_COND(!rc_owner); - CRASH_COND(!p_object->has_script_instance_binding(get_language_index())); -#endif + MonoObject *target = gchandle.get_target(); + if (!target) { + return refcount == 0; // Called after the managed side was collected, so nothing to do here + } - void *data = p_object->get_script_instance_binding(get_language_index()); - CRASH_COND(!data); + // Release the current strong handle and replace it with a weak handle. + MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(target); + gchandle.release(); + gchandle = weak_gchandle; - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); - MonoGCHandleData &gchandle = script_binding.gchandle; - - int refcount = rc_owner->reference_get_count(); + return false; + } - if (!script_binding.inited) { return refcount == 0; } +} - if (refcount == 1 && !gchandle.is_released() && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 - GD_MONO_SCOPE_THREAD_ATTACH; +void *CSharpLanguage::get_instance_binding(Object *p_object) { + void *binding = p_object->get_instance_binding(get_singleton(), &_instance_binding_callbacks); - // If owner owner is no longer referenced by the unmanaged side, - // the managed instance takes responsibility of deleting the owner when GCed. + // Initially this was in `_instance_binding_create_callback`. However, after the new instance + // binding re-write it was resulting in a deadlock in `_instance_binding_reference`, as + // `setup_csharp_script_binding` may call `reference()`. It was moved here outside to fix that. - MonoObject *target = gchandle.get_target(); - if (!target) { - return refcount == 0; // Called after the managed side was collected, so nothing to do here - } + if (binding) { + CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)binding)->value(); - // Release the current strong handle and replace it with a weak handle. - MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(target); - gchandle.release(); - gchandle = weak_gchandle; + if (!script_binding.inited) { + MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex()); - return false; + if (!script_binding.inited) { // Another thread may have set it up + CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, p_object); + } + } } - return refcount == 0; + return binding; +} + +void *CSharpLanguage::get_existing_instance_binding(Object *p_object) { +#ifdef DEBUG_ENABLED + CRASH_COND(p_object->has_instance_binding(p_object)); #endif - return false; + return p_object->get_instance_binding(get_singleton(), &_instance_binding_callbacks); +} + +void CSharpLanguage::set_instance_binding(Object *p_object, void *p_binding) { + p_object->set_instance_binding(get_singleton(), p_binding, &_instance_binding_callbacks); +} + +bool CSharpLanguage::has_instance_binding(Object *p_object) { + return p_object->has_instance_binding(get_singleton()); } CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) { @@ -2260,29 +2284,16 @@ CSharpInstance::~CSharpInstance() { // Otherwise, the unsafe reference debug checks will incorrectly detect a bug. bool die = _unreference_owner_unsafe(); CRASH_COND(die); // `owner_keep_alive` holds a reference, so it can't die -#if 0 - void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); - + void *data = CSharpLanguage::get_instance_binding(owner); CRASH_COND(data == nullptr); - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); - - if (!script_binding.inited) { - MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex()); - - if (!script_binding.inited) { // Other thread may have set it up - // Already had a binding that needs to be setup - CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, owner); - CRASH_COND(!script_binding.inited); - } - } + CRASH_COND(!script_binding.inited); #ifdef DEBUG_ENABLED // The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope CRASH_COND(rc_owner->reference_get_count() <= 1); #endif -#endif } if (script.is_valid() && owner) { @@ -3100,10 +3111,10 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg // Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance. ref = Ref<RefCounted>(static_cast<RefCounted *>(p_owner)); } -#if 0 + // If the object had a script instance binding, dispose it before adding the CSharpInstance - if (p_owner->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())) { - void *data = p_owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + if (CSharpLanguage::has_instance_binding(p_owner)) { + void *data = CSharpLanguage::get_existing_instance_binding(p_owner); CRASH_COND(data == nullptr); CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); @@ -3122,7 +3133,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg script_binding.inited = false; } } -#endif + CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(this))); instance->base_ref_counted = p_is_ref_counted; instance->owner = p_owner; @@ -3192,7 +3203,7 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error); if (!instance) { if (ref.is_null()) { - memdelete(owner); //no owner, sorry + memdelete(owner); // no owner, sorry } return Variant(); } diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index da6b60aee2..4552f376d0 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -401,7 +401,18 @@ class CSharpLanguage : public ScriptLanguage { static void _editor_init_callback(); #endif + static void *_instance_binding_create_callback(void *p_token, void *p_instance); + static void _instance_binding_free_callback(void *p_token, void *p_instance, void *p_binding); + static GDNativeBool _instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference); + + static GDNativeInstanceBindingCallbacks _instance_binding_callbacks; + public: + static void *get_instance_binding(Object *p_object); + static void *get_existing_instance_binding(Object *p_object); + static void set_instance_binding(Object *p_object, void *p_binding); + static bool has_instance_binding(Object *p_object); + StringNameCache string_names; const Mutex &get_language_bind_mutex() { return language_bind_mutex; } @@ -507,12 +518,6 @@ public: void thread_enter() override; void thread_exit() override; - // Don't use these. I'm watching you - void *alloc_instance_binding_data(Object *p_object) override; - void free_instance_binding_data(void *p_data) override; - void refcount_incremented_instance_binding(Object *p_object) override; - bool refcount_decremented_instance_binding(Object *p_object) override; - Map<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding); bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 632f7d61cc..7fdef8ff45 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -3130,8 +3130,18 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::CALLABLE: + ERR_FAIL_COND_V_MSG(r_iarg.type.cname != name_cache.type_Callable, false, + "Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value of type '" + String(name_cache.type_Callable) + "'."); + ERR_FAIL_COND_V_MSG(!p_val.is_zero(), false, + "Parameter of type '" + String(r_iarg.type.cname) + "' can only have null/zero as the default value."); + r_iarg.default_argument = "default"; + break; case Variant::SIGNAL: - CRASH_NOW_MSG("Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value."); + ERR_FAIL_COND_V_MSG(r_iarg.type.cname != name_cache.type_Signal, false, + "Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value of type '" + String(name_cache.type_Signal) + "'."); + ERR_FAIL_COND_V_MSG(!p_val.is_zero(), false, + "Parameter of type '" + String(r_iarg.type.cname) + "' can only have null/zero as the default value."); + r_iarg.default_argument = "default"; break; default: CRASH_NOW_MSG("Unexpected Variant type: " + itos(p_val.get_type())); diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index a649181b20..8a85a1acbd 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -536,6 +536,8 @@ class BindingsGenerator { StringName type_Object = StaticCString::create("Object"); StringName type_RefCounted = StaticCString::create("RefCounted"); StringName type_RID = StaticCString::create("RID"); + StringName type_Callable = StaticCString::create("Callable"); + StringName type_Signal = StaticCString::create("Signal"); StringName type_String = StaticCString::create("String"); StringName type_StringName = StaticCString::create("StringName"); StringName type_NodePath = StaticCString::create("NodePath"); diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index b7b36a92d8..d911f6461c 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/modules/mono/editor/code_completion.cpp @@ -121,7 +121,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr case CompletionKind::NODE_PATHS: { { // AutoLoads - Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) { const ProjectSettings::AutoloadInfo &info = E.value; diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index 8164f459ca..6692a6efec 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -241,7 +241,7 @@ MonoBoolean godot_icall_Internal_IsAssembliesReloadingNeeded() { void godot_icall_Internal_ReloadAssemblies(MonoBoolean p_soft_reload) { #ifdef GD_MONO_HOT_RELOAD - _GodotSharp::get_singleton()->call_deferred(SNAME("_reload_assemblies"), (bool)p_soft_reload); + mono_bind::GodotSharp::get_singleton()->call_deferred(SNAME("_reload_assemblies"), (bool)p_soft_reload); #endif } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index d9665cbf2b..e619ad74e9 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -64,7 +64,7 @@ namespace Godot /// <summary> /// If the string is a path to a file, return the path to the file without the extension. /// </summary> - public static string BaseName(this string instance) + public static string GetBaseName(this string instance) { int index = instance.LastIndexOf('.'); @@ -339,7 +339,7 @@ namespace Godot /// <summary> /// If the string is a path to a file, return the extension. /// </summary> - public static string Extension(this string instance) + public static string GetExtension(this string instance) { int pos = instance.FindLast("."); @@ -575,7 +575,7 @@ namespace Godot /// <summary> /// If the string is a path to a file or directory, return <see langword="true"/> if the path is absolute. /// </summary> - public static bool IsAbsPath(this string instance) + public static bool IsAbsolutePath(this string instance) { if (string.IsNullOrEmpty(instance)) return false; @@ -590,7 +590,7 @@ namespace Godot /// </summary> public static bool IsRelPath(this string instance) { - return !IsAbsPath(instance); + return !IsAbsolutePath(instance); } /// <summary> @@ -1103,6 +1103,17 @@ namespace Godot } /// <summary> + /// Returns a simplified canonical path. + /// </summary> + public static string SimplifyPath(this string instance) + { + return godot_icall_String_simplify_path(instance); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static string godot_icall_String_simplify_path(string str); + + /// <summary> /// Split the string by a divisor string, return an array of the substrings. /// Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". /// </summary> diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index a99dff8432..6c5503a3bd 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -64,8 +64,8 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { return; } } -#if 0 - void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + + void *data = CSharpLanguage::get_existing_instance_binding(p_ptr); if (data) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); @@ -76,7 +76,6 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { } } } -#endif } void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { @@ -85,7 +84,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole // This is only called with RefCounted derived classes CRASH_COND(!Object::cast_to<RefCounted>(p_ptr)); #endif -#if 0 + RefCounted *rc = static_cast<RefCounted *>(p_ptr); if (rc->get_script_instance()) { @@ -113,7 +112,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole if (rc->unreference()) { memdelete(rc); } else { - void *data = rc->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + void *data = CSharpLanguage::get_existing_instance_binding(rc); if (data) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); @@ -125,7 +124,6 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole } } } -#endif } void godot_icall_Object_ConnectEventSignals(Object *p_ptr) { diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp index 18a9221f89..bb80a836ad 100644 --- a/modules/mono/glue/string_glue.cpp +++ b/modules/mono/glue/string_glue.cpp @@ -67,6 +67,11 @@ MonoString *godot_icall_String_sha256_text(MonoString *p_str) { return GDMonoMarshal::mono_string_from_godot(ret); } +MonoString *godot_icall_String_simplify_path(MonoString *p_str) { + String ret = GDMonoMarshal::mono_string_to_godot(p_str).simplify_path(); + return GDMonoMarshal::mono_string_from_godot(ret); +} + void godot_register_string_icalls() { GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", godot_icall_String_md5_buffer); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", godot_icall_String_md5_text); @@ -74,6 +79,7 @@ void godot_register_string_icalls() { GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", godot_icall_String_rfindn); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", godot_icall_String_sha256_buffer); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text); + GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_simplify_path", godot_icall_String_simplify_path); } #endif // MONO_GLUE_ENABLED diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 299344bb93..1b1349a3a3 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -73,7 +73,7 @@ #endif // TODO: -// This has turn into a gigantic mess. There's too much going on here. Too much #ifdef as well. +// This has turned into a gigantic mess. There's too much going on here. Too much #ifdef as well. // It's just painful to read... It needs to be re-structured. Please, clean this up, future me. GDMono *GDMono::singleton = nullptr; @@ -1335,23 +1335,25 @@ GDMono::~GDMono() { singleton = nullptr; } -_GodotSharp *_GodotSharp::singleton = nullptr; +namespace mono_bind { -void _GodotSharp::attach_thread() { +GodotSharp *GodotSharp::singleton = nullptr; + +void GodotSharp::attach_thread() { GDMonoUtils::attach_current_thread(); } -void _GodotSharp::detach_thread() { +void GodotSharp::detach_thread() { GDMonoUtils::detach_current_thread(); } -int32_t _GodotSharp::get_domain_id() { +int32_t GodotSharp::get_domain_id() { MonoDomain *domain = mono_domain_get(); ERR_FAIL_NULL_V(domain, -1); return mono_domain_get_id(domain); } -int32_t _GodotSharp::get_scripts_domain_id() { +int32_t GodotSharp::get_scripts_domain_id() { ERR_FAIL_NULL_V_MSG(GDMono::get_singleton(), -1, "The Mono runtime is not initialized"); MonoDomain *domain = GDMono::get_singleton()->get_scripts_domain(); @@ -1359,21 +1361,21 @@ int32_t _GodotSharp::get_scripts_domain_id() { return mono_domain_get_id(domain); } -bool _GodotSharp::is_scripts_domain_loaded() { +bool GodotSharp::is_scripts_domain_loaded() { return GDMono::get_singleton() != nullptr && GDMono::get_singleton()->is_runtime_initialized() && GDMono::get_singleton()->get_scripts_domain() != nullptr; } -bool _GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) { +bool GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) { return is_domain_finalizing_for_unload(p_domain_id); } -bool _GodotSharp::is_domain_finalizing_for_unload(int32_t p_domain_id) { +bool GodotSharp::is_domain_finalizing_for_unload(int32_t p_domain_id) { return is_domain_finalizing_for_unload(mono_domain_get_by_id(p_domain_id)); } -bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) { +bool GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) { GDMono *gd_mono = GDMono::get_singleton(); ERR_FAIL_COND_V_MSG(!gd_mono || !gd_mono->is_runtime_initialized(), @@ -1388,15 +1390,15 @@ bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) { return mono_domain_is_unloading(p_domain); } -bool _GodotSharp::is_runtime_shutting_down() { +bool GodotSharp::is_runtime_shutting_down() { return mono_runtime_is_shutting_down(); } -bool _GodotSharp::is_runtime_initialized() { +bool GodotSharp::is_runtime_initialized() { return GDMono::get_singleton() != nullptr && GDMono::get_singleton()->is_runtime_initialized(); } -void _GodotSharp::_reload_assemblies(bool p_soft_reload) { +void GodotSharp::_reload_assemblies(bool p_soft_reload) { #ifdef GD_MONO_HOT_RELOAD CRASH_COND(CSharpLanguage::get_singleton() == nullptr); // This method may be called more than once with `call_deferred`, so we need to check @@ -1407,24 +1409,26 @@ void _GodotSharp::_reload_assemblies(bool p_soft_reload) { #endif } -void _GodotSharp::_bind_methods() { - ClassDB::bind_method(D_METHOD("attach_thread"), &_GodotSharp::attach_thread); - ClassDB::bind_method(D_METHOD("detach_thread"), &_GodotSharp::detach_thread); +void GodotSharp::_bind_methods() { + ClassDB::bind_method(D_METHOD("attach_thread"), &GodotSharp::attach_thread); + ClassDB::bind_method(D_METHOD("detach_thread"), &GodotSharp::detach_thread); - ClassDB::bind_method(D_METHOD("get_domain_id"), &_GodotSharp::get_domain_id); - ClassDB::bind_method(D_METHOD("get_scripts_domain_id"), &_GodotSharp::get_scripts_domain_id); - ClassDB::bind_method(D_METHOD("is_scripts_domain_loaded"), &_GodotSharp::is_scripts_domain_loaded); - ClassDB::bind_method(D_METHOD("is_domain_finalizing_for_unload", "domain_id"), &_GodotSharp::_is_domain_finalizing_for_unload); + ClassDB::bind_method(D_METHOD("get_domain_id"), &GodotSharp::get_domain_id); + ClassDB::bind_method(D_METHOD("get_scripts_domain_id"), &GodotSharp::get_scripts_domain_id); + ClassDB::bind_method(D_METHOD("is_scripts_domain_loaded"), &GodotSharp::is_scripts_domain_loaded); + ClassDB::bind_method(D_METHOD("is_domain_finalizing_for_unload", "domain_id"), &GodotSharp::_is_domain_finalizing_for_unload); - ClassDB::bind_method(D_METHOD("is_runtime_shutting_down"), &_GodotSharp::is_runtime_shutting_down); - ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &_GodotSharp::is_runtime_initialized); - ClassDB::bind_method(D_METHOD("_reload_assemblies"), &_GodotSharp::_reload_assemblies); + ClassDB::bind_method(D_METHOD("is_runtime_shutting_down"), &GodotSharp::is_runtime_shutting_down); + ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &GodotSharp::is_runtime_initialized); + ClassDB::bind_method(D_METHOD("_reload_assemblies"), &GodotSharp::_reload_assemblies); } -_GodotSharp::_GodotSharp() { +GodotSharp::GodotSharp() { singleton = this; } -_GodotSharp::~_GodotSharp() { +GodotSharp::~GodotSharp() { singleton = nullptr; } + +} // namespace mono_bind diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 5accc21f8e..4170e5053f 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -293,8 +293,10 @@ public: gdmono::ScopeExitDomainUnload __gdmono__scope__exit__domain__unload__(m_mono_domain); \ (void)__gdmono__scope__exit__domain__unload__; -class _GodotSharp : public Object { - GDCLASS(_GodotSharp, Object); +namespace mono_bind { + +class GodotSharp : public Object { + GDCLASS(GodotSharp, Object); friend class GDMono; @@ -303,11 +305,11 @@ class _GodotSharp : public Object { void _reload_assemblies(bool p_soft_reload); protected: - static _GodotSharp *singleton; + static GodotSharp *singleton; static void _bind_methods(); public: - static _GodotSharp *get_singleton() { return singleton; } + static GodotSharp *get_singleton() { return singleton; } void attach_thread(); void detach_thread(); @@ -323,8 +325,10 @@ public: bool is_runtime_shutting_down(); bool is_runtime_initialized(); - _GodotSharp(); - ~_GodotSharp(); + GodotSharp(); + ~GodotSharp(); }; +} // namespace mono_bind + #endif // GD_MONO_H diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp index d6545d50ec..cf76c23926 100644 --- a/modules/mono/mono_gd/gd_mono_internals.cpp +++ b/modules/mono/mono_gd/gd_mono_internals.cpp @@ -45,7 +45,7 @@ namespace GDMonoInternals { void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { // This method should not fail -#if 0 + CRASH_COND(!unmanaged); // All mono objects created from the managed world (e.g.: 'new Player()') @@ -89,12 +89,16 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { } // The object was just created, no script instance binding should have been attached - CRASH_COND(unmanaged->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())); + CRASH_COND(CSharpLanguage::has_instance_binding(unmanaged)); - void *data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(unmanaged, script_binding); + void *data; + { + MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex()); + data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(unmanaged, script_binding); + } // Should be thread safe because the object was just created and nothing else should be referencing it - unmanaged->set_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index(), data); + CSharpLanguage::set_instance_binding(unmanaged, data); return; } @@ -108,7 +112,6 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle); unmanaged->set_script_and_instance(script, csharp_instance); -#endif } void unhandled_exception(MonoException *p_exc) { diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 9f2977bfa2..c9789bf270 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -1686,7 +1686,9 @@ Callable managed_to_callable(const M_Callable &p_managed_callable) { Object *target = p_managed_callable.target ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_callable.target)) : nullptr; - StringName *method_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name)); + StringName *method_ptr = p_managed_callable.method_string_name ? + unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name)) : + nullptr; StringName method = method_ptr ? *method_ptr : StringName(); return Callable(target, method); } @@ -1732,7 +1734,9 @@ Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal) { Object *owner = p_managed_signal.owner ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_signal.owner)) : nullptr; - StringName *name_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name)); + StringName *name_ptr = p_managed_signal.name_string_name ? + unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name)) : + nullptr; StringName name = name_ptr ? *name_ptr : StringName(); return Signal(owner, name); } diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 080398c997..13939bd014 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -54,7 +54,6 @@ namespace GDMonoUtils { MonoObject *unmanaged_get_managed(Object *unmanaged) { -#if 0 if (!unmanaged) { return nullptr; } @@ -69,22 +68,10 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) { // If the owner does not have a CSharpInstance... - void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); - + void *data = CSharpLanguage::get_instance_binding(unmanaged); ERR_FAIL_NULL_V(data, nullptr); - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value(); - - if (!script_binding.inited) { - MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex()); - - if (!script_binding.inited) { // Other thread may have set it up - // Already had a binding that needs to be setup - CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, unmanaged); - - ERR_FAIL_COND_V(!script_binding.inited, nullptr); - } - } + ERR_FAIL_COND_V(!script_binding.inited, nullptr); MonoGCHandleData &gchandle = script_binding.gchandle; @@ -121,8 +108,6 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) { } return mono_object; -#endif - return nullptr; } void set_main_thread(MonoThread *p_thread) { diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp index 2ba89eac55..98e83335e9 100644 --- a/modules/mono/register_types.cpp +++ b/modules/mono/register_types.cpp @@ -38,15 +38,15 @@ CSharpLanguage *script_language_cs = nullptr; Ref<ResourceFormatLoaderCSharpScript> resource_loader_cs; Ref<ResourceFormatSaverCSharpScript> resource_saver_cs; -_GodotSharp *_godotsharp = nullptr; +mono_bind::GodotSharp *_godotsharp = nullptr; void register_mono_types() { GDREGISTER_CLASS(CSharpScript); - _godotsharp = memnew(_GodotSharp); + _godotsharp = memnew(mono_bind::GodotSharp); - GDREGISTER_CLASS(_GodotSharp); - Engine::get_singleton()->add_singleton(Engine::Singleton("GodotSharp", _GodotSharp::get_singleton())); + GDREGISTER_CLASS(mono_bind::GodotSharp); + Engine::get_singleton()->add_singleton(Engine::Singleton("GodotSharp", mono_bind::GodotSharp::get_singleton())); script_language_cs = memnew(CSharpLanguage); script_language_cs->set_language_index(ScriptServer::get_language_count()); |