@@ -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