Files
UnrealEngine/Engine/Plugins/Experimental/PythonScriptPlugin/Source/PythonScriptPlugin/Private/PyConversion.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

1213 lines
44 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "PyConversion.h"
#include "PyUtil.h"
#include "PyGenUtil.h"
#include "PyPtr.h"
#include "PyWrapperObject.h"
#include "PyWrapperStruct.h"
#include "PyWrapperEnum.h"
#include "PyWrapperDelegate.h"
#include "PyWrapperName.h"
#include "PyWrapperText.h"
#include "PyWrapperArray.h"
#include "PyWrapperFixedArray.h"
#include "PyWrapperSet.h"
#include "PyWrapperMap.h"
#include "PyWrapperFieldPath.h"
#include "PyWrapperTypeRegistry.h"
#include "Templates/Casts.h"
#include "UObject/UnrealType.h"
#include "UObject/EnumProperty.h"
#include "UObject/TextProperty.h"
#include "UObject/PropertyPortFlags.h"
#if WITH_PYTHON
#define PYCONVERSION_RETURN(RESULT, ERROR_CTX, ERROR_MSG) \
{ \
const FPyConversionResult PyConversionReturnResult_Internal = (RESULT); \
if (!PyConversionReturnResult_Internal) \
{ \
if (SetErrorState == ESetErrorState::Yes) \
{ \
PyUtil::SetPythonError(PyExc_TypeError, (ERROR_CTX), (ERROR_MSG)); \
} \
else \
{ \
PyErr_Clear(); \
} \
} \
return PyConversionReturnResult_Internal; \
}
namespace PyConversion
{
namespace Internal
{
FPyConversionResult NativizeStructInstance(PyObject* PyObj, UScriptStruct* StructType, void* StructInstance, const ESetErrorState SetErrorState)
{
FPyConversionResult Result = FPyConversionResult::Failure();
PyTypeObject* PyStructType = FPyWrapperTypeRegistry::Get().GetWrappedStructType(StructType);
FPyWrapperStructPtr PyStruct = FPyWrapperStructPtr::StealReference(FPyWrapperStruct::CastPyObject(PyObj, PyStructType, &Result));
if (PyStruct && ensureAlways(PyStruct->ScriptStruct->IsChildOf(StructType)))
{
StructType->CopyScriptStruct(StructInstance, PyStruct->StructInstance);
}
PYCONVERSION_RETURN(Result, TEXT("NativizeStructInstance"), *FString::Printf(TEXT("Cannot nativize '%s' as '%s'"), *PyUtil::GetFriendlyTypename(PyObj), *PyUtil::GetFriendlyTypename(PyStructType)));
}
FPyConversionResult PythonizeStructInstance(UScriptStruct* StructType, const void* StructInstance, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
OutPyObj = (PyObject*)FPyWrapperStructFactory::Get().CreateInstance(StructType, (void*)StructInstance, FPyWrapperOwnerContext(), EPyConversionMethod::Copy);
return FPyConversionResult::Success();
}
template <typename T>
FPyConversionResult NativizeSigned(PyObject* PyObj, T& OutVal, const ESetErrorState SetErrorState, const TCHAR* InErrorType)
{
// Booleans subclass integer, so exclude those explicitly
if (!PyBool_Check(PyObj))
{
if (PyLong_Check(PyObj))
{
OutVal = PyLong_AsLongLong(PyObj);
return FPyConversionResult::Success();
}
if (PyFloat_Check(PyObj))
{
OutVal = PyFloat_AsDouble(PyObj);
return FPyConversionResult::SuccessWithCoercion();
}
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as '%s'"), *PyUtil::GetFriendlyTypename(PyObj), InErrorType));
}
template <typename T>
FPyConversionResult NativizeUnsigned(PyObject* PyObj, T& OutVal, const ESetErrorState SetErrorState, const TCHAR* InErrorType)
{
// Booleans subclass integer, so exclude those explicitly
if (!PyBool_Check(PyObj))
{
if (PyLong_Check(PyObj))
{
OutVal = PyLong_AsUnsignedLongLong(PyObj);
return FPyConversionResult::Success();
}
if (PyFloat_Check(PyObj))
{
OutVal = PyFloat_AsDouble(PyObj);
return FPyConversionResult::SuccessWithCoercion();
}
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as '%s'"), *PyUtil::GetFriendlyTypename(PyObj), InErrorType));
}
template <typename T>
FPyConversionResult NativizeReal(PyObject* PyObj, T& OutVal, const ESetErrorState SetErrorState, const TCHAR* InErrorType)
{
// Booleans subclass integer, so exclude those explicitly
if (!PyBool_Check(PyObj))
{
if (PyLong_Check(PyObj))
{
OutVal = PyLong_AsDouble(PyObj);
return FPyConversionResult::SuccessWithCoercion();
}
if (PyFloat_Check(PyObj))
{
OutVal = PyFloat_AsDouble(PyObj);
return FPyConversionResult::Success();
}
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as '%s'"), *PyUtil::GetFriendlyTypename(PyObj), InErrorType));
}
template <typename T>
FPyConversionResult PythonizeSigned(const T Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState, const TCHAR* InErrorType)
{
OutPyObj = PyLong_FromLongLong(Val);
return FPyConversionResult::Success();
}
template <typename T>
FPyConversionResult PythonizeUnsigned(const T Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState, const TCHAR* InErrorType)
{
OutPyObj = PyLong_FromUnsignedLongLong(Val);
return FPyConversionResult::Success();
}
template <typename T>
FPyConversionResult PythonizeReal(const T Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState, const TCHAR* InErrorType)
{
OutPyObj = PyFloat_FromDouble(Val);
return FPyConversionResult::Success();
}
} // namespace Internal
FPyConversionResult Nativize(PyObject* PyObj, bool& OutVal, const ESetErrorState SetErrorState)
{
if (PyObj == Py_True)
{
OutVal = true;
return FPyConversionResult::Success();
}
if (PyObj == Py_False)
{
OutVal = false;
return FPyConversionResult::Success();
}
if (PyObj == Py_None)
{
OutVal = false;
return FPyConversionResult::Success();
}
if (PyLong_Check(PyObj))
{
OutVal = PyLong_AsLongLong(PyObj) != 0;
return FPyConversionResult::SuccessWithCoercion();
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as 'bool'"), *PyUtil::GetFriendlyTypename(PyObj)));
}
FPyConversionResult Pythonize(const bool Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
if (Val)
{
Py_INCREF(Py_True);
OutPyObj = Py_True;
}
else
{
Py_INCREF(Py_False);
OutPyObj = Py_False;
}
return FPyConversionResult::Success();
}
FPyConversionResult Nativize(PyObject* PyObj, int8& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeSigned(PyObj, OutVal, SetErrorState, TEXT("int8"));
}
FPyConversionResult Pythonize(const int8 Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeSigned(Val, OutPyObj, SetErrorState, TEXT("int8"));
}
FPyConversionResult Nativize(PyObject* PyObj, uint8& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeUnsigned(PyObj, OutVal, SetErrorState, TEXT("uint8"));
}
FPyConversionResult Pythonize(const uint8 Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeUnsigned(Val, OutPyObj, SetErrorState, TEXT("uint8"));
}
FPyConversionResult Nativize(PyObject* PyObj, int16& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeSigned(PyObj, OutVal, SetErrorState, TEXT("int16"));
}
FPyConversionResult Pythonize(const int16 Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeSigned(Val, OutPyObj, SetErrorState, TEXT("int16"));
}
FPyConversionResult Nativize(PyObject* PyObj, uint16& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeUnsigned(PyObj, OutVal, SetErrorState, TEXT("uint16"));
}
FPyConversionResult Pythonize(const uint16 Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeUnsigned(Val, OutPyObj, SetErrorState, TEXT("uint16"));
}
FPyConversionResult Nativize(PyObject* PyObj, int32& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeSigned(PyObj, OutVal, SetErrorState, TEXT("int32"));
}
FPyConversionResult Pythonize(const int32 Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeSigned(Val, OutPyObj, SetErrorState, TEXT("int32"));
}
FPyConversionResult Nativize(PyObject* PyObj, uint32& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeUnsigned(PyObj, OutVal, SetErrorState, TEXT("uint32"));
}
FPyConversionResult Pythonize(const uint32 Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeUnsigned(Val, OutPyObj, SetErrorState, TEXT("uint32"));
}
FPyConversionResult Nativize(PyObject* PyObj, int64& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeSigned(PyObj, OutVal, SetErrorState, TEXT("int64"));
}
FPyConversionResult Pythonize(const int64 Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeSigned(Val, OutPyObj, SetErrorState, TEXT("int64"));
}
FPyConversionResult Nativize(PyObject* PyObj, uint64& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeUnsigned(PyObj, OutVal, SetErrorState, TEXT("uint64"));
}
FPyConversionResult Pythonize(const uint64 Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeUnsigned(Val, OutPyObj, SetErrorState, TEXT("uint64"));
}
FPyConversionResult Nativize(PyObject* PyObj, float& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeReal(PyObj, OutVal, SetErrorState, TEXT("float"));
}
FPyConversionResult Pythonize(const float Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeReal(Val, OutPyObj, SetErrorState, TEXT("float"));
}
FPyConversionResult Nativize(PyObject* PyObj, double& OutVal, const ESetErrorState SetErrorState)
{
return Internal::NativizeReal(PyObj, OutVal, SetErrorState, TEXT("double"));
}
FPyConversionResult Pythonize(const double Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return Internal::PythonizeReal(Val, OutPyObj, SetErrorState, TEXT("double"));
}
FPyConversionResult Nativize(PyObject* PyObj, FString& OutVal, const ESetErrorState SetErrorState)
{
if (PyUnicode_Check(PyObj))
{
if (const char* PyUtf8Buffer = PyUnicode_AsUTF8(PyObj))
{
OutVal = UTF8_TO_TCHAR(PyUtf8Buffer);
return FPyConversionResult::Success();
}
}
if (PyObject_IsInstance(PyObj, (PyObject*)&PyWrapperNameType) == 1)
{
FPyWrapperName* PyWrappedName = (FPyWrapperName*)PyObj;
OutVal = PyWrappedName->Value.ToString();
return FPyConversionResult::SuccessWithCoercion();
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as 'String'"), *PyUtil::GetFriendlyTypename(PyObj)));
}
FPyConversionResult Pythonize(const FString& Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
OutPyObj = PyUnicode_FromString(TCHAR_TO_UTF8(*Val));
return FPyConversionResult::Success();
}
FPyConversionResult Nativize(PyObject* PyObj, FName& OutVal, const ESetErrorState SetErrorState)
{
if (PyObject_IsInstance(PyObj, (PyObject*)&PyWrapperNameType) == 1)
{
FPyWrapperName* PyWrappedName = (FPyWrapperName*)PyObj;
OutVal = PyWrappedName->Value;
return FPyConversionResult::Success();
}
FString NameStr;
if (Nativize(PyObj, NameStr, ESetErrorState::No))
{
if (NameStr.Len() >= NAME_SIZE)
{
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as 'Name' (lenth: %d, max length: %d)"), *PyUtil::GetFriendlyTypename(PyObj), NameStr.Len(), NAME_SIZE - 1));
}
OutVal = *NameStr;
return FPyConversionResult::SuccessWithCoercion();
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as 'Name'"), *PyUtil::GetFriendlyTypename(PyObj)));
}
FPyConversionResult Pythonize(const FName& Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
OutPyObj = (PyObject*)FPyWrapperNameFactory::Get().CreateInstance(Val);
return FPyConversionResult::Success();
}
FPyConversionResult Nativize(PyObject* PyObj, FText& OutVal, const ESetErrorState SetErrorState)
{
if (PyObject_IsInstance(PyObj, (PyObject*)&PyWrapperTextType) == 1)
{
FPyWrapperText* PyWrappedText = (FPyWrapperText*)PyObj;
OutVal = PyWrappedText->Value;
return FPyConversionResult::Success();
}
FString TextStr;
if (Nativize(PyObj, TextStr, ESetErrorState::No))
{
OutVal = FText::AsCultureInvariant(TextStr);
return FPyConversionResult::SuccessWithCoercion();
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as 'Text'"), *PyUtil::GetFriendlyTypename(PyObj)));
}
FPyConversionResult Pythonize(const FText& Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
OutPyObj = (PyObject*)FPyWrapperTextFactory::Get().CreateInstance(Val);
return FPyConversionResult::Success();
}
FPyConversionResult Nativize(PyObject* PyObj, FFieldPath& OutVal, const ESetErrorState SetErrorState)
{
if (PyObject_IsInstance(PyObj, (PyObject*)&PyWrapperFieldPathType) == 1)
{
FPyWrapperFieldPath* PyWrappedFieldPath = (FPyWrapperFieldPath*)PyObj;
OutVal = PyWrappedFieldPath->Value;
return FPyConversionResult::Success();
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as 'FieldPath'"), *PyUtil::GetFriendlyTypename(PyObj)));
}
FPyConversionResult Pythonize(const FFieldPath& Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
OutPyObj = (PyObject*)FPyWrapperFieldPathFactory::Get().CreateInstance(Val);
return FPyConversionResult::Success();
}
FPyConversionResult Nativize(PyObject* PyObj, void*& OutVal, const ESetErrorState SetErrorState)
{
// CObject was removed in Python 3.2
#if !(PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 2)
if (PyCObject_Check(PyObj))
{
OutVal = PyCObject_AsVoidPtr(PyObj);
return FPyConversionResult::Success();
}
#endif // !(PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 2)
// Capsule was added in Python 2.7 and 3.1
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 1
if (PyCapsule_CheckExact(PyObj))
{
OutVal = PyCapsule_GetPointer(PyObj, PyCapsule_GetName(PyObj));
return FPyConversionResult::Success();
}
#endif // PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 1
if (PyObj == Py_None)
{
OutVal = nullptr;
return FPyConversionResult::Success();
}
{
uint64 PtrValue = 0;
if (PyConversion::Nativize(PyObj, PtrValue, ESetErrorState::No))
{
OutVal = (void*)PtrValue;
return FPyConversionResult::SuccessWithCoercion();
}
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("Nativize"), *FString::Printf(TEXT("Cannot nativize '%s' as 'void*'"), *PyUtil::GetFriendlyTypename(PyObj)));
}
FPyConversionResult Pythonize(void* Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
if (Val)
{
// Use Capsule for Python 3.1+, and CObject for older versions
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 1
OutPyObj = PyCapsule_New(Val, nullptr, nullptr);
#else // PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 1
OutPyObj = PyCObject_FromVoidPtr(Val, nullptr);
#endif // PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 1
}
else
{
Py_INCREF(Py_None);
OutPyObj = Py_None;
}
return FPyConversionResult::Success();
}
FPyConversionResult Nativize(PyObject* PyObj, UObject*& OutVal, const ESetErrorState SetErrorState)
{
return NativizeObject(PyObj, OutVal, UObject::StaticClass(), SetErrorState);
}
FPyConversionResult Pythonize(UObject* Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return PythonizeObject(Val, OutPyObj, SetErrorState);
}
FPyConversionResult NativizeObject(PyObject* PyObj, UObject*& OutVal, UClass* ExpectedType, const ESetErrorState SetErrorState)
{
auto IsObjectExpectedType = [ExpectedType](const UObject* ObjectInstance) -> bool
{
if (!ExpectedType)
{
return true;
}
return ExpectedType->HasAnyClassFlags(CLASS_Interface)
? ObjectInstance->GetClass()->ImplementsInterface(ExpectedType)
: ObjectInstance->IsA(ExpectedType);
};
if (PyObject_IsInstance(PyObj, (PyObject*)&PyWrapperObjectType) == 1)
{
FPyWrapperObject* PyWrappedObj = (FPyWrapperObject*)PyObj;
if (FPyWrapperObject::ValidateInternalState(PyWrappedObj) && IsObjectExpectedType(PyWrappedObj->ObjectInstance))
{
OutVal = PyWrappedObj->ObjectInstance;
return FPyConversionResult::Success();
}
}
if (PyObj == Py_None)
{
OutVal = nullptr;
return FPyConversionResult::Success();
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("NativizeObject"), *FString::Printf(TEXT("Cannot nativize '%s' as 'Object' (allowed Class type: '%s')"), *PyUtil::GetFriendlyTypename(PyObj), ExpectedType ? *ExpectedType->GetName() : TEXT("<any>")));
}
FPyConversionResult PythonizeObject(UObject* Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
if (Val)
{
OutPyObj = (PyObject*)FPyWrapperObjectFactory::Get().CreateInstance(Val);
}
else
{
Py_INCREF(Py_None);
OutPyObj = Py_None;
}
return FPyConversionResult::Success();
}
PyObject* PythonizeObject(UObject* Val, const ESetErrorState SetErrorState)
{
PyObject* Obj = nullptr;
PythonizeObject(Val, Obj, SetErrorState);
return Obj;
}
FPyConversionResult NativizeClass(PyObject* PyObj, UClass*& OutVal, UClass* ExpectedType, const ESetErrorState SetErrorState)
{
UClass* Class = nullptr;
if (PyType_Check(PyObj) && PyType_IsSubtype((PyTypeObject*)PyObj, &PyWrapperObjectType))
{
Class = FPyWrapperObjectMetaData::GetClass((PyTypeObject*)PyObj);
}
if (Class || NativizeObject(PyObj, (UObject*&)Class, UClass::StaticClass(), SetErrorState))
{
if (!Class || !ExpectedType || Class->IsChildOf(ExpectedType))
{
OutVal = Class;
return FPyConversionResult::Success();
}
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("NativizeClass"), *FString::Printf(TEXT("Cannot nativize '%s' as 'Class' (allowed Class type: '%s')"), *PyUtil::GetFriendlyTypename(PyObj), ExpectedType ? *ExpectedType->GetName() : TEXT("<any>")));
}
FPyConversionResult PythonizeClass(UClass* Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return PythonizeObject(Val, OutPyObj, SetErrorState);
}
PyObject* PythonizeClass(UClass* Val, const ESetErrorState SetErrorState)
{
PyObject* Obj = nullptr;
PythonizeClass(Val, Obj, SetErrorState);
return Obj;
}
FPyConversionResult NativizeStruct(PyObject* PyObj, UScriptStruct*& OutVal, UScriptStruct* ExpectedType, const ESetErrorState SetErrorState)
{
UScriptStruct* Struct = nullptr;
if (PyType_Check(PyObj) && PyType_IsSubtype((PyTypeObject*)PyObj, &PyWrapperStructType))
{
Struct = FPyWrapperStructMetaData::GetStruct((PyTypeObject*)PyObj);
}
if (Struct || NativizeObject(PyObj, (UObject*&)Struct, UScriptStruct::StaticClass(), SetErrorState))
{
if (!Struct || !ExpectedType || Struct->IsChildOf(ExpectedType))
{
OutVal = Struct;
return FPyConversionResult::Success();
}
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("NativizeStruct"), *FString::Printf(TEXT("Cannot nativize '%s' as 'Struct' (allowed Struct type: '%s')"), *PyUtil::GetFriendlyTypename(PyObj), ExpectedType ? *ExpectedType->GetName() : TEXT("<any>")));
}
FPyConversionResult PythonizeStruct(UScriptStruct* Val, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
return PythonizeObject(Val, OutPyObj, SetErrorState);
}
PyObject* PythonizeStruct(UScriptStruct* Val, const ESetErrorState SetErrorState)
{
PyObject* Obj = nullptr;
PythonizeStruct(Val, Obj, SetErrorState);
return Obj;
}
void EnsureWrappedBlueprintEnumType(const UEnum* EnumType)
{
if (PyGenUtil::IsBlueprintGeneratedEnum(EnumType))
{
FPyWrapperTypeRegistry& PyWrapperTypeRegistry = FPyWrapperTypeRegistry::Get();
FPyWrapperTypeRegistry::FGeneratedWrappedTypeReferences GeneratedWrappedTypeReferences;
TSet<FName> DirtyModules;
PyWrapperTypeRegistry.GenerateWrappedTypeForObject(EnumType, GeneratedWrappedTypeReferences, DirtyModules, EPyTypeGenerationFlags::IncludeBlueprintGeneratedTypes);
PyWrapperTypeRegistry.GenerateWrappedTypesForReferences(GeneratedWrappedTypeReferences, DirtyModules);
PyWrapperTypeRegistry.NotifyModulesDirtied(DirtyModules);
}
}
FPyConversionResult NativizeEnumEntry(PyObject* PyObj, const UEnum* EnumType, int64& OutVal, const ESetErrorState SetErrorState)
{
FPyConversionResult Result = FPyConversionResult::Failure();
EnsureWrappedBlueprintEnumType(EnumType);
PyTypeObject* PyEnumType = FPyWrapperTypeRegistry::Get().GetWrappedEnumType(EnumType);
FPyWrapperEnumPtr PyEnum = FPyWrapperEnumPtr::StealReference(FPyWrapperEnum::CastPyObject(PyObj, PyEnumType, &Result));
if (PyEnum)
{
OutVal = FPyWrapperEnum::GetEnumEntryValue(PyEnum);
}
PYCONVERSION_RETURN(Result, TEXT("NativizeEnumEntry"), *FString::Printf(TEXT("Cannot nativize '%s' as '%s'"), *PyUtil::GetFriendlyTypename(PyObj), *PyUtil::GetFriendlyTypename(PyEnumType)));
}
FPyConversionResult PythonizeEnumEntry(const int64 Val, const UEnum* EnumType, PyObject*& OutPyObj, const ESetErrorState SetErrorState)
{
EnsureWrappedBlueprintEnumType(EnumType);
PyTypeObject* PyEnumType = FPyWrapperTypeRegistry::Get().GetWrappedEnumType(EnumType);
if (const FPyWrapperEnumMetaData* PyEnumMetaData = FPyWrapperEnumMetaData::GetMetaData(PyEnumType))
{
// Find an enum entry using this value
for (FPyWrapperEnum* PyEnumEntry : PyEnumMetaData->EnumEntries)
{
const int64 EnumEntryVal = FPyWrapperEnum::GetEnumEntryValue(PyEnumEntry);
if (EnumEntryVal == Val)
{
Py_INCREF(PyEnumEntry);
OutPyObj = (PyObject*)PyEnumEntry;
return FPyConversionResult::Success();
}
}
}
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("PythonizeEnumEntry"), *FString::Printf(TEXT("Cannot pythonize '%" INT64_FMT "' (int64) as '%s'"), Val, *PyUtil::GetFriendlyTypename(PyEnumType)));
}
PyObject* PythonizeEnumEntry(const int64 Val, const UEnum* EnumType, const ESetErrorState SetErrorState)
{
PyObject* Obj = nullptr;
PythonizeEnumEntry(Val, EnumType, Obj, SetErrorState);
return Obj;
}
FPyConversionResult NativizeProperty(PyObject* PyObj, const FProperty* Prop, void* ValueAddr, const TConstArrayView<void*>& InArchetypeInstValueAddrs, const FPropertyAccessChangeNotify* InChangeNotify, const ESetErrorState SetErrorState)
{
#define PYCONVERSION_PROPERTY_RETURN(RESULT) \
PYCONVERSION_RETURN(RESULT, TEXT("NativizeProperty"), *FString::Printf(TEXT("Cannot nativize '%s' as '%s' (%s)"), *PyUtil::GetFriendlyTypename(PyObj), *Prop->GetName(), *Prop->GetClass()->GetName()))
if (Prop->ArrayDim > 1)
{
FPyWrapperFixedArrayPtr PyFixedArray = FPyWrapperFixedArrayPtr::StealReference(FPyWrapperFixedArray::CastPyObject(PyObj, &PyWrapperFixedArrayType, Prop));
if (PyFixedArray)
{
EmitPropertyChangeNotifications(InChangeNotify, /*bIdenticalValue*/false, [&]()
{
const int32 ArrSize = FMath::Min(Prop->ArrayDim, PyFixedArray->ArrayProp->ArrayDim);
for (int32 ArrIndex = 0; ArrIndex < ArrSize; ++ArrIndex)
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
Prop->CopySingleValue(static_cast<uint8*>(ArchInstValueAddr) + (Prop->GetElementSize() * ArrIndex), FPyWrapperFixedArray::GetItemPtr(PyFixedArray, ArrIndex));
}
Prop->CopySingleValue(static_cast<uint8*>(ValueAddr) + (Prop->GetElementSize() * ArrIndex), FPyWrapperFixedArray::GetItemPtr(PyFixedArray, ArrIndex));
}
});
return FPyConversionResult::Success();
}
PYCONVERSION_PROPERTY_RETURN(FPyConversionResult::Failure());
}
return NativizeProperty_Direct(PyObj, Prop, ValueAddr, InArchetypeInstValueAddrs, InChangeNotify, SetErrorState);
#undef PYCONVERSION_PROPERTY_RETURN
}
FPyConversionResult PythonizeProperty(const FProperty* Prop, const void* ValueAddr, PyObject*& OutPyObj, const EPyConversionMethod ConversionMethod, PyObject* OwnerPyObj, const ESetErrorState SetErrorState)
{
if (Prop->ArrayDim > 1)
{
OutPyObj = (PyObject*)FPyWrapperFixedArrayFactory::Get().CreateInstance((void*)ValueAddr, Prop, FPyWrapperOwnerContext(OwnerPyObj, OwnerPyObj ? Prop : nullptr), ConversionMethod);
return FPyConversionResult::Success();
}
return PythonizeProperty_Direct(Prop, ValueAddr, OutPyObj, ConversionMethod, OwnerPyObj, SetErrorState);
}
FPyConversionResult NativizeProperty_Direct(PyObject* PyObj, const FProperty* Prop, void* ValueAddr, const TConstArrayView<void*>& InArchetypeInstValueAddrs, const FPropertyAccessChangeNotify* InChangeNotify, const ESetErrorState SetErrorState)
{
#define PYCONVERSION_PROPERTY_RETURN(RESULT) \
PYCONVERSION_RETURN(RESULT, TEXT("NativizeProperty"), *FString::Printf(TEXT("Cannot nativize '%s' as '%s' (%s)"), *PyUtil::GetFriendlyTypename(PyObj), *Prop->GetName(), *Prop->GetClass()->GetName()))
#define NATIVIZE_SETTER_PROPERTY(PROPTYPE) \
if (const PROPTYPE* CastProp = CastField<PROPTYPE>(Prop)) \
{ \
PROPTYPE::TCppType NewValue; \
const FPyConversionResult Result = Nativize(PyObj, NewValue, SetErrorState);\
if (Result) \
{ \
auto OldValue = CastProp->GetPropertyValue(ValueAddr); \
EmitPropertyChangeNotifications(InChangeNotify, \
OldValue == NewValue, [&]() \
{ \
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs) \
{ \
CastProp->SetPropertyValue(ArchInstValueAddr, NewValue); \
} \
CastProp->SetPropertyValue(ValueAddr, NewValue); \
}); \
} \
PYCONVERSION_PROPERTY_RETURN(Result); \
}
#define NATIVIZE_INLINE_PROPERTY(PROPTYPE) \
if (const PROPTYPE* CastProp = CastField<PROPTYPE>(Prop)) \
{ \
PROPTYPE::TCppType NewValue; \
const FPyConversionResult Result = Nativize(PyObj, NewValue, SetErrorState);\
if (Result) \
{ \
auto* ValuePtr = static_cast<PROPTYPE::TCppType*>(ValueAddr); \
EmitPropertyChangeNotifications(InChangeNotify, \
CastProp->Identical(ValuePtr, &NewValue, PPF_None), [&]() \
{ \
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs) \
{ \
auto* ArchInstValuePtr = static_cast<PROPTYPE::TCppType*>(ArchInstValueAddr); \
*ArchInstValuePtr = NewValue; \
} \
*ValuePtr = MoveTemp(NewValue); \
}); \
} \
PYCONVERSION_PROPERTY_RETURN(Result); \
}
NATIVIZE_SETTER_PROPERTY(FBoolProperty);
NATIVIZE_INLINE_PROPERTY(FInt8Property);
NATIVIZE_INLINE_PROPERTY(FInt16Property);
NATIVIZE_INLINE_PROPERTY(FUInt16Property);
NATIVIZE_INLINE_PROPERTY(FIntProperty);
NATIVIZE_INLINE_PROPERTY(FUInt32Property);
NATIVIZE_INLINE_PROPERTY(FInt64Property);
NATIVIZE_INLINE_PROPERTY(FUInt64Property);
NATIVIZE_INLINE_PROPERTY(FFloatProperty);
NATIVIZE_INLINE_PROPERTY(FDoubleProperty);
NATIVIZE_INLINE_PROPERTY(FStrProperty);
NATIVIZE_INLINE_PROPERTY(FNameProperty);
NATIVIZE_INLINE_PROPERTY(FTextProperty);
NATIVIZE_INLINE_PROPERTY(FFieldPathProperty);
if (const FByteProperty* CastProp = CastField<FByteProperty>(Prop))
{
uint8 NewValue = 0;
FPyConversionResult Result = FPyConversionResult::Failure();
if (CastProp->Enum)
{
int64 EnumVal = 0;
Result = NativizeEnumEntry(PyObj, CastProp->Enum, EnumVal, SetErrorState);
if (Result.GetState() == EPyConversionResultState::SuccessWithCoercion)
{
// Don't allow implicit conversion on enum properties
Result.SetState(EPyConversionResultState::Failure);
}
if (Result)
{
NewValue = (uint8)EnumVal;
}
}
else
{
Result = Nativize(PyObj, NewValue, SetErrorState);
}
if (Result)
{
auto* ValuePtr = static_cast<uint8*>(ValueAddr);
EmitPropertyChangeNotifications(InChangeNotify, *ValuePtr == NewValue, [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
auto* InstValuePtr = static_cast<uint8*>(ArchInstValueAddr);
*InstValuePtr = NewValue;
}
*ValuePtr = NewValue;
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FEnumProperty* CastProp = CastField<FEnumProperty>(Prop))
{
FPyConversionResult Result = FPyConversionResult::Failure();
FNumericProperty* EnumInternalProp = CastProp->GetUnderlyingProperty();
if (EnumInternalProp)
{
int64 NewValue = 0;
Result = NativizeEnumEntry(PyObj, CastProp->GetEnum(), NewValue, SetErrorState);
if (Result.GetState() == EPyConversionResultState::SuccessWithCoercion)
{
// Don't allow implicit conversion on enum properties
Result.SetState(EPyConversionResultState::Failure);
}
if (Result)
{
const int64 OldValue = EnumInternalProp->GetSignedIntPropertyValue(ValueAddr);
EmitPropertyChangeNotifications(InChangeNotify, OldValue == NewValue, [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
EnumInternalProp->SetIntPropertyValue(ArchInstValueAddr, NewValue);
}
EnumInternalProp->SetIntPropertyValue(ValueAddr, NewValue);
});
}
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FClassProperty* CastProp = CastField<FClassProperty>(Prop))
{
UClass* NewValue = nullptr;
const FPyConversionResult Result = NativizeClass(PyObj, NewValue, CastProp->MetaClass, SetErrorState);
if (Result)
{
UObject* OldValue = CastProp->GetObjectPropertyValue(ValueAddr);
EmitPropertyChangeNotifications(InChangeNotify, OldValue == NewValue, [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->SetPropertyValue(ArchInstValueAddr, NewValue);
}
CastProp->SetObjectPropertyValue(ValueAddr, NewValue);
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FSoftClassProperty* CastProp = CastField<FSoftClassProperty>(Prop))
{
UClass* NewValue = nullptr;
const FPyConversionResult Result = NativizeClass(PyObj, NewValue, CastProp->MetaClass, SetErrorState);
if (Result)
{
UObject* OldValue = CastProp->GetObjectPropertyValue(ValueAddr);
EmitPropertyChangeNotifications(InChangeNotify, OldValue == NewValue, [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->SetObjectPropertyValue(ArchInstValueAddr, NewValue);
}
CastProp->SetObjectPropertyValue(ValueAddr, NewValue);
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FObjectPropertyBase* CastProp = CastField<FObjectPropertyBase>(Prop))
{
UObject* NewValue = nullptr;
const FPyConversionResult Result = NativizeObject(PyObj, NewValue, CastProp->PropertyClass, SetErrorState);
if (Result)
{
UObject* OldValue = CastProp->GetObjectPropertyValue(ValueAddr);
EmitPropertyChangeNotifications(InChangeNotify, OldValue == NewValue, [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->SetObjectPropertyValue(ArchInstValueAddr, NewValue);
}
CastProp->SetObjectPropertyValue(ValueAddr, NewValue);
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FInterfaceProperty* CastProp = CastField<FInterfaceProperty>(Prop))
{
UObject* NewValue = nullptr;
const FPyConversionResult Result = NativizeObject(PyObj, NewValue, CastProp->InterfaceClass, SetErrorState);
if (Result)
{
UObject* OldValue = CastProp->GetPropertyValue(ValueAddr).GetObject();
EmitPropertyChangeNotifications(InChangeNotify, OldValue == NewValue, [&]()
{
const FScriptInterface ScriptInterface = FScriptInterface(NewValue, NewValue ? NewValue->GetInterfaceAddress(CastProp->InterfaceClass) : nullptr);
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->SetPropertyValue(ArchInstValueAddr, ScriptInterface);
}
CastProp->SetPropertyValue(ValueAddr, ScriptInterface);
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FStructProperty* CastProp = CastField<FStructProperty>(Prop))
{
FPyConversionResult Result = FPyConversionResult::Failure();
PyTypeObject* PyStructType = FPyWrapperTypeRegistry::Get().GetWrappedStructType(CastProp->Struct);
FPyWrapperStructPtr PyStruct = FPyWrapperStructPtr::StealReference(FPyWrapperStruct::CastPyObject(PyObj, PyStructType, &Result));
if (PyStruct && ensureAlways(PyStruct->ScriptStruct->IsChildOf(CastProp->Struct)))
{
EmitPropertyChangeNotifications(InChangeNotify, CastProp->Identical(ValueAddr, PyStruct->StructInstance, PPF_None), [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->Struct->CopyScriptStruct(ArchInstValueAddr, PyStruct->StructInstance);
}
CastProp->Struct->CopyScriptStruct(ValueAddr, PyStruct->StructInstance);
});
}
else
{
// Extra function scope as we don't want PYCONVERSION_RETURN to early return and skip the PYCONVERSION_PROPERTY_RETURN below
[&]()
{
PYCONVERSION_RETURN(Result, TEXT("NativizeStructInstance"), *FString::Printf(TEXT("Cannot nativize '%s' as '%s'"), *PyUtil::GetFriendlyTypename(PyObj), *PyUtil::GetFriendlyTypename(PyStructType)));
}();
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FDelegateProperty* CastProp = CastField<FDelegateProperty>(Prop))
{
FPyConversionResult Result = FPyConversionResult::Failure();
PyTypeObject* PyDelegateType = FPyWrapperTypeRegistry::Get().GetWrappedDelegateType(CastProp->SignatureFunction);
FPyWrapperDelegatePtr PyDelegate = FPyWrapperDelegatePtr::StealReference(FPyWrapperDelegate::CastPyObject(PyObj, PyDelegateType, &Result));
if (PyDelegate)
{
EmitPropertyChangeNotifications(InChangeNotify, CastProp->Identical(ValueAddr, PyDelegate->DelegateInstance, PPF_None), [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->SetPropertyValue(ArchInstValueAddr, *PyDelegate->DelegateInstance);
}
CastProp->SetPropertyValue(ValueAddr, *PyDelegate->DelegateInstance);
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FMulticastDelegateProperty* CastProp = CastField<FMulticastDelegateProperty>(Prop))
{
FPyConversionResult Result = FPyConversionResult::Failure();
PyTypeObject* PyDelegateType = FPyWrapperTypeRegistry::Get().GetWrappedDelegateType(CastProp->SignatureFunction);
FPyWrapperMulticastDelegatePtr PyDelegate = FPyWrapperMulticastDelegatePtr::StealReference(FPyWrapperMulticastDelegate::CastPyObject(PyObj, PyDelegateType, &Result));
if (PyDelegate)
{
EmitPropertyChangeNotifications(InChangeNotify, CastProp->Identical(ValueAddr, PyDelegate->DelegateInstance, PPF_None), [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->SetMulticastDelegate(ArchInstValueAddr, *PyDelegate->DelegateInstance);
}
CastProp->SetMulticastDelegate(ValueAddr, *PyDelegate->DelegateInstance);
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FArrayProperty* CastProp = CastField<FArrayProperty>(Prop))
{
FPyConversionResult Result = FPyConversionResult::Failure();
FPyWrapperArrayPtr PyArray = FPyWrapperArrayPtr::StealReference(FPyWrapperArray::CastPyObject(PyObj, &PyWrapperArrayType, CastProp->Inner, &Result));
if (PyArray)
{
EmitPropertyChangeNotifications(InChangeNotify, CastProp->Identical(ValueAddr, PyArray->ArrayInstance, PPF_None), [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->CopySingleValue(ArchInstValueAddr, PyArray->ArrayInstance);
}
CastProp->CopySingleValue(ValueAddr, PyArray->ArrayInstance);
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FSetProperty* CastProp = CastField<FSetProperty>(Prop))
{
FPyConversionResult Result = FPyConversionResult::Failure();
FPyWrapperSetPtr PySet = FPyWrapperSetPtr::StealReference(FPyWrapperSet::CastPyObject(PyObj, &PyWrapperSetType, CastProp->ElementProp, &Result));
if (PySet)
{
EmitPropertyChangeNotifications(InChangeNotify, CastProp->Identical(ValueAddr, PySet->SetInstance, PPF_None), [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->CopySingleValue(ArchInstValueAddr, PySet->SetInstance);
}
CastProp->CopySingleValue(ValueAddr, PySet->SetInstance);
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
if (const FMapProperty* CastProp = CastField<FMapProperty>(Prop))
{
FPyConversionResult Result = FPyConversionResult::Failure();
FPyWrapperMapPtr PyMap = FPyWrapperMapPtr::StealReference(FPyWrapperMap::CastPyObject(PyObj, &PyWrapperMapType, CastProp->KeyProp, CastProp->ValueProp, &Result));
if (PyMap)
{
EmitPropertyChangeNotifications(InChangeNotify, CastProp->Identical(ValueAddr, PyMap->MapInstance, PPF_None), [&]()
{
for (void* ArchInstValueAddr : InArchetypeInstValueAddrs)
{
CastProp->CopySingleValue(ArchInstValueAddr, PyMap->MapInstance);
}
CastProp->CopySingleValue(ValueAddr, PyMap->MapInstance);
});
}
PYCONVERSION_PROPERTY_RETURN(Result);
}
#undef NATIVIZE_SETTER_PROPERTY
#undef NATIVIZE_INLINE_PROPERTY
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("NativizeProperty"), *FString::Printf(TEXT("Cannot nativize '%s' as '%s' (%s). %s conversion not implemented!"), *PyUtil::GetFriendlyTypename(PyObj), *Prop->GetName(), *Prop->GetClass()->GetName(), *Prop->GetClass()->GetName()));
#undef PYCONVERSION_PROPERTY_RETURN
}
FPyConversionResult PythonizeProperty_Direct(const FProperty* Prop, const void* ValueAddr, PyObject*& OutPyObj, const EPyConversionMethod ConversionMethod, PyObject* OwnerPyObj, const ESetErrorState SetErrorState)
{
#define PYCONVERSION_PROPERTY_RETURN(RESULT) \
PYCONVERSION_RETURN(RESULT, TEXT("PythonizeProperty"), *FString::Printf(TEXT("Cannot pythonize '%s' (%s)"), *Prop->GetName(), *Prop->GetClass()->GetName()))
const FPyWrapperOwnerContext OwnerContext(OwnerPyObj, OwnerPyObj ? Prop : nullptr);
OwnerContext.AssertValidConversionMethod(ConversionMethod);
#define PYTHONIZE_GETTER_PROPERTY(PROPTYPE) \
if (const PROPTYPE* CastProp = CastField<PROPTYPE>(Prop)) \
{ \
auto&& Value = CastProp->GetPropertyValue(ValueAddr); \
PYCONVERSION_PROPERTY_RETURN(Pythonize(Value, OutPyObj, SetErrorState)); \
}
PYTHONIZE_GETTER_PROPERTY(FBoolProperty);
PYTHONIZE_GETTER_PROPERTY(FInt8Property);
PYTHONIZE_GETTER_PROPERTY(FInt16Property);
PYTHONIZE_GETTER_PROPERTY(FUInt16Property);
PYTHONIZE_GETTER_PROPERTY(FIntProperty);
PYTHONIZE_GETTER_PROPERTY(FUInt32Property);
PYTHONIZE_GETTER_PROPERTY(FInt64Property);
PYTHONIZE_GETTER_PROPERTY(FUInt64Property);
PYTHONIZE_GETTER_PROPERTY(FFloatProperty);
PYTHONIZE_GETTER_PROPERTY(FDoubleProperty);
PYTHONIZE_GETTER_PROPERTY(FStrProperty);
PYTHONIZE_GETTER_PROPERTY(FNameProperty);
PYTHONIZE_GETTER_PROPERTY(FTextProperty);
PYTHONIZE_GETTER_PROPERTY(FFieldPathProperty);
if (const FByteProperty* CastProp = CastField<FByteProperty>(Prop))
{
const uint8 Value = CastProp->GetPropertyValue(ValueAddr);
if (CastProp->Enum)
{
PYCONVERSION_PROPERTY_RETURN(PythonizeEnumEntry((int64)Value, CastProp->Enum, OutPyObj, SetErrorState));
}
else
{
PYCONVERSION_PROPERTY_RETURN(Pythonize(Value, OutPyObj, SetErrorState));
}
}
if (const FEnumProperty* CastProp = CastField<FEnumProperty>(Prop))
{
FNumericProperty* EnumInternalProp = CastProp->GetUnderlyingProperty();
PYCONVERSION_PROPERTY_RETURN(PythonizeEnumEntry(EnumInternalProp ? EnumInternalProp->GetSignedIntPropertyValue(ValueAddr) : 0, CastProp->GetEnum(), OutPyObj, SetErrorState));
}
if (const FClassProperty* CastProp = CastField<FClassProperty>(Prop))
{
UClass* Value = Cast<UClass>(CastProp->LoadObjectPropertyValue(ValueAddr));
PYCONVERSION_PROPERTY_RETURN(PythonizeClass(Value, OutPyObj, SetErrorState));
}
if (const FSoftClassProperty* CastProp = CastField<FSoftClassProperty>(Prop))
{
UClass* Value = Cast<UClass>(CastProp->LoadObjectPropertyValue(ValueAddr));
PYCONVERSION_PROPERTY_RETURN(PythonizeClass(Value, OutPyObj, SetErrorState));
}
if (const FObjectPropertyBase* CastProp = CastField<FObjectPropertyBase>(Prop))
{
UObject* Value = CastProp->LoadObjectPropertyValue(ValueAddr);
PYCONVERSION_PROPERTY_RETURN(Pythonize(Value, OutPyObj, SetErrorState));
}
if (const FInterfaceProperty* CastProp = CastField<FInterfaceProperty>(Prop))
{
UObject* Value = CastProp->GetPropertyValue(ValueAddr).GetObject();
if (Value)
{
OutPyObj = (PyObject*)FPyWrapperObjectFactory::Get().CreateInstance(CastProp->InterfaceClass, Value);
}
else
{
Py_INCREF(Py_None);
OutPyObj = Py_None;
}
return FPyConversionResult::Success();
}
if (const FStructProperty* CastProp = CastField<FStructProperty>(Prop))
{
OutPyObj = (PyObject*)FPyWrapperStructFactory::Get().CreateInstance(CastProp->Struct, (void*)ValueAddr, OwnerContext, ConversionMethod);
return FPyConversionResult::Success();
}
if (const FDelegateProperty* CastProp = CastField<FDelegateProperty>(Prop))
{
const FScriptDelegate* Value = CastProp->GetPropertyValuePtr(ValueAddr);
OutPyObj = (PyObject*)FPyWrapperDelegateFactory::Get().CreateInstance(CastProp->SignatureFunction, (FScriptDelegate*)Value, OwnerContext, ConversionMethod);
return FPyConversionResult::Success();
}
if (const FMulticastDelegateProperty* CastProp = CastField<FMulticastDelegateProperty>(Prop))
{
const FMulticastScriptDelegate* Value = CastProp->GetMulticastDelegate(ValueAddr);
OutPyObj = (PyObject*)FPyWrapperMulticastDelegateFactory::Get().CreateInstance(CastProp->SignatureFunction, (FMulticastScriptDelegate*)Value, OwnerContext, ConversionMethod);
return FPyConversionResult::Success();
}
// TODO: We're just not handling sparse delegates at this time
/*if (const FMulticastSparseDelegateProperty* CastProp = CastField<FMulticastSparseDelegateProperty>(Prop))
{
const FMulticastScriptDelegate* Value = CastProp->GetMulticastDelegate(ValueAddr);
OutPyObj = (PyObject*)FPyWrapperMulticastDelegateFactory::Get().CreateInstance(CastProp->SignatureFunction, (FMulticastScriptDelegate*)Value, OwnerContext, ConversionMethod);
return FPyConversionResult::Success();
}*/
if (const FArrayProperty* CastProp = CastField<FArrayProperty>(Prop))
{
OutPyObj = (PyObject*)FPyWrapperArrayFactory::Get().CreateInstance((void*)ValueAddr, CastProp, OwnerContext, ConversionMethod);
return FPyConversionResult::Success();
}
if (const FSetProperty* CastProp = CastField<FSetProperty>(Prop))
{
OutPyObj = (PyObject*)FPyWrapperSetFactory::Get().CreateInstance((void*)ValueAddr, CastProp, OwnerContext, ConversionMethod);
return FPyConversionResult::Success();
}
if (const FMapProperty* CastProp = CastField<FMapProperty>(Prop))
{
OutPyObj = (PyObject*)FPyWrapperMapFactory::Get().CreateInstance((void*)ValueAddr, CastProp, OwnerContext, ConversionMethod);
return FPyConversionResult::Success();
}
#undef PYTHONIZE_GETTER_PROPERTY
PYCONVERSION_RETURN(FPyConversionResult::Failure(), TEXT("PythonizeProperty"), *FString::Printf(TEXT("Cannot pythonize '%s' (%s). %s conversion not implemented!"), *Prop->GetName(), *Prop->GetClass()->GetName(), *Prop->GetClass()->GetName()));
#undef PYCONVERSION_PROPERTY_RETURN
}
FPyConversionResult NativizeProperty_InContainer(PyObject* PyObj, const FProperty* Prop, void* BaseAddr, const int32 ArrayIndex, const TConstArrayView<void*>& InArchetypeInstBaseAddrs, const FPropertyAccessChangeNotify* InChangeNotify, const ESetErrorState SetErrorState)
{
TArray<void*> ArchetypeInstValueAddrs;
ArchetypeInstValueAddrs.Reserve(InArchetypeInstBaseAddrs.Num());
for (void* ContainerAddr : InArchetypeInstBaseAddrs)
{
ArchetypeInstValueAddrs.Add(Prop->ContainerPtrToValuePtr<void>(ContainerAddr, ArrayIndex));
}
check(ArrayIndex < Prop->ArrayDim);
return NativizeProperty(PyObj, Prop, Prop->ContainerPtrToValuePtr<void>(BaseAddr, ArrayIndex), ArchetypeInstValueAddrs, InChangeNotify, SetErrorState);
}
FPyConversionResult PythonizeProperty_InContainer(const FProperty* Prop, const void* BaseAddr, const int32 ArrayIndex, PyObject*& OutPyObj, const EPyConversionMethod ConversionMethod, PyObject* OwnerPyObj, const ESetErrorState SetErrorState)
{
check(ArrayIndex < Prop->ArrayDim);
return PythonizeProperty(Prop, Prop->ContainerPtrToValuePtr<void>(BaseAddr, ArrayIndex), OutPyObj, ConversionMethod, OwnerPyObj, SetErrorState);
}
void EmitPropertyChangeNotifications(const FPropertyAccessChangeNotify* InChangeNotify, const bool bIdenticalValue, const TFunctionRef<void()>& InDoChangeFunc)
{
Py_BEGIN_ALLOW_THREADS
PropertyAccessUtil::EmitPreChangeNotify(InChangeNotify, bIdenticalValue);
if (!bIdenticalValue)
{
InDoChangeFunc();
}
PropertyAccessUtil::EmitPostChangeNotify(InChangeNotify, bIdenticalValue);
Py_END_ALLOW_THREADS
}
}
#undef PYCONVERSION_RETURN
#endif // WITH_PYTHON