Skip to content

Commit debb296

Browse files
authored
Merge pull request 20tab#595 from dfb/more_func_params
add support for native types like FVector in method params
2 parents 7611c52 + 376e9c5 commit debb296

File tree

13 files changed

+220
-63
lines changed

13 files changed

+220
-63
lines changed

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 195 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2642,9 +2642,18 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in
26422642
{
26432643
if (auto casted_prop = Cast<UObjectPropertyBase>(prop))
26442644
{
2645-
// ensure the object type is correct, otherwise crash could happen (soon or later)
2646-
if (!ue_obj->ue_object->IsA(casted_prop->PropertyClass))
2647-
return false;
2645+
// if the property specifies an interface, the object must be of a class that implements it
2646+
if (casted_prop->PropertyClass->HasAnyClassFlags(CLASS_Interface))
2647+
{
2648+
if (!ue_obj->ue_object->GetClass()->ImplementsInterface(casted_prop->PropertyClass))
2649+
return false;
2650+
}
2651+
else
2652+
{
2653+
// ensure the object type is correct, otherwise crash could happen (soon or later)
2654+
if (!ue_obj->ue_object->IsA(casted_prop->PropertyClass))
2655+
return false;
2656+
}
26482657

26492658
casted_prop->SetObjectPropertyValue_InContainer(buffer, ue_obj->ue_object, index);
26502659

@@ -3151,35 +3160,103 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
31513160
{
31523161
prop = NewObject<UIntProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
31533162
}
3163+
else if ((PyTypeObject *)value == &ue_PyFVectorType)
3164+
{
3165+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3166+
prop_struct->Struct = TBaseStructure<FVector>::Get();
3167+
prop = prop_struct;
3168+
}
3169+
else if ((PyTypeObject *)value == &ue_PyFRotatorType)
3170+
{
3171+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3172+
prop_struct->Struct = TBaseStructure<FRotator>::Get();
3173+
prop = prop_struct;
3174+
}
3175+
else if ((PyTypeObject *)value == &ue_PyFLinearColorType)
3176+
{
3177+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3178+
prop_struct->Struct = TBaseStructure<FLinearColor>::Get();
3179+
prop = prop_struct;
3180+
}
3181+
else if ((PyTypeObject *)value == &ue_PyFColorType)
3182+
{
3183+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3184+
prop_struct->Struct = TBaseStructure<FColor>::Get();
3185+
prop = prop_struct;
3186+
}
3187+
else if ((PyTypeObject *)value == &ue_PyFTransformType)
3188+
{
3189+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3190+
prop_struct->Struct = TBaseStructure<FTransform>::Get();
3191+
prop = prop_struct;
3192+
}
3193+
else if ((PyTypeObject *)value == &ue_PyFQuatType)
3194+
{
3195+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3196+
prop_struct->Struct = TBaseStructure<FQuat>::Get();
3197+
prop = prop_struct;
3198+
}
3199+
else if (PyObject_IsInstance(value, (PyObject *)&PyType_Type))
3200+
{
3201+
// Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,)
3202+
PyObject *type_args = PyObject_GetAttrString(value, "__args__");
3203+
if (!type_args)
3204+
{
3205+
UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name));
3206+
return nullptr;
3207+
}
3208+
if (PyTuple_Size(type_args) != 1)
3209+
{
3210+
Py_DECREF(type_args);
3211+
UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name));
3212+
return nullptr;
3213+
}
3214+
PyObject *py_class = PyTuple_GetItem(type_args, 0);
3215+
ue_PyUObject *py_obj = ue_is_pyuobject(py_class);
3216+
if (!py_obj)
3217+
{
3218+
Py_DECREF(type_args);
3219+
UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name));
3220+
return nullptr;
3221+
}
3222+
if (!py_obj->ue_object->IsA<UClass>())
3223+
{
3224+
Py_DECREF(type_args);
3225+
UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name));
3226+
return nullptr;
3227+
}
3228+
UClassProperty *prop_class = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3229+
prop_class->SetMetaClass((UClass*)py_obj->ue_object);
3230+
prop_class->PropertyClass = UClass::StaticClass();
3231+
prop = prop_class;
3232+
Py_DECREF(type_args);
3233+
}
31543234
}
31553235
else if (ue_PyUObject *py_obj = ue_is_pyuobject(value))
31563236
{
31573237
if (py_obj->ue_object->IsA<UClass>())
31583238
{
31593239
UClass *p_u_class = (UClass *)py_obj->ue_object;
3160-
if (p_u_class->IsChildOf<UClass>())
3161-
{
3162-
UClassProperty *prop_base = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3163-
if (p_u_class == UClass::StaticClass())
3164-
{
3165-
prop_base->SetMetaClass(UObject::StaticClass());
3166-
}
3167-
else
3168-
{
3169-
prop_base->SetMetaClass(p_u_class->GetClass());
3170-
}
3171-
prop_base->PropertyClass = UClass::StaticClass();
3172-
prop = prop_base;
3173-
}
3174-
else
3175-
{
3176-
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3177-
prop_base->SetPropertyClass(p_u_class);
3178-
prop = prop_base;
3179-
}
3180-
}
3240+
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3241+
prop_base->SetPropertyClass(p_u_class);
3242+
prop = prop_base;
3243+
}
3244+
else if (py_obj->ue_object->IsA<UEnum>())
3245+
{
3246+
UEnumProperty *prop_enum = NewObject<UEnumProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3247+
UNumericProperty *prop_underlying = NewObject<UByteProperty>(prop_enum, TEXT("UnderlyingType"), RF_Public);
3248+
prop_enum->SetEnum((UEnum*)py_obj->ue_object);
3249+
prop_enum->AddCppProperty(prop_underlying);
3250+
prop = prop_enum;
3251+
}
3252+
else if (py_obj->ue_object->IsA<UStruct>())
3253+
{
3254+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3255+
prop_struct->Struct = (UScriptStruct*)py_obj->ue_object;
3256+
prop = prop_struct;
3257+
}
31813258
}
3182-
// TODO add native types (like vectors, rotators...)
3259+
31833260
if (prop)
31843261
{
31853262
prop->SetPropertyFlags(CPF_Parm);
@@ -3222,35 +3299,103 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
32223299
{
32233300
prop = NewObject<UIntProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
32243301
}
3302+
else if ((PyTypeObject *)py_return_value == &ue_PyFVectorType)
3303+
{
3304+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3305+
prop_struct->Struct = TBaseStructure<FVector>::Get();
3306+
prop = prop_struct;
3307+
}
3308+
else if ((PyTypeObject *)py_return_value == &ue_PyFRotatorType)
3309+
{
3310+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3311+
prop_struct->Struct = TBaseStructure<FRotator>::Get();
3312+
prop = prop_struct;
3313+
}
3314+
else if ((PyTypeObject *)py_return_value == &ue_PyFLinearColorType)
3315+
{
3316+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3317+
prop_struct->Struct = TBaseStructure<FLinearColor>::Get();
3318+
prop = prop_struct;
3319+
}
3320+
else if ((PyTypeObject *)py_return_value == &ue_PyFColorType)
3321+
{
3322+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3323+
prop_struct->Struct = TBaseStructure<FColor>::Get();
3324+
prop = prop_struct;
3325+
}
3326+
else if ((PyTypeObject *)py_return_value == &ue_PyFTransformType)
3327+
{
3328+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3329+
prop_struct->Struct = TBaseStructure<FTransform>::Get();
3330+
prop = prop_struct;
3331+
}
3332+
else if ((PyTypeObject *)py_return_value == &ue_PyFQuatType)
3333+
{
3334+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3335+
prop_struct->Struct = TBaseStructure<FQuat>::Get();
3336+
prop = prop_struct;
3337+
}
3338+
else if (PyObject_IsInstance(py_return_value, (PyObject *)&PyType_Type))
3339+
{
3340+
// Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,)
3341+
PyObject *type_args = PyObject_GetAttrString(py_return_value, "__args__");
3342+
if (!type_args)
3343+
{
3344+
UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name));
3345+
return nullptr;
3346+
}
3347+
if (PyTuple_Size(type_args) != 1)
3348+
{
3349+
Py_DECREF(type_args);
3350+
UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name));
3351+
return nullptr;
3352+
}
3353+
PyObject *py_class = PyTuple_GetItem(type_args, 0);
3354+
ue_PyUObject *py_obj = ue_is_pyuobject(py_class);
3355+
if (!py_obj)
3356+
{
3357+
Py_DECREF(type_args);
3358+
UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name));
3359+
return nullptr;
3360+
}
3361+
if (!py_obj->ue_object->IsA<UClass>())
3362+
{
3363+
Py_DECREF(type_args);
3364+
UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name));
3365+
return nullptr;
3366+
}
3367+
UClassProperty *prop_class = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3368+
prop_class->SetMetaClass((UClass*)py_obj->ue_object);
3369+
prop_class->PropertyClass = UClass::StaticClass();
3370+
prop = prop_class;
3371+
Py_DECREF(type_args);
3372+
}
32253373
}
32263374
else if (ue_PyUObject *py_obj = ue_is_pyuobject(py_return_value))
32273375
{
3228-
if (py_obj->ue_object->IsA<UClass>())
3229-
{
3230-
UClass *p_u_class = (UClass *)py_obj->ue_object;
3231-
if (p_u_class->IsChildOf<UClass>())
3232-
{
3233-
UClassProperty *prop_base = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3234-
if (p_u_class == UClass::StaticClass())
3235-
{
3236-
prop_base->SetMetaClass(UObject::StaticClass());
3237-
}
3238-
else
3239-
{
3240-
prop_base->SetMetaClass(p_u_class->GetClass());
3241-
}
3242-
prop_base->PropertyClass = UClass::StaticClass();
3243-
prop = prop_base;
3244-
}
3245-
else
3246-
{
3247-
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3248-
prop_base->SetPropertyClass(p_u_class);
3249-
prop = prop_base;
3250-
}
3251-
}
3376+
if (py_obj->ue_object->IsA<UClass>())
3377+
{
3378+
UClass *p_u_class = (UClass *)py_obj->ue_object;
3379+
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3380+
prop_base->SetPropertyClass(p_u_class);
3381+
prop = prop_base;
3382+
}
3383+
else if (py_obj->ue_object->IsA<UEnum>())
3384+
{
3385+
UEnumProperty *prop_enum = NewObject<UEnumProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3386+
UNumericProperty *prop_underlying = NewObject<UByteProperty>(prop_enum, TEXT("UnderlyingType"), RF_Public);
3387+
prop_enum->SetEnum((UEnum*)py_obj->ue_object);
3388+
prop_enum->AddCppProperty(prop_underlying);
3389+
prop = prop_enum;
3390+
}
3391+
else if (py_obj->ue_object->IsA<UStruct>())
3392+
{
3393+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3394+
prop_struct->Struct = (UScriptStruct*)py_obj->ue_object;
3395+
prop = prop_struct;
3396+
}
32523397
}
3253-
// TODO add native types (like vectors, rotators...)
3398+
32543399
if (prop)
32553400
{
32563401
prop->SetPropertyFlags(CPF_Parm | CPF_OutParm | CPF_ReturnParm);

Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ static PyObject *ue_PyFColor_str(ue_PyFColor *self)
103103
self->color.R, self->color.G, self->color.B, self->color.A);
104104
}
105105

106-
static PyTypeObject ue_PyFColorType = {
106+
PyTypeObject ue_PyFColorType = {
107107
PyVarObject_HEAD_INIT(NULL, 0)
108108
"unreal_engine.FColor", /* tp_name */
109109
sizeof(ue_PyFColor), /* tp_basicsize */

Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ typedef struct
1111
FColor color;
1212
} ue_PyFColor;
1313

14+
extern PyTypeObject ue_PyFColorType;
15+
1416
PyObject *py_ue_new_fcolor(FColor);
1517
ue_PyFColor *py_ue_is_fcolor(PyObject *);
1618

1719
void ue_python_init_fcolor(PyObject *);
1820

1921
bool py_ue_color_arg(PyObject *, FColor &);
2022

21-
bool py_ue_get_fcolor(PyObject *, FColor &);
23+
bool py_ue_get_fcolor(PyObject *, FColor &);

Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ static PyObject *ue_PyFLinearColor_str(ue_PyFLinearColor *self)
106106
PyFloat_FromDouble(self->color.A));
107107
}
108108

109-
static PyTypeObject ue_PyFLinearColorType = {
109+
PyTypeObject ue_PyFLinearColorType = {
110110
PyVarObject_HEAD_INIT(NULL, 0)
111111
"unreal_engine.FLinearColor", /* tp_name */
112112
sizeof(ue_PyFLinearColor), /* tp_basicsize */

Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ typedef struct
1111
FLinearColor color;
1212
} ue_PyFLinearColor;
1313

14+
extern PyTypeObject ue_PyFLinearColorType;
15+
1416
PyObject *py_ue_new_flinearcolor(FLinearColor);
1517
ue_PyFLinearColor *py_ue_is_flinearcolor(PyObject *);
1618

1719
void ue_python_init_flinearcolor(PyObject *);
1820

1921
bool py_ue_linearcolor_arg(PyObject *, FLinearColor &);
2022

21-
bool py_ue_get_flinearcolor(PyObject *, FLinearColor &);
23+
bool py_ue_get_flinearcolor(PyObject *, FLinearColor &);

Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ static PyObject *ue_PyFQuat_str(ue_PyFQuat *self)
152152
PyFloat_FromDouble(self->quat.X), PyFloat_FromDouble(self->quat.Y), PyFloat_FromDouble(self->quat.Z), PyFloat_FromDouble(self->quat.W));
153153
}
154154

155-
static PyTypeObject ue_PyFQuatType = {
155+
PyTypeObject ue_PyFQuatType = {
156156
PyVarObject_HEAD_INIT(NULL, 0)
157157
"unreal_engine.FQuat", /* tp_name */
158158
sizeof(ue_PyFQuat), /* tp_basicsize */

Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ typedef struct
1111
FQuat quat;
1212
} ue_PyFQuat;
1313

14+
extern PyTypeObject ue_PyFQuatType;
15+
1416
PyObject *py_ue_new_fquat(FQuat);
1517
ue_PyFQuat *py_ue_is_fquat(PyObject *);
1618

1719
void ue_python_init_fquat(PyObject *);
1820

19-
bool py_ue_quat_arg(PyObject *, FQuat &);
21+
bool py_ue_quat_arg(PyObject *, FQuat &);

Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ static PyObject *ue_PyFRotator_str(ue_PyFRotator *self)
9393
PyFloat_FromDouble(self->rot.Roll), PyFloat_FromDouble(self->rot.Pitch), PyFloat_FromDouble(self->rot.Yaw));
9494
}
9595

96-
static PyTypeObject ue_PyFRotatorType = {
96+
PyTypeObject ue_PyFRotatorType = {
9797
PyVarObject_HEAD_INIT(NULL, 0)
9898
"unreal_engine.FRotator", /* tp_name */
9999
sizeof(ue_PyFRotator), /* tp_basicsize */

Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ typedef struct {
1010
FRotator rot;
1111
} ue_PyFRotator;
1212

13+
extern PyTypeObject ue_PyFRotatorType;
14+
1315
PyObject *py_ue_new_frotator(FRotator);
1416
ue_PyFRotator *py_ue_is_frotator(PyObject *);
1517

1618
void ue_python_init_frotator(PyObject *);
1719

18-
bool py_ue_rotator_arg(PyObject *, FRotator &);
20+
bool py_ue_rotator_arg(PyObject *, FRotator &);

Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ static PyObject *ue_PyFTransform_str(ue_PyFTransform *self)
220220
}
221221

222222

223-
static PyTypeObject ue_PyFTransformType = {
223+
PyTypeObject ue_PyFTransformType = {
224224
PyVarObject_HEAD_INIT(NULL, 0)
225225
"unreal_engine.FTransform", /* tp_name */
226226
sizeof(ue_PyFTransform), /* tp_basicsize */
@@ -435,4 +435,4 @@ bool py_ue_transform_arg(PyObject *args, FTransform &t)
435435
t.SetRotation(FRotator(pitch, yaw, roll).Quaternion());
436436
t.SetScale3D(FVector(sx, sy, sz));
437437
return true;
438-
}
438+
}

0 commit comments

Comments
 (0)