Skip to content

Commit 799cbd5

Browse files
author
Roberto De Ioris
committed
added a dedicated python class for structures
1 parent 9d65722 commit 799cbd5

8 files changed

Lines changed: 209 additions & 18 deletions

File tree

‎Source/UnrealEnginePython/Private/UEPyEngine.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ PyObject *py_unreal_engine_find_struct(PyObject * self, PyObject * args) {
230230
return NULL;
231231
}
232232

233-
UStruct *u_struct = FindObject<UStruct>(ANY_PACKAGE, UTF8_TO_TCHAR(name));
233+
UScriptStruct *u_struct = FindObject<UScriptStruct>(ANY_PACKAGE, UTF8_TO_TCHAR(name));
234234

235235
if (!u_struct)
236236
return PyErr_Format(PyExc_Exception, "unable to find struct %s", name);
@@ -254,7 +254,7 @@ PyObject *py_unreal_engine_load_struct(PyObject * self, PyObject * args) {
254254
if (filename)
255255
t_filename = UTF8_TO_TCHAR(filename);
256256

257-
UObject *u_struct = StaticLoadObject(UStruct::StaticClass(), NULL, UTF8_TO_TCHAR(name), t_filename);
257+
UObject *u_struct = StaticLoadObject(UScriptStruct::StaticClass(), NULL, UTF8_TO_TCHAR(name), t_filename);
258258

259259
if (!u_struct)
260260
return PyErr_Format(PyExc_Exception, "unable to find struct %s", name);

‎Source/UnrealEnginePython/Private/UEPyModule.cpp‎

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -571,8 +571,8 @@ void ue_pydelegates_cleanup(ue_PyUObject *self) {
571571
UE_LOG(LogPython, Warning, TEXT("Removing UPythonDelegate %p from ue_PyUObject %p mapped to UObject %p"), py_delegate, self, self->ue_object);
572572
#endif
573573
py_delegate->RemoveFromRoot();
574-
}
575-
}
574+
}
575+
}
576576
self->python_delegates_gc->clear();
577577
delete self->python_delegates_gc;
578578
self->python_delegates_gc = nullptr;
@@ -715,7 +715,6 @@ static PyObject *ue_PyUObject_call(ue_PyUObject *self, PyObject *args, PyObject
715715
Py_DECREF(py_args);
716716
return (PyObject *)ret;
717717
}
718-
719718
return PyErr_Format(PyExc_Exception, "the specified uobject has no __call__ support");
720719
}
721720

@@ -1065,6 +1064,8 @@ void unreal_engine_init_py_module() {
10651064

10661065
ue_python_init_callable(new_unreal_engine_module);
10671066

1067+
ue_python_init_uscriptstruct(new_unreal_engine_module);
1068+
10681069
ue_python_init_uclassesimporter(new_unreal_engine_module);
10691070
ue_python_init_enumsimporter(new_unreal_engine_module);
10701071
ue_python_init_ustructsimporter(new_unreal_engine_module);
@@ -1236,7 +1237,7 @@ void unreal_engine_py_log_error() {
12361237
}
12371238

12381239
PyErr_Clear();
1239-
}
1240+
}
12401241

12411242
// retrieve a UWorld from a generic UObject (if possible)
12421243
UWorld *ue_get_uworld(ue_PyUObject *py_obj) {
@@ -1343,8 +1344,6 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer) {
13431344
return PyErr_Format(PyExc_Exception, "invalid UClass type for %s", TCHAR_TO_UTF8(*casted_prop->GetName()));
13441345
}
13451346

1346-
1347-
13481347
// try to manage known struct first
13491348
if (auto casted_prop = Cast<UStructProperty>(prop)) {
13501349
if (auto casted_struct = Cast<UScriptStruct>(casted_prop->Struct)) {
@@ -1373,11 +1372,7 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer) {
13731372
FLinearColor color = *casted_prop->ContainerPtrToValuePtr<FLinearColor>(buffer);
13741373
return py_ue_new_flinearcolor(color);
13751374
}
1376-
ue_PyUObject *ret = ue_get_python_wrapper(casted_struct);
1377-
if (!ret)
1378-
return PyErr_Format(PyExc_Exception, "uobject is in invalid state");
1379-
Py_INCREF(ret);
1380-
return (PyObject *)ret;
1375+
return (PyObject *)py_ue_new_uscriptstruct(casted_struct, casted_prop->ContainerPtrToValuePtr<uint8>(buffer));
13811376
}
13821377
return PyErr_Format(PyExc_TypeError, "unsupported UStruct type");
13831378
}
@@ -1530,10 +1525,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) {
15301525
return false;
15311526
}
15321527

1533-
// TODO encode a dictionary to a struct
1534-
if (PyDict_Check(py_obj)) {
1535-
return false;
1536-
}
1528+
// structs
15371529

15381530
if (ue_PyFVector *py_vec = py_ue_is_fvector(py_obj)) {
15391531
if (auto casted_prop = Cast<UStructProperty>(prop)) {
@@ -1595,6 +1587,18 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) {
15951587
return false;
15961588
}
15971589

1590+
// generic structs
1591+
if (py_ue_is_uscriptstruct(py_obj)) {
1592+
ue_PyUScriptStruct *py_u_struct = (ue_PyUScriptStruct *)py_obj;
1593+
if (auto casted_prop = Cast<UStructProperty>(prop)) {
1594+
if (casted_prop->Struct == py_u_struct->u_struct) {
1595+
*casted_prop->ContainerPtrToValuePtr<uint8 *>(buffer) = py_u_struct->data;
1596+
return true;
1597+
}
1598+
}
1599+
return false;
1600+
}
1601+
15981602
if (PyObject_IsInstance(py_obj, (PyObject *)&ue_PyUObjectType)) {
15991603
ue_PyUObject *ue_obj = (ue_PyUObject *)py_obj;
16001604
if (ue_obj->ue_object->IsA<UClass>()) {

‎Source/UnrealEnginePython/Private/UEPyObject.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ PyObject *py_ue_get_property(ue_PyUObject *self, PyObject * args) {
477477

478478
UStruct *u_struct = nullptr;
479479

480-
if (self->ue_object->IsA<UStruct>()) {
480+
if (self->ue_object->IsA<UClass>()) {
481481
u_struct = (UStruct *)self->ue_object;
482482
}
483483
else {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
2+
3+
#include "UnrealEnginePythonPrivatePCH.h"
4+
5+
6+
static PyObject *py_ue_uscriptstruct_get_field(ue_PyUScriptStruct *self, PyObject * args) {
7+
char *name;
8+
if (!PyArg_ParseTuple(args, "s:get_field", &name)) {
9+
return NULL;
10+
}
11+
12+
UProperty *u_property = self->u_struct->FindPropertyByName(FName(UTF8_TO_TCHAR(name)));
13+
if (!u_property)
14+
return PyErr_Format(PyExc_Exception, "unable to find property %s", name);
15+
16+
return ue_py_convert_property(u_property, self->data);
17+
}
18+
19+
static PyMethodDef ue_PyUScriptStruct_methods[] = {
20+
{ "get_field", (PyCFunction)py_ue_uscriptstruct_get_field, METH_VARARGS, "" },
21+
{ NULL } /* Sentinel */
22+
};
23+
24+
25+
static PyObject *ue_PyUScriptStruct_str(ue_PyUScriptStruct *self)
26+
{
27+
return PyUnicode_FromFormat("<unreal_engine.UScriptStruct {'struct': '%s', 'size': %d}>",
28+
TCHAR_TO_UTF8(*self->u_struct->GetName()), self->u_struct->GetStructureSize());
29+
}
30+
31+
static PyTypeObject ue_PyUScriptStructType = {
32+
PyVarObject_HEAD_INIT(NULL, 0)
33+
"unreal_engine.UScriptStruct", /* tp_name */
34+
sizeof(ue_PyUScriptStruct), /* tp_basicsize */
35+
0, /* tp_itemsize */
36+
0, /* tp_dealloc */
37+
0, /* tp_print */
38+
0, /* tp_getattr */
39+
0, /* tp_setattr */
40+
0, /* tp_reserved */
41+
0, /* tp_repr */
42+
0, /* tp_as_number */
43+
0, /* tp_as_sequence */
44+
0, /* tp_as_mapping */
45+
0, /* tp_hash */
46+
0, /* tp_call */
47+
(reprfunc)ue_PyUScriptStruct_str, /* tp_str */
48+
0, /* tp_getattro */
49+
0, /* tp_setattro */
50+
0, /* tp_as_buffer */
51+
Py_TPFLAGS_DEFAULT, /* tp_flags */
52+
"Unreal Engine Editor UScriptStruct", /* tp_doc */
53+
0, /* tp_traverse */
54+
0, /* tp_clear */
55+
0, /* tp_richcompare */
56+
0, /* tp_weaklistoffset */
57+
0, /* tp_iter */
58+
0, /* tp_iternext */
59+
ue_PyUScriptStruct_methods, /* tp_methods */
60+
0,
61+
0,
62+
};
63+
64+
65+
void ue_python_init_uscriptstruct(PyObject *ue_module) {
66+
ue_PyUScriptStructType.tp_new = PyType_GenericNew;
67+
68+
if (PyType_Ready(&ue_PyUScriptStructType) < 0)
69+
return;
70+
71+
Py_INCREF(&ue_PyUScriptStructType);
72+
PyModule_AddObject(ue_module, "UScriptStruct", (PyObject *)&ue_PyUScriptStructType);
73+
}
74+
75+
PyObject *py_ue_new_uscriptstruct(UScriptStruct *u_struct, uint8 *data) {
76+
ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)PyObject_New(ue_PyUScriptStruct, &ue_PyUScriptStructType);
77+
ret->u_struct = u_struct;
78+
ret->data = data;
79+
return (PyObject *)ret;
80+
}
81+
82+
ue_PyUScriptStruct *py_ue_is_uscriptstruct(PyObject *obj) {
83+
if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyUScriptStructType))
84+
return nullptr;
85+
return (ue_PyUScriptStruct *)obj;
86+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
3+
#include "UnrealEnginePython.h"
4+
5+
typedef struct {
6+
PyObject_HEAD
7+
/* Type-specific fields go here. */
8+
UScriptStruct *u_struct;
9+
uint8 *data;
10+
} ue_PyUScriptStruct;
11+
12+
PyObject *py_ue_new_uscriptstruct(UScriptStruct *, uint8 *);
13+
ue_PyUScriptStruct *py_ue_is_uscriptstruct(PyObject *);
14+
15+
void ue_python_init_uscriptstruct(PyObject *);
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "UnrealEnginePythonPrivatePCH.h"
2+
3+
static PyObject *ue_PyUStructsImporter_getattro(ue_PyUStructsImporter *self, PyObject *attr_name) {
4+
PyObject *ret = PyObject_GenericGetAttr((PyObject *)self, attr_name);
5+
if (!ret) {
6+
if (PyUnicodeOrString_Check(attr_name)) {
7+
char *attr = PyUnicode_AsUTF8(attr_name);
8+
if (attr[0] != '_') {
9+
UScriptStruct *u_struct = FindObject<UScriptStruct>(ANY_PACKAGE, UTF8_TO_TCHAR(attr));
10+
if (u_struct) {
11+
// swallow old exception
12+
PyErr_Clear();
13+
ue_PyUObject *u_ret = ue_get_python_wrapper(u_struct);
14+
if (!u_ret)
15+
return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state");
16+
Py_INCREF(u_ret);
17+
return (PyObject *)u_ret;
18+
}
19+
}
20+
}
21+
}
22+
return ret;
23+
}
24+
25+
static PyTypeObject ue_PyUStructsImporterType = {
26+
PyVarObject_HEAD_INIT(NULL, 0)
27+
"unreal_engine.UStructsImporter", /* tp_name */
28+
sizeof(ue_PyUStructsImporter), /* tp_basicsize */
29+
0, /* tp_itemsize */
30+
0, /* tp_dealloc */
31+
0, /* tp_print */
32+
0, /* tp_getattr */
33+
0, /* tp_setattr */
34+
0, /* tp_reserved */
35+
0, /* tp_repr */
36+
0, /* tp_as_number */
37+
0, /* tp_as_sequence */
38+
0, /* tp_as_mapping */
39+
0, /* tp_hash */
40+
0, /* tp_call */
41+
0, /* tp_str */
42+
(getattrofunc)ue_PyUStructsImporter_getattro, /* tp_getattro */
43+
0, /* tp_setattro */
44+
0, /* tp_as_buffer */
45+
Py_TPFLAGS_DEFAULT, /* tp_flags */
46+
"Unreal Engine UStructs Importer", /* tp_doc */
47+
0, /* tp_traverse */
48+
0, /* tp_clear */
49+
0, /* tp_richcompare */
50+
0, /* tp_weaklistoffset */
51+
0, /* tp_iter */
52+
0, /* tp_iternext */
53+
0, /* tp_methods */
54+
0,
55+
0,
56+
};
57+
58+
void ue_python_init_ustructsimporter(PyObject *ue_module) {
59+
ue_PyUStructsImporterType.tp_new = PyType_GenericNew;
60+
61+
if (PyType_Ready(&ue_PyUStructsImporterType) < 0)
62+
return;
63+
64+
Py_INCREF(&ue_PyUStructsImporterType);
65+
PyModule_AddObject(ue_module, "UStructsImporter", (PyObject *)&ue_PyUStructsImporterType);
66+
}
67+
68+
PyObject *py_ue_new_ustructsimporter() {
69+
ue_PyUStructsImporter *ret = (ue_PyUStructsImporter *)PyObject_New(ue_PyUStructsImporter, &ue_PyUStructsImporterType);
70+
return (PyObject *)ret;
71+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
3+
4+
5+
#include "UnrealEnginePython.h"
6+
7+
typedef struct {
8+
PyObject_HEAD
9+
/* Type-specific fields go here. */
10+
} ue_PyUStructsImporter;
11+
12+
PyObject *py_ue_new_ustructsimporter();
13+
14+
void ue_python_init_ustructsimporter(PyObject *);

‎Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "UEPyFColor.h"
3535
#include "UEPyFLinearColor.h"
3636
#include "UEPyFSocket.h"
37+
#include "UEPyUScriptStruct.h"
3738

3839
#include "UEPyCallable.h"
3940
#include "UEPyUClassesImporter.h"

0 commit comments

Comments
 (0)