Prechádzať zdrojové kódy

C#: Fix custom event signals crash on hot-reload

Cleanup and re-initialization of event signals before
and after hot-reload should be working correctly now.
Ignacio Etcheverry 4 rokov pred
rodič
commit
34960cb936

+ 10 - 5
modules/mono/csharp_script.cpp

@@ -940,8 +940,6 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
 
 				// Use a placeholder for now to avoid losing the state when saving a scene
 
-				obj->set_script(scr);
-
 				PlaceHolderScriptInstance *placeholder = scr->placeholder_instance_create(obj);
 				obj->set_script_instance(placeholder);
 
@@ -968,12 +966,12 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
 	for (List<Ref<CSharpScript>>::Element *E = to_reload.front(); E; E = E->next()) {
 		Ref<CSharpScript> script = E->get();
 
-		if (!script->get_path().empty()) {
 #ifdef TOOLS_ENABLED
-			script->exports_invalidated = true;
+		script->exports_invalidated = true;
 #endif
-			script->signals_invalidated = true;
+		script->signals_invalidated = true;
 
+		if (!script->get_path().empty()) {
 			script->reload(p_soft_reload);
 
 			if (!script->valid) {
@@ -1949,6 +1947,7 @@ MonoObject *CSharpInstance::_internal_new_managed() {
 }
 
 void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
+	// Must make sure event signals are not left dangling
 	disconnect_event_signals();
 
 #ifdef DEBUG_ENABLED
@@ -1964,6 +1963,9 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f
 	CRASH_COND(gchandle.is_released());
 #endif
 
+	// Must make sure event signals are not left dangling
+	disconnect_event_signals();
+
 	r_remove_script_instance = false;
 
 	if (_unreference_owner_unsafe()) {
@@ -2223,6 +2225,9 @@ CSharpInstance::~CSharpInstance() {
 
 	destructing_script_instance = true;
 
+	// Must make sure event signals are not left dangling
+	disconnect_event_signals();
+
 	if (!gchandle.is_released()) {
 		if (!predelete_notified && !ref_dying) {
 			// This destructor is not called from the owners destructor.

+ 1 - 1
modules/mono/csharp_script.h

@@ -288,7 +288,7 @@ public:
 	void mono_object_disposed(MonoObject *p_obj);
 
 	/*
-	 * If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, ifevent_signal
+	 * If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, if
 	 * 'r_remove_script_instance' is set to true, the caller must destroy the script instance by removing it from its owner.
 	 */
 	void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);

+ 2 - 2
modules/mono/editor/bindings_generator.cpp

@@ -97,7 +97,7 @@
 #define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL "::signal_info_to_callable"
 #define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL "::callable_to_signal_info"
 
-#define BINDINGS_GENERATOR_VERSION UINT32_C(11)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(12)
 
 const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
 
@@ -1368,7 +1368,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
 			output.append(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
 			output.append(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
 			output.append("." + ctor_method);
-			output.append("(this);\n" CLOSE_BLOCK_L2);
+			output.append("(this);\n" INDENT3 "_InitializeGodotScriptInstanceInternals();\n" CLOSE_BLOCK_L2);
 		} else {
 			// Hide the constructor
 			output.append(MEMBER_BEGIN "internal ");

+ 6 - 7
modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs

@@ -15,14 +15,13 @@ namespace Godot
         public Object() : this(false)
         {
             if (ptr == IntPtr.Zero)
-            {
                 ptr = godot_icall_Object_Ctor(this);
-            }
-            else
-            {
-                // This is called inside godot_icall_Object_Ctor, so we must call it as well in this case.
-                godot_icall_Object_ConnectEventSignals(ptr);
-            }
+            _InitializeGodotScriptInstanceInternals();
+        }
+
+        internal void _InitializeGodotScriptInstanceInternals()
+        {
+            godot_icall_Object_ConnectEventSignals(ptr);
         }
 
         internal Object(bool memoryOwn)

+ 0 - 2
modules/mono/mono_gd/gd_mono_internals.cpp

@@ -109,8 +109,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);
-
-	csharp_instance->connect_event_signals();
 }
 
 void unhandled_exception(MonoException *p_exc) {