@@ -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