static PyObject *py_ue_uscriptstruct_get_field(ue_PyUScriptStruct *self, PyObject * args)
{
	char *name;
	int index = 0;
	if (!PyArg_ParseTuple(args, "s|i:get_field", &name, &index))
	{
		return nullptr;
	}

	UProperty *u_property = self->u_struct->FindPropertyByName(FName(UTF8_TO_TCHAR(name)));
	if (!u_property)
		return PyErr_Format(PyExc_Exception, "unable to find property %s", name);

	return ue_py_convert_property(u_property, self->data, index);
}
static PyObject *ue_PyUScriptStruct_getattro(ue_PyUScriptStruct *self, PyObject *attr_name)
{
	PyObject *ret = PyObject_GenericGetAttr((PyObject *)self, attr_name);
	if (!ret)
	{
		if (PyUnicodeOrString_Check(attr_name))
		{
			char *attr = PyUnicode_AsUTF8(attr_name);
			// first check for property
			UProperty *u_property = get_field_from_name(self->u_struct, attr);
			if (u_property)
			{
				// swallow previous exception
				PyErr_Clear();
				return ue_py_convert_property(u_property, self->data, 0);
			}
		}
	}
	return ret;
}
PyObject *py_ue_uscriptstruct_as_dict(ue_PyUScriptStruct * self, PyObject * args)
{

	PyObject *py_bool = nullptr;
	if (!PyArg_ParseTuple(args, "|O:as_dict", &py_bool))
	{
		return nullptr;
	}

	static const FName DisplayNameKey(TEXT("DisplayName"));

	PyObject *py_struct_dict = PyDict_New();
	TFieldIterator<UProperty> SArgs(self->u_struct);
	for (; SArgs; ++SArgs)
	{
		PyObject *struct_value = ue_py_convert_property(*SArgs, self->data, 0);
		if (!struct_value)
		{
			Py_DECREF(py_struct_dict);
			return NULL;
		}
		FString prop_name = SArgs->GetName();
#if WITH_EDITOR
		if (py_bool && PyObject_IsTrue(py_bool))
		{

			if (SArgs->HasMetaData(DisplayNameKey))
			{
				FString display_name = SArgs->GetMetaData(DisplayNameKey);
				if (display_name.Len() > 0)
					prop_name = display_name;
			}
		}
#endif
		PyDict_SetItemString(py_struct_dict, TCHAR_TO_UTF8(*prop_name), struct_value);
	}
	return py_struct_dict;
}
void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
{

	FScopePythonGIL gil;

	UPythonFunction *function = static_cast<UPythonFunction *>(Stack.CurrentNativeFunction);

	bool on_error = false;
	bool is_static = function->HasAnyFunctionFlags(FUNC_Static);

	// count the number of arguments
	Py_ssize_t argn = (Stack.Object && !is_static) ? 1 : 0;
	TFieldIterator<UProperty> IArgs(function);
	for (; IArgs && ((IArgs->PropertyFlags & (CPF_Parm | CPF_ReturnParm)) == CPF_Parm); ++IArgs) {
		argn++;
	}
#if defined(UEPY_MEMORY_DEBUG)
	UE_LOG(LogPython, Warning, TEXT("Initializing %d parameters"), argn);
#endif
	PyObject *py_args = PyTuple_New(argn);

	if (Stack.Object && !is_static) {
		PyObject *py_obj = (PyObject *)ue_get_python_wrapper(Stack.Object);
		if (!py_obj) {
			unreal_engine_py_log_error();
			on_error = true;
		}
		else {
			Py_INCREF(py_obj);
			PyTuple_SetItem(py_args, 0, py_obj);
		}
	}

	uint8 *frame = Stack.Locals;

	argn = (Stack.Object && !is_static) ? 1 : 0;
	// is it a blueprint call ?
	if (*Stack.Code == EX_EndFunctionParms) {
		for (UProperty *prop = (UProperty *)function->Children; prop; prop = (UProperty *)prop->Next) {
			if (prop->PropertyFlags & CPF_ReturnParm)
				continue;
			if (!on_error) {
				PyObject *arg = ue_py_convert_property(prop, (uint8 *)Stack.Locals);
				if (!arg) {
					unreal_engine_py_log_error();
					on_error = true;
				}
				else {
					PyTuple_SetItem(py_args, argn++, arg);
				}
			}
		}
	}
	else {
		//UE_LOG(LogPython, Warning, TEXT("BLUEPRINT CALL"));
		frame = (uint8 *)FMemory_Alloca(function->PropertiesSize);
		FMemory::Memzero(frame, function->PropertiesSize);
		for (UProperty *prop = (UProperty *)function->Children; *Stack.Code != EX_EndFunctionParms; prop = (UProperty *)prop->Next) {
			Stack.Step(Stack.Object, prop->ContainerPtrToValuePtr<uint8>(frame));
			if (prop->PropertyFlags & CPF_ReturnParm)
				continue;
			if (!on_error) {
				PyObject *arg = ue_py_convert_property(prop, frame);
				if (!arg) {
					unreal_engine_py_log_error();
					on_error = true;
				}
				else {
					PyTuple_SetItem(py_args, argn++, arg);
				}
			}
		}
	}

	Stack.Code++;

	if (on_error || !function->py_callable) {
		Py_DECREF(py_args);
		return;
	}

	PyObject *ret = PyObject_CallObject(function->py_callable, py_args);
	Py_DECREF(py_args);
	if (!ret) {
		unreal_engine_py_log_error();
		return;
	}

	// get return value (if required)
	UProperty *return_property = function->GetReturnProperty();
	if (return_property && function->ReturnValueOffset != MAX_uint16) {
#if defined(UEPY_MEMORY_DEBUG)
		UE_LOG(LogPython, Warning, TEXT("FOUND RETURN VALUE"));
#endif
		if (ue_py_convert_pyobject(ret, return_property, frame)) {
			// copy value to stack result value
			FMemory::Memcpy(RESULT_PARAM, frame + function->ReturnValueOffset, return_property->ArrayDim * return_property->ElementSize);
		}
		else {
			UE_LOG(LogPython, Error, TEXT("Invalid return value type for function %s"), *function->GetFName().ToString());
		}
	}
	Py_DECREF(ret);
}