Browse Source

Merge pull request #66674 from pkdawson/fix-callable-delegate

Fix C# delegate signal not disconnected when Object is destroyed
Ignacio Roldán Etcheverry 2 years ago
parent
commit
abf473e2d0

+ 1 - 1
modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs

@@ -72,7 +72,7 @@ namespace Godot
         /// <param name="delegate">Delegate method that will be called.</param>
         public Callable(Delegate @delegate)
         {
-            _target = null;
+            _target = @delegate?.Target as Object;
             _method = null;
             _delegate = @delegate;
         }

+ 2 - 1
modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs

@@ -721,8 +721,9 @@ namespace Godot.NativeInterop
             if (p_managed_callable.Delegate != null)
             {
                 var gcHandle = CustomGCHandle.AllocStrong(p_managed_callable.Delegate);
+                IntPtr objectPtr = p_managed_callable.Target != null ? Object.GetPtr(p_managed_callable.Target) : IntPtr.Zero;
                 NativeFuncs.godotsharp_callable_new_with_delegate(
-                    GCHandle.ToIntPtr(gcHandle), out godot_callable callable);
+                    GCHandle.ToIntPtr(gcHandle), objectPtr, out godot_callable callable);
                 return callable;
             }
             else

+ 1 - 1
modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs

@@ -141,7 +141,7 @@ namespace Godot.NativeInterop
         public static partial void godotsharp_packed_string_array_add(ref godot_packed_string_array r_dest,
             in godot_string p_element);
 
-        public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle,
+        public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, IntPtr p_object,
             out godot_callable r_callable);
 
         internal static partial godot_bool godotsharp_callable_get_data_for_marshalling(in godot_callable p_callable,

+ 3 - 2
modules/mono/glue/runtime_interop.cpp

@@ -447,9 +447,10 @@ void godotsharp_packed_string_array_add(PackedStringArray *r_dest, const String
 	r_dest->append(*p_element);
 }
 
-void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, Callable *r_callable) {
+void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, const Object *p_object, Callable *r_callable) {
 	// TODO: Use pooling for ManagedCallable instances.
-	CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle));
+	ObjectID objid = p_object ? p_object->get_instance_id() : ObjectID();
+	CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle, objid));
 	memnew_placement(r_callable, Callable(managed_callable));
 }
 

+ 4 - 2
modules/mono/managed_callable.cpp

@@ -79,7 +79,9 @@ CallableCustom::CompareLessFunc ManagedCallable::get_compare_less_func() const {
 }
 
 ObjectID ManagedCallable::get_object() const {
-	// TODO: If the delegate target extends Godot.Object, use that instead!
+	if (object_id != ObjectID()) {
+		return object_id;
+	}
 	return CSharpLanguage::get_singleton()->get_managed_callable_middleman()->get_instance_id();
 }
 
@@ -104,7 +106,7 @@ void ManagedCallable::release_delegate_handle() {
 
 // Why you do this clang-format...
 /* clang-format off */
-ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle) : delegate_handle(p_delegate_handle) {
+ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle, ObjectID p_object_id) : delegate_handle(p_delegate_handle), object_id(p_object_id) {
 #ifdef GD_MONO_HOT_RELOAD
 	{
 		MutexLock lock(instances_mutex);

+ 2 - 1
modules/mono/managed_callable.h

@@ -40,6 +40,7 @@
 class ManagedCallable : public CallableCustom {
 	friend class CSharpLanguage;
 	GCHandleIntPtr delegate_handle;
+	ObjectID object_id;
 
 #ifdef GD_MONO_HOT_RELOAD
 	SelfList<ManagedCallable> self_instance = this;
@@ -66,7 +67,7 @@ public:
 
 	void release_delegate_handle();
 
-	ManagedCallable(GCHandleIntPtr p_delegate_handle);
+	ManagedCallable(GCHandleIntPtr p_delegate_handle, ObjectID p_object_id);
 	~ManagedCallable();
 };