Skip to content

Commit 8b60cca

Browse files
authored
Merge pull request 20tab#676 from dfb/pr_unbind_event
Add support for unbind_event
2 parents b9fb929 + dc6e93c commit 8b60cca

File tree

7 files changed

+82
-2
lines changed

7 files changed

+82
-2
lines changed

Source/UnrealEnginePython/Private/PythonDelegate.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
#include "PythonDelegate.h"
33
#include "UEPyModule.h"
4+
#include "UEPyCallable.h"
45

56
UPythonDelegate::UPythonDelegate()
67
{
@@ -101,6 +102,12 @@ void UPythonDelegate::PyInputAxisHandler(float value)
101102
Py_DECREF(ret);
102103
}
103104

105+
bool UPythonDelegate::UsesPyCallable(PyObject *other)
106+
{
107+
ue_PyCallable *other_callable = (ue_PyCallable*)other;
108+
ue_PyCallable *this_callable = (ue_PyCallable*)py_callable;
109+
return other_callable->u_function == this_callable->u_function && other_callable->u_target == this_callable->u_target;
110+
}
104111

105112
UPythonDelegate::~UPythonDelegate()
106113
{
@@ -110,4 +117,4 @@ UPythonDelegate::~UPythonDelegate()
110117
#if defined(UEPY_MEMORY_DEBUG)
111118
UE_LOG(LogPython, Warning, TEXT("PythonDelegate %p callable XDECREF'ed"), this);
112119
#endif
113-
}
120+
}

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ static PyMethodDef ue_PyUObject_methods[] = {
607607
{ "set_name", (PyCFunction)py_ue_set_name, METH_VARARGS, "" },
608608

609609
{ "bind_event", (PyCFunction)py_ue_bind_event, METH_VARARGS, "" },
610+
{ "unbind_event", (PyCFunction)py_ue_unbind_event, METH_VARARGS, "" },
610611
{ "delegate_bind_ufunction", (PyCFunction)py_ue_delegate_bind_ufunction, METH_VARARGS, "" },
611612

612613
{ "get_py_proxy", (PyCFunction)py_ue_get_py_proxy, METH_VARARGS, "" },
@@ -3044,6 +3045,45 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject *
30443045
Py_RETURN_NONE;
30453046
}
30463047

3048+
PyObject *ue_unbind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_callable, bool fail_on_wrong_property)
3049+
{
3050+
UProperty *u_property = u_obj->ue_object->GetClass()->FindPropertyByName(FName(*event_name));
3051+
if (!u_property)
3052+
{
3053+
if (fail_on_wrong_property)
3054+
return PyErr_Format(PyExc_Exception, "unable to find event property %s", TCHAR_TO_UTF8(*event_name));
3055+
Py_RETURN_NONE;
3056+
}
3057+
3058+
if (auto casted_prop = Cast<UMulticastDelegateProperty>(u_property))
3059+
{
3060+
UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->FindDelegate(u_obj->ue_object, py_callable);
3061+
if (py_delegate != nullptr)
3062+
{
3063+
FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(u_obj->ue_object);
3064+
multiscript_delegate.Remove(py_delegate, FName("PyFakeCallable"));
3065+
3066+
// re-assign multicast delegate
3067+
casted_prop->SetPropertyValue_InContainer(u_obj->ue_object, multiscript_delegate);
3068+
}
3069+
}
3070+
else if (auto casted_prop_delegate = Cast<UDelegateProperty>(u_property))
3071+
{
3072+
FScriptDelegate script_delegate = casted_prop_delegate->GetPropertyValue_InContainer(u_obj->ue_object);
3073+
script_delegate.Unbind();
3074+
3075+
// re-assign multicast delegate
3076+
casted_prop_delegate->SetPropertyValue_InContainer(u_obj->ue_object, script_delegate);
3077+
}
3078+
else
3079+
{
3080+
if (fail_on_wrong_property)
3081+
return PyErr_Format(PyExc_Exception, "property %s is not an event", TCHAR_TO_UTF8(*event_name));
3082+
}
3083+
3084+
Py_RETURN_NONE;
3085+
}
3086+
30473087
PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_callable, bool fail_on_wrong_property)
30483088
{
30493089

Source/UnrealEnginePython/Private/UEPyModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ void ue_bind_events_for_py_class_by_attribute(UObject *, PyObject *);
3535

3636
void ue_autobind_events_for_pyclass(ue_PyUObject *, PyObject *);
3737
PyObject *ue_bind_pyevent(ue_PyUObject *, FString, PyObject *, bool);
38+
PyObject *ue_unbind_pyevent(ue_PyUObject *, FString, PyObject *, bool);
3839

3940
PyObject *py_ue_ufunction_call(UFunction *, UObject *, PyObject *, int, PyObject *);
4041

Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,6 +1517,25 @@ PyObject *py_ue_bind_event(ue_PyUObject * self, PyObject * args)
15171517
return ue_bind_pyevent(self, FString(event_name), py_callable, true);
15181518
}
15191519

1520+
PyObject *py_ue_unbind_event(ue_PyUObject * self, PyObject * args)
1521+
{
1522+
ue_py_check(self);
1523+
1524+
char *event_name;
1525+
PyObject *py_callable;
1526+
if (!PyArg_ParseTuple(args, "sO:bind_event", &event_name, &py_callable))
1527+
{
1528+
return NULL;
1529+
}
1530+
1531+
if (!PyCallable_Check(py_callable))
1532+
{
1533+
return PyErr_Format(PyExc_Exception, "object is not callable");
1534+
}
1535+
1536+
return ue_unbind_pyevent(self, FString(event_name), py_callable, true);
1537+
}
1538+
15201539
PyObject *py_ue_delegate_bind_ufunction(ue_PyUObject * self, PyObject * args)
15211540
{
15221541
ue_py_check(self);

Source/UnrealEnginePython/Private/UObject/UEPyObject.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ PyObject *py_ue_enum_user_defined_names(ue_PyUObject *, PyObject *);
5151

5252

5353
PyObject *py_ue_bind_event(ue_PyUObject *, PyObject *);
54+
PyObject *py_ue_unbind_event(ue_PyUObject *, PyObject *);
5455
PyObject *py_ue_add_function(ue_PyUObject *, PyObject *);
5556
PyObject *py_ue_add_property(ue_PyUObject *, PyObject *);
5657

@@ -111,4 +112,4 @@ PyObject *py_ue_render_thumbnail(ue_PyUObject *, PyObject *);
111112

112113
PyObject *py_ue_to_bytes(ue_PyUObject *, PyObject *);
113114
PyObject *py_ue_to_bytearray(ue_PyUObject *, PyObject *);
114-
PyObject *py_ue_from_bytes(ue_PyUObject *, PyObject *);
115+
PyObject *py_ue_from_bytes(ue_PyUObject *, PyObject *);

Source/UnrealEnginePython/Public/PythonDelegate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class UPythonDelegate : public UObject
1313
~UPythonDelegate();
1414
virtual void ProcessEvent(UFunction *function, void *Parms) override;
1515
void SetPyCallable(PyObject *callable);
16+
bool UsesPyCallable(PyObject *callable);
1617
void SetSignature(UFunction *original_signature);
1718

1819
void PyInputHandler();

Source/UnrealEnginePython/Public/PythonHouseKeeper.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,17 @@ class FUnrealEnginePythonHouseKeeper : public FGCObject
238238
return Garbaged;
239239
}
240240

241+
UPythonDelegate *FindDelegate(UObject *Owner, PyObject *PyCallable)
242+
{
243+
for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i)
244+
{
245+
FPythonDelegateTracker &Tracker = PyDelegatesTracker[i];
246+
if (Tracker.Owner.Get() == Owner && Tracker.Delegate->UsesPyCallable(PyCallable))
247+
return Tracker.Delegate;
248+
}
249+
return nullptr;
250+
}
251+
241252
UPythonDelegate *NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature)
242253
{
243254
UPythonDelegate *Delegate = NewObject<UPythonDelegate>();

0 commit comments

Comments
 (0)