Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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