diff options
Diffstat (limited to 'modules/mono/csharp_script.cpp')
-rw-r--r-- | modules/mono/csharp_script.cpp | 49 |
1 files changed, 29 insertions, 20 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index bc26352e9c..1ed495943f 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -120,6 +120,7 @@ void CSharpLanguage::init() { GLOBAL_DEF("dotnet/project/assembly_name", ""); #ifdef TOOLS_ENABLED GLOBAL_DEF("dotnet/project/solution_directory", ""); + GLOBAL_DEF(PropertyInfo(Variant::INT, "dotnet/project/assembly_reload_attempts", PROPERTY_HINT_RANGE, "1,16,1,or_greater"), 3); #endif gdmono = memnew(GDMono); @@ -770,10 +771,6 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { return; } - // TODO: - // Currently, this reloads all scripts, including those whose class is not part of the - // assembly load context being unloaded. As such, we unnecessarily reload GodotTools. - print_verbose(".NET: Reloading assemblies..."); // There is no soft reloading with Mono. It's always hard reloading. @@ -784,8 +781,20 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { MutexLock lock(script_instances_mutex); for (SelfList<CSharpScript> *elem = script_list.first(); elem; elem = elem->next()) { - // Cast to CSharpScript to avoid being erased by accident - scripts.push_back(Ref<CSharpScript>(elem->self())); + // Do not reload scripts with only non-collectible instances to avoid disrupting event subscriptions and such. + bool is_reloadable = elem->self()->instances.size() == 0; + for (Object *obj : elem->self()->instances) { + ERR_CONTINUE(!obj->get_script_instance()); + CSharpInstance *csi = static_cast<CSharpInstance *>(obj->get_script_instance()); + if (GDMonoCache::managed_callbacks.GCHandleBridge_GCHandleIsTargetCollectible(csi->get_gchandle_intptr())) { + is_reloadable = true; + break; + } + } + if (is_reloadable) { + // Cast to CSharpScript to avoid being erased by accident. + scripts.push_back(Ref<CSharpScript>(elem->self())); + } } } @@ -800,6 +809,10 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { ERR_CONTINUE(managed_callable->delegate_handle.value == nullptr); + if (!GDMonoCache::managed_callbacks.GCHandleBridge_GCHandleIsTargetCollectible(managed_callable->delegate_handle)) { + continue; + } + Array serialized_data; bool success = GDMonoCache::managed_callbacks.DelegateUtils_TrySerializeDelegateWithGCHandle( @@ -907,6 +920,15 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { scr->_clear(); } + // Release the delegates that were serialized earlier. + { + MutexLock lock(ManagedCallable::instances_mutex); + + for (KeyValue<ManagedCallable *, Array> &kv : ManagedCallable::instances_pending_reload) { + kv.key->release_delegate_handle(); + } + } + // Do domain reload if (gdmono->reload_project_assemblies() != OK) { // Failed to reload the scripts domain @@ -1158,19 +1180,6 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) { } } -void CSharpLanguage::_on_scripts_domain_about_to_unload() { -#ifdef GD_MONO_HOT_RELOAD - { - MutexLock lock(ManagedCallable::instances_mutex); - - for (SelfList<ManagedCallable> *elem = ManagedCallable::instances.first(); elem; elem = elem->next()) { - ManagedCallable *managed_callable = elem->self(); - managed_callable->release_delegate_handle(); - } - } -#endif -} - #ifdef TOOLS_ENABLED void CSharpLanguage::_editor_init_callback() { // Load GodotTools and initialize GodotSharpEditor @@ -2263,7 +2272,7 @@ void CSharpScript::reload_registered_script(Ref<CSharpScript> p_script) { // If the EditorFileSystem singleton is available, update the file; // otherwise, the file will be updated when the singleton becomes available. EditorFileSystem *efs = EditorFileSystem::get_singleton(); - if (efs) { + if (efs && !p_script->get_path().is_empty()) { efs->update_file(p_script->get_path()); } #endif |