Skip to content
Open
Prev Previous commit
Next Next commit
misc cleanup
  • Loading branch information
dfb committed Dec 12, 2018
commit f53a8e51c3d5c4aac9c341bf3dbbd5071c9d13f4
16 changes: 7 additions & 9 deletions Source/UnrealEnginePython/Private/PythonFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)

uint8 *frame = Stack.Locals;

// is it a blueprint call ?
if (*Stack.Code == EX_EndFunctionParms) {
if (*Stack.Code == EX_EndFunctionParms)
{ // native call
for (UProperty *prop = (UProperty *)function->Children; prop; prop = (UProperty *)prop->Next) {
if (prop->PropertyFlags & CPF_OutParm)
continue;
Expand All @@ -72,10 +72,8 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
}
}
else
{
//UE_LOG(LogPython, Warning, TEXT("BLUEPRINT CALL"));
// largely copied from ScriptCore.cpp::CallFunction
// for BP calls, we need to set up the FOutParmRec stuff ourselves
{ // blueprint call
// largely copied from ScriptCore.cpp::CallFunction - for BP calls, we need to set up the FOutParmRec stuff ourselves
Stack.OutParms = NULL;
frame = (uint8 *)FMemory_Alloca(function->PropertiesSize);
FMemory::Memzero(frame, function->PropertiesSize);
Expand Down Expand Up @@ -118,7 +116,7 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
return;
}

// get return value and/or any out params - for convenience, if a single item is returned, wrap it in a tuple so that we can process
// get return value and/or any out params - for convenience, if a single item is returned, wrap it in a tuple so that we can process
// multi-out params and single out params with one block of code
bool wrapped_ret = false;
if (!PyTuple_Check(ret))
Expand All @@ -143,14 +141,14 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
UProperty *prop = *It;
PyObject *py_obj = PyTuple_GetItem(ret, tuple_index);
if (prop->PropertyFlags & CPF_ReturnParm)
{ // handle the return value specially by have it write directly to the stack
{ // handle the return value specially by having it write directly to the stack
if (!ue_py_convert_pyobject(py_obj, prop, (uint8*)RESULT_PARAM - prop->GetOffset_ForUFunction(), 0))
{
UE_LOG(LogPython, Error, TEXT("Invalid return value type for function %s"), *function->GetFName().ToString());
}
}
else
{
{ // Find the given FOutParmRec for this property
uint8 *out_frame = frame;
for (FOutParmRec *rec = Stack.OutParms; rec != nullptr; rec = rec->NextOutParm)
{
Expand Down
62 changes: 26 additions & 36 deletions Source/UnrealEnginePython/Private/UEPyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2970,7 +2970,8 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject *

if (num_out_params > 0)
{
// mirror Python function return behavior: 'return x' produces a single object, while 'return x,y' produces a tuple
// mirror normal Python function return behavior in that there is ever only a single return value, and returning multiple items is
// actually achieved by returning a tuple
if (num_out_params > 1)
ret = PyTuple_New(num_out_params);

Expand Down Expand Up @@ -3184,7 +3185,6 @@ UProperty *new_property_from_pyobject(UObject *owner, const char *prop_name, PyO

UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_callable, uint32 function_flags)
{

UFunction *parent_function = u_class->GetSuperClass()->FindFunctionByName(UTF8_TO_TCHAR(name));
// if the function is not available in the parent
// check for name collision
Expand All @@ -3197,26 +3197,6 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
}
}

// note the index of the return param, if any
int return_param_index = -1;
if (parent_function)
{
TFieldIterator<UProperty> It(parent_function);
int cur_index = 0;
while (It)
{
UProperty *p = *It;
if (p->PropertyFlags & CPF_ReturnParm)
{
return_param_index = cur_index;
break;
}
if (p->PropertyFlags & CPF_OutParm)
cur_index++;
++It;
}
}

UPythonFunction *function = NewObject<UPythonFunction>(u_class, UTF8_TO_TCHAR(name), RF_Public | RF_Transient | RF_MarkAsNative);
function->SetPyCallable(py_callable);

Expand Down Expand Up @@ -3294,15 +3274,35 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
}
}

// check for return value
// check for return value (including out params)
if (annotations)
{
PyObject *py_return_value = PyDict_GetItemString(annotations, "return");
if (py_return_value)
{
// in the parent, note the index of the return param, if any, among all out params
int return_param_index = -1;
if (parent_function)
{
TFieldIterator<UProperty> It(parent_function);
int cur_index = 0;
while (It)
{
UProperty *p = *It;
if (p->PropertyFlags & CPF_ReturnParm)
{
return_param_index = cur_index;
break;
}
if (p->PropertyFlags & CPF_OutParm)
cur_index++;
++It;
}
}

if (PyTuple_Check(py_return_value))
{ // some combination of a return value and output params
UE_LOG(LogPython, Warning, TEXT("Multiple return values found"));
//UE_LOG(LogPython, Warning, TEXT("Multiple return values found"));
for (auto i=0; i < PyTuple_Size(py_return_value); i++)
{
PyObject *item = PyTuple_GetItem(py_return_value, i);
Expand All @@ -3329,7 +3329,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
}
else
{ // either a single output param or a single return value
UE_LOG(LogPython, Warning, TEXT("Return value or single output value found"));
//UE_LOG(LogPython, Warning, TEXT("Return value or single output value found"));
FString param_name(return_param_index == -1 ? _T("OutParam0") : _T("ReturnValue"));
UProperty *prop = new_property_from_pyobject(function, TCHAR_TO_UTF8(*param_name), py_return_value);
if (prop)
Expand Down Expand Up @@ -3401,30 +3401,20 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_

// allocate properties storage (ignore super)
TFieldIterator<UProperty> props(function, EFieldIteratorFlags::ExcludeSuper);
int num_out_params = 0;
int num_return_params = 0;
for (; props; ++props)
{
UProperty *p = *props;
if (p->HasAnyPropertyFlags(CPF_Parm))
{
if (p->HasAnyPropertyFlags(CPF_OutParm))
num_out_params++;
function_flags |= FUNC_HasOutParms;
function->NumParms++;
function->ParmsSize = p->GetOffset_ForUFunction() + p->GetSize();
if (p->HasAnyPropertyFlags(CPF_ReturnParm))
{
function->ReturnValueOffset = p->GetOffset_ForUFunction();
num_return_params++;
}
}
}

// UProps have both out + return flags set on the property that is the return value, but a function with a return value but no other
// out properties does not get HasOutParms set.
if (num_out_params > 0) //num_return_params)
function_flags |= FUNC_HasOutParms;

if (parent_function)
{
UE_LOG(LogPython, Warning, TEXT("OVERRIDDEN FUNCTION %s WITH %d PARAMS (size %d) %d"), *function->GetFName().ToString(), function->NumParms, function->ParmsSize, function->PropertiesSize);
Expand Down