Skip to content

Commit 0463b69

Browse files
author
Roberto De Ioris
committed
UObject's created from python are now managed by python itself
1 parent 353b2ee commit 0463b69

File tree

4 files changed

+47
-9
lines changed

4 files changed

+47
-9
lines changed

Source/UnrealEnginePython/Private/UEPyEngine.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,17 @@ PyObject *py_unreal_engine_new_object(PyObject * self, PyObject * args)
601601
if (!new_object)
602602
return PyErr_Format(PyExc_Exception, "unable to create object");
603603

604-
Py_RETURN_UOBJECT(new_object);
604+
ue_PyUObject *py_uobject = ue_get_python_uobject(new_object);
605+
if (!py_uobject)
606+
{
607+
return PyErr_Format(PyExc_Exception, "unable to create python wrapper for uobject");
608+
}
609+
py_uobject->owned = 1;
610+
611+
// UObject crated explicitely from python, will be managed by python...
612+
FUnrealEnginePythonHouseKeeper::Get()->TrackUObject(new_object);
613+
614+
return (PyObject *)py_uobject;
605615
}
606616

607617
PyObject *py_unreal_engine_get_mutable_default(PyObject * self, PyObject * args)

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,11 @@ static void ue_pyobject_dealloc(ue_PyUObject *self)
11221122
#if defined(UEPY_MEMORY_DEBUG)
11231123
UE_LOG(LogPython, Warning, TEXT("Destroying ue_PyUObject %p mapped to UObject %p"), self, self->ue_object);
11241124
#endif
1125+
if (self->owned)
1126+
{
1127+
FUnrealEnginePythonHouseKeeper::Get()->UntrackUObject(self->ue_object);
1128+
}
1129+
11251130
if (self->auto_rooted && (self->ue_object && self->ue_object->IsValidLowLevel() && self->ue_object->IsRooted()))
11261131
{
11271132
self->ue_object->RemoveFromRoot();
@@ -1756,6 +1761,7 @@ ue_PyUObject *ue_get_python_uobject(UObject *ue_obj)
17561761
ue_py_object->py_proxy = nullptr;
17571762
ue_py_object->auto_rooted = 0;
17581763
ue_py_object->py_dict = PyDict_New();
1764+
ue_py_object->owned = 0;
17591765

17601766
FUnrealEnginePythonHouseKeeper::Get()->RegisterPyUObject(ue_obj, ue_py_object);
17611767

Source/UnrealEnginePython/Public/PythonHouseKeeper.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
#include "UObject/WeakObjectPtr.h"
66
#include "Widgets/SWidget.h"
77
#include "Slate/UEPySlateDelegate.h"
8+
#include "Runtime/CoreUObject/Public/UObject/GCObject.h"
89
#include "PythonDelegate.h"
910

10-
class FUnrealEnginePythonHouseKeeper
11+
class FUnrealEnginePythonHouseKeeper : public FGCObject
1112
{
1213

1314
struct FPythonUOjectTracker
@@ -53,6 +54,11 @@ class FUnrealEnginePythonHouseKeeper
5354

5455
public:
5556

57+
virtual void AddReferencedObjects(FReferenceCollector& InCollector) override
58+
{
59+
InCollector.AddReferencedObjects(PythonTrackedObjects);
60+
}
61+
5662
static FUnrealEnginePythonHouseKeeper *Get()
5763
{
5864
static FUnrealEnginePythonHouseKeeper *Singleton;
@@ -101,6 +107,16 @@ class FUnrealEnginePythonHouseKeeper
101107

102108
}
103109

110+
void TrackUObject(UObject *Object)
111+
{
112+
PythonTrackedObjects.Add(Object);
113+
}
114+
115+
void UntrackUObject(UObject *Object)
116+
{
117+
PythonTrackedObjects.Remove(Object);
118+
}
119+
104120
void RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject)
105121
{
106122
UObjectPyMapping.Add(Object, FPythonUOjectTracker(Object, InPyUObject));
@@ -124,7 +140,8 @@ class FUnrealEnginePythonHouseKeeper
124140
#if defined(UEPY_MEMORY_DEBUG)
125141
UE_LOG(LogPython, Warning, TEXT("DEFREF'ing UObject at %p (refcnt: %d)"), Object, Tracker->PyUObject->ob_base.ob_refcnt);
126142
#endif
127-
Py_DECREF((PyObject *)Tracker->PyUObject);
143+
if (!Tracker->PyUObject->owned)
144+
Py_DECREF((PyObject *)Tracker->PyUObject);
128145
UnregisterPyUObject(Object);
129146
return nullptr;
130147
}
@@ -157,18 +174,19 @@ class FUnrealEnginePythonHouseKeeper
157174
UE_LOG(LogPython, Error, TEXT("UObject at %p %s is in use"), Object, *Object->GetName());
158175
#endif
159176
}
160-
}
177+
}
161178

162179
for (UObject *Object : BrokenList)
163180
{
164181
FPythonUOjectTracker &Tracker = UObjectPyMapping[Object];
165-
Py_DECREF((PyObject *)Tracker.PyUObject);
182+
if (!Tracker.PyUObject->owned)
183+
Py_DECREF((PyObject *)Tracker.PyUObject);
166184
UnregisterPyUObject(Object);
167185
}
168186

169187
return Garbaged;
170188

171-
}
189+
}
172190

173191

174192
int32 DelegatesGC()
@@ -261,4 +279,6 @@ class FUnrealEnginePythonHouseKeeper
261279

262280
TArray<FPythonSWidgetDelegateTracker> PySlateDelegatesTracker;
263281
TArray<TSharedRef<FPythonSlateDelegate>> PyStaticSlateDelegatesTracker;
264-
};
282+
283+
TArray<UObject *> PythonTrackedObjects;
284+
};

Source/UnrealEnginePython/Public/UnrealEnginePython.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,16 @@
3636
typedef struct
3737
{
3838
PyObject_HEAD
39-
/* Type-specific fields go here. */
40-
UObject *ue_object;
39+
/* Type-specific fields go here. */
40+
UObject *ue_object;
4141
// reference to proxy class (can be null)
4242
PyObject *py_proxy;
4343
// the __dict__
4444
PyObject *py_dict;
4545
// if true RemoveFromRoot will be called at object destruction time
4646
int auto_rooted;
47+
// if owned the life of the UObject is related to the life of PyObject
48+
int owned;
4749
} ue_PyUObject;
4850

4951
UNREALENGINEPYTHON_API void ue_py_register_magic_module(char *name, PyObject *(*)());

0 commit comments

Comments
 (0)