Skip to content

Commit 376e9c5

Browse files
committed
added support for structs and class objects in function params and return values
1 parent ed1e6d8 commit 376e9c5

File tree

1 file changed

+104
-47
lines changed

1 file changed

+104
-47
lines changed

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 104 additions & 47 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

@@ -3187,32 +3196,50 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
31873196
prop_struct->Struct = TBaseStructure<FQuat>::Get();
31883197
prop = prop_struct;
31893198
}
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+
}
31903234
}
31913235
else if (ue_PyUObject *py_obj = ue_is_pyuobject(value))
31923236
{
31933237
if (py_obj->ue_object->IsA<UClass>())
31943238
{
31953239
UClass *p_u_class = (UClass *)py_obj->ue_object;
3196-
if (p_u_class->IsChildOf<UClass>())
3197-
{
3198-
UClassProperty *prop_base = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3199-
if (p_u_class == UClass::StaticClass())
3200-
{
3201-
prop_base->SetMetaClass(UObject::StaticClass());
3202-
}
3203-
else
3204-
{
3205-
prop_base->SetMetaClass(p_u_class->GetClass());
3206-
}
3207-
prop_base->PropertyClass = UClass::StaticClass();
3208-
prop = prop_base;
3209-
}
3210-
else
3211-
{
3212-
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3213-
prop_base->SetPropertyClass(p_u_class);
3214-
prop = prop_base;
3215-
}
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;
32163243
}
32173244
else if (py_obj->ue_object->IsA<UEnum>())
32183245
{
@@ -3221,6 +3248,12 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
32213248
prop_enum->SetEnum((UEnum*)py_obj->ue_object);
32223249
prop_enum->AddCppProperty(prop_underlying);
32233250
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;
32243257
}
32253258
}
32263259

@@ -3302,40 +3335,64 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
33023335
prop_struct->Struct = TBaseStructure<FQuat>::Get();
33033336
prop = prop_struct;
33043337
}
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+
}
33053373
}
33063374
else if (ue_PyUObject *py_obj = ue_is_pyuobject(py_return_value))
33073375
{
3308-
if (py_obj->ue_object->IsA<UClass>())
3309-
{
3310-
UClass *p_u_class = (UClass *)py_obj->ue_object;
3311-
if (p_u_class->IsChildOf<UClass>())
3312-
{
3313-
UClassProperty *prop_base = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3314-
if (p_u_class == UClass::StaticClass())
3315-
{
3316-
prop_base->SetMetaClass(UObject::StaticClass());
3317-
}
3318-
else
3319-
{
3320-
prop_base->SetMetaClass(p_u_class->GetClass());
3321-
}
3322-
prop_base->PropertyClass = UClass::StaticClass();
3323-
prop = prop_base;
3324-
}
3325-
else
3326-
{
3327-
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3328-
prop_base->SetPropertyClass(p_u_class);
3329-
prop = prop_base;
3330-
}
3331-
}
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+
}
33323383
else if (py_obj->ue_object->IsA<UEnum>())
33333384
{
33343385
UEnumProperty *prop_enum = NewObject<UEnumProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
33353386
UNumericProperty *prop_underlying = NewObject<UByteProperty>(prop_enum, TEXT("UnderlyingType"), RF_Public);
33363387
prop_enum->SetEnum((UEnum*)py_obj->ue_object);
33373388
prop_enum->AddCppProperty(prop_underlying);
33383389
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;
33393396
}
33403397
}
33413398

0 commit comments

Comments
 (0)