Skip to content

Commit f8f0fcc

Browse files
committed
initial POC implementation
1 parent e73b3f2 commit f8f0fcc

File tree

2 files changed

+332
-337
lines changed

2 files changed

+332
-337
lines changed

Source/UnrealEnginePython/Private/PythonFunction.cpp

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
3131
// count the number of arguments
3232
Py_ssize_t argn = (Context && !is_static) ? 1 : 0;
3333
TFieldIterator<UProperty> IArgs(function);
34-
for (; IArgs && ((IArgs->PropertyFlags & (CPF_Parm | CPF_ReturnParm)) == CPF_Parm); ++IArgs) {
34+
for (; IArgs && ((IArgs->PropertyFlags & (CPF_Parm | CPF_OutParm)) == CPF_Parm); ++IArgs) {
3535
argn++;
3636
}
3737
#if defined(UEPY_MEMORY_DEBUG)
@@ -55,10 +55,15 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
5555
uint8 *frame = Stack.Locals;
5656

5757
// is it a blueprint call ?
58+
UProperty *first_out_prop = nullptr;
5859
if (*Stack.Code == EX_EndFunctionParms) {
5960
for (UProperty *prop = (UProperty *)function->Children; prop; prop = (UProperty *)prop->Next) {
60-
if (prop->PropertyFlags & CPF_ReturnParm)
61+
if (prop->PropertyFlags & CPF_OutParm)
62+
{
63+
if (!first_out_prop)
64+
first_out_prop = prop;
6165
continue;
66+
}
6267
if (!on_error) {
6368
PyObject *arg = ue_py_convert_property(prop, (uint8 *)Stack.Locals, 0);
6469
if (!arg) {
@@ -77,8 +82,12 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
7782
FMemory::Memzero(frame, function->PropertiesSize);
7883
for (UProperty *prop = (UProperty *)function->Children; *Stack.Code != EX_EndFunctionParms; prop = (UProperty *)prop->Next) {
7984
Stack.Step(Stack.Object, prop->ContainerPtrToValuePtr<uint8>(frame));
80-
if (prop->PropertyFlags & CPF_ReturnParm)
85+
if (prop->PropertyFlags & CPF_OutParm)
86+
{
87+
if (!first_out_prop)
88+
first_out_prop = prop;
8189
continue;
90+
}
8291
if (!on_error) {
8392
PyObject *arg = ue_py_convert_property(prop, frame, 0);
8493
if (!arg) {
@@ -106,19 +115,74 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
106115
return;
107116
}
108117

109-
// get return value (if required)
110-
UProperty *return_property = function->GetReturnProperty();
111-
if (return_property && function->ReturnValueOffset != MAX_uint16) {
112-
#if defined(UEPY_MEMORY_DEBUG)
113-
UE_LOG(LogPython, Warning, TEXT("FOUND RETURN VALUE"));
114-
#endif
115-
if (ue_py_convert_pyobject(ret, return_property, frame, 0)) {
116-
// copy value to stack result value
117-
FMemory::Memcpy(RESULT_PARAM, frame + function->ReturnValueOffset, return_property->ArrayDim * return_property->ElementSize);
118-
}
119-
else {
120-
UE_LOG(LogPython, Error, TEXT("Invalid return value type for function %s"), *function->GetFName().ToString());
121-
}
118+
// get return value and/or any out params
119+
if (PyTuple_Check(ret))
120+
{ // function has multiple output params or a return value and one or more output params
121+
int nret = PyTuple_Size(ret);
122+
int tuple_index = 0;
123+
for( TFieldIterator<UProperty> It(function); It && (It->PropertyFlags & CPF_Parm); ++It )
124+
{
125+
if( It->PropertyFlags & CPF_OutParm )
126+
{
127+
if (tuple_index >= nret)
128+
{
129+
UE_LOG(LogPython, Error, TEXT("Python function %s didn't return enough values"), *function->GetFName().ToString());
130+
}
131+
else
132+
{
133+
UProperty *prop = *It;
134+
PyObject *py_obj = PyTuple_GetItem(ret, tuple_index);
135+
uint8 *out_frame = frame;
136+
for (FOutParmRec *rec = Stack.OutParms; rec != nullptr; rec = rec->NextOutParm)
137+
{
138+
if (rec->Property == prop)
139+
{
140+
out_frame = rec->PropAddr - prop->GetOffset_ForUFunction();
141+
break;
142+
}
143+
}
144+
if (ue_py_convert_pyobject(py_obj, prop, out_frame, 0))
145+
{
146+
if (prop->PropertyFlags & CPF_ReturnParm)
147+
{
148+
// copy value to stack result value
149+
//FMemory::Memcpy(RESULT_PARAM, frame + function->ReturnValueOffset, prop->ArrayDim * prop->ElementSize);
150+
}
151+
}
152+
else {
153+
UE_LOG(LogPython, Error, TEXT("Invalid return value type for function %s"), *function->GetFName().ToString());
154+
}
155+
tuple_index++;
156+
}
157+
}
158+
}
159+
160+
}
161+
else
162+
{ // no output params, but maybe a return value
163+
if (first_out_prop)
164+
{
165+
uint8 *out_frame = frame;
166+
for (FOutParmRec *rec = Stack.OutParms; rec != nullptr; rec = rec->NextOutParm)
167+
{
168+
if (rec->Property == first_out_prop)
169+
{
170+
out_frame = rec->PropAddr - first_out_prop->GetOffset_ForUFunction();
171+
break;
172+
}
173+
}
174+
if (ue_py_convert_pyobject(ret, first_out_prop, out_frame, 0))
175+
{
176+
if (function->ReturnValueOffset != MAX_uint16)
177+
{
178+
// copy value to stack result value
179+
//FMemory::Memcpy(RESULT_PARAM, frame + function->ReturnValueOffset, first_out_prop->ArrayDim * first_out_prop->ElementSize);
180+
}
181+
}
182+
else {
183+
UE_LOG(LogPython, Error, TEXT("Invalid return value type for function %s"), *function->GetFName().ToString());
184+
}
185+
}
122186
}
123187
Py_DECREF(ret);
124188
}

0 commit comments

Comments
 (0)