Skip to content

Commit 3afec1d

Browse files
committed
improved sequencer api
1 parent 5031be3 commit 3afec1d

File tree

3 files changed

+166
-122
lines changed

3 files changed

+166
-122
lines changed

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 124 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,8 @@ static PyMethodDef ue_PyUObject_methods[] = {
10811081
{ "sequencer_set_view_range", (PyCFunction)py_ue_sequencer_set_view_range, METH_VARARGS, "" },
10821082
{ "sequencer_set_working_range", (PyCFunction)py_ue_sequencer_set_working_range, METH_VARARGS, "" },
10831083
{ "sequencer_set_section_range", (PyCFunction)py_ue_sequencer_set_section_range, METH_VARARGS, "" },
1084+
{ "sequencer_get_playback_range", (PyCFunction)py_ue_sequencer_get_playback_range, METH_VARARGS, "" },
1085+
{ "sequencer_get_selection_range", (PyCFunction)py_ue_sequencer_get_selection_range, METH_VARARGS, "" },
10841086
{ "sequencer_folders", (PyCFunction)py_ue_sequencer_folders, METH_VARARGS, "" },
10851087
{ "sequencer_create_folder", (PyCFunction)py_ue_sequencer_create_folder, METH_VARARGS, "" },
10861088
{ "sequencer_set_display_name", (PyCFunction)py_ue_sequencer_set_display_name, METH_VARARGS, "" },
@@ -1960,7 +1962,7 @@ void unreal_engine_py_log_error()
19601962
}
19611963

19621964
PyErr_Clear();
1963-
}
1965+
}
19641966

19651967
// retrieve a UWorld from a generic UObject (if possible)
19661968
UWorld *ue_get_uworld(ue_PyUObject *py_obj)
@@ -2645,18 +2647,18 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in
26452647
{
26462648
if (auto casted_prop = Cast<UObjectPropertyBase>(prop))
26472649
{
2648-
// if the property specifies an interface, the object must be of a class that implements it
2649-
if (casted_prop->PropertyClass->HasAnyClassFlags(CLASS_Interface))
2650-
{
2651-
if (!ue_obj->ue_object->GetClass()->ImplementsInterface(casted_prop->PropertyClass))
2652-
return false;
2653-
}
2654-
else
2655-
{
2656-
// ensure the object type is correct, otherwise crash could happen (soon or later)
2657-
if (!ue_obj->ue_object->IsA(casted_prop->PropertyClass))
2658-
return false;
2659-
}
2650+
// if the property specifies an interface, the object must be of a class that implements it
2651+
if (casted_prop->PropertyClass->HasAnyClassFlags(CLASS_Interface))
2652+
{
2653+
if (!ue_obj->ue_object->GetClass()->ImplementsInterface(casted_prop->PropertyClass))
2654+
return false;
2655+
}
2656+
else
2657+
{
2658+
// ensure the object type is correct, otherwise crash could happen (soon or later)
2659+
if (!ue_obj->ue_object->IsA(casted_prop->PropertyClass))
2660+
return false;
2661+
}
26602662

26612663
casted_prop->SetObjectPropertyValue_InContainer(buffer, ue_obj->ue_object, index);
26622664

@@ -3199,65 +3201,65 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
31993201
prop_struct->Struct = TBaseStructure<FQuat>::Get();
32003202
prop = prop_struct;
32013203
}
3202-
else if (PyObject_IsInstance(value, (PyObject *)&PyType_Type))
3203-
{
3204-
// Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,)
3205-
PyObject *type_args = PyObject_GetAttrString(value, "__args__");
3206-
if (!type_args)
3207-
{
3208-
UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name));
3209-
return nullptr;
3210-
}
3211-
if (PyTuple_Size(type_args) != 1)
3212-
{
3213-
Py_DECREF(type_args);
3214-
UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name));
3215-
return nullptr;
3216-
}
3217-
PyObject *py_class = PyTuple_GetItem(type_args, 0);
3218-
ue_PyUObject *py_obj = ue_is_pyuobject(py_class);
3219-
if (!py_obj)
3220-
{
3221-
Py_DECREF(type_args);
3222-
UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name));
3223-
return nullptr;
3224-
}
3225-
if (!py_obj->ue_object->IsA<UClass>())
3226-
{
3227-
Py_DECREF(type_args);
3228-
UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name));
3229-
return nullptr;
3230-
}
3231-
UClassProperty *prop_class = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3232-
prop_class->SetMetaClass((UClass*)py_obj->ue_object);
3233-
prop_class->PropertyClass = UClass::StaticClass();
3234-
prop = prop_class;
3235-
Py_DECREF(type_args);
3236-
}
3204+
else if (PyObject_IsInstance(value, (PyObject *)&PyType_Type))
3205+
{
3206+
// Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,)
3207+
PyObject *type_args = PyObject_GetAttrString(value, "__args__");
3208+
if (!type_args)
3209+
{
3210+
UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name));
3211+
return nullptr;
3212+
}
3213+
if (PyTuple_Size(type_args) != 1)
3214+
{
3215+
Py_DECREF(type_args);
3216+
UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name));
3217+
return nullptr;
3218+
}
3219+
PyObject *py_class = PyTuple_GetItem(type_args, 0);
3220+
ue_PyUObject *py_obj = ue_is_pyuobject(py_class);
3221+
if (!py_obj)
3222+
{
3223+
Py_DECREF(type_args);
3224+
UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name));
3225+
return nullptr;
3226+
}
3227+
if (!py_obj->ue_object->IsA<UClass>())
3228+
{
3229+
Py_DECREF(type_args);
3230+
UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name));
3231+
return nullptr;
3232+
}
3233+
UClassProperty *prop_class = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3234+
prop_class->SetMetaClass((UClass*)py_obj->ue_object);
3235+
prop_class->PropertyClass = UClass::StaticClass();
3236+
prop = prop_class;
3237+
Py_DECREF(type_args);
3238+
}
32373239
}
32383240
else if (ue_PyUObject *py_obj = ue_is_pyuobject(value))
32393241
{
32403242
if (py_obj->ue_object->IsA<UClass>())
32413243
{
32423244
UClass *p_u_class = (UClass *)py_obj->ue_object;
3243-
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3244-
prop_base->SetPropertyClass(p_u_class);
3245-
prop = prop_base;
3246-
}
3247-
else if (py_obj->ue_object->IsA<UEnum>())
3248-
{
3249-
UEnumProperty *prop_enum = NewObject<UEnumProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3250-
UNumericProperty *prop_underlying = NewObject<UByteProperty>(prop_enum, TEXT("UnderlyingType"), RF_Public);
3251-
prop_enum->SetEnum((UEnum*)py_obj->ue_object);
3252-
prop_enum->AddCppProperty(prop_underlying);
3253-
prop = prop_enum;
3254-
}
3255-
else if (py_obj->ue_object->IsA<UStruct>())
3256-
{
3257-
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3258-
prop_struct->Struct = (UScriptStruct*)py_obj->ue_object;
3259-
prop = prop_struct;
3260-
}
3245+
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3246+
prop_base->SetPropertyClass(p_u_class);
3247+
prop = prop_base;
3248+
}
3249+
else if (py_obj->ue_object->IsA<UEnum>())
3250+
{
3251+
UEnumProperty *prop_enum = NewObject<UEnumProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3252+
UNumericProperty *prop_underlying = NewObject<UByteProperty>(prop_enum, TEXT("UnderlyingType"), RF_Public);
3253+
prop_enum->SetEnum((UEnum*)py_obj->ue_object);
3254+
prop_enum->AddCppProperty(prop_underlying);
3255+
prop = prop_enum;
3256+
}
3257+
else if (py_obj->ue_object->IsA<UStruct>())
3258+
{
3259+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3260+
prop_struct->Struct = (UScriptStruct*)py_obj->ue_object;
3261+
prop = prop_struct;
3262+
}
32613263
}
32623264

32633265
if (prop)
@@ -3338,65 +3340,65 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_
33383340
prop_struct->Struct = TBaseStructure<FQuat>::Get();
33393341
prop = prop_struct;
33403342
}
3341-
else if (PyObject_IsInstance(py_return_value, (PyObject *)&PyType_Type))
3342-
{
3343-
// Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,)
3344-
PyObject *type_args = PyObject_GetAttrString(py_return_value, "__args__");
3345-
if (!type_args)
3346-
{
3347-
UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name));
3348-
return nullptr;
3349-
}
3350-
if (PyTuple_Size(type_args) != 1)
3351-
{
3352-
Py_DECREF(type_args);
3353-
UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name));
3354-
return nullptr;
3355-
}
3356-
PyObject *py_class = PyTuple_GetItem(type_args, 0);
3357-
ue_PyUObject *py_obj = ue_is_pyuobject(py_class);
3358-
if (!py_obj)
3359-
{
3360-
Py_DECREF(type_args);
3361-
UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name));
3362-
return nullptr;
3363-
}
3364-
if (!py_obj->ue_object->IsA<UClass>())
3365-
{
3366-
Py_DECREF(type_args);
3367-
UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name));
3368-
return nullptr;
3369-
}
3370-
UClassProperty *prop_class = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3371-
prop_class->SetMetaClass((UClass*)py_obj->ue_object);
3372-
prop_class->PropertyClass = UClass::StaticClass();
3373-
prop = prop_class;
3374-
Py_DECREF(type_args);
3375-
}
3343+
else if (PyObject_IsInstance(py_return_value, (PyObject *)&PyType_Type))
3344+
{
3345+
// Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,)
3346+
PyObject *type_args = PyObject_GetAttrString(py_return_value, "__args__");
3347+
if (!type_args)
3348+
{
3349+
UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name));
3350+
return nullptr;
3351+
}
3352+
if (PyTuple_Size(type_args) != 1)
3353+
{
3354+
Py_DECREF(type_args);
3355+
UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name));
3356+
return nullptr;
3357+
}
3358+
PyObject *py_class = PyTuple_GetItem(type_args, 0);
3359+
ue_PyUObject *py_obj = ue_is_pyuobject(py_class);
3360+
if (!py_obj)
3361+
{
3362+
Py_DECREF(type_args);
3363+
UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name));
3364+
return nullptr;
3365+
}
3366+
if (!py_obj->ue_object->IsA<UClass>())
3367+
{
3368+
Py_DECREF(type_args);
3369+
UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name));
3370+
return nullptr;
3371+
}
3372+
UClassProperty *prop_class = NewObject<UClassProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3373+
prop_class->SetMetaClass((UClass*)py_obj->ue_object);
3374+
prop_class->PropertyClass = UClass::StaticClass();
3375+
prop = prop_class;
3376+
Py_DECREF(type_args);
3377+
}
33763378
}
33773379
else if (ue_PyUObject *py_obj = ue_is_pyuobject(py_return_value))
33783380
{
3379-
if (py_obj->ue_object->IsA<UClass>())
3380-
{
3381-
UClass *p_u_class = (UClass *)py_obj->ue_object;
3382-
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3383-
prop_base->SetPropertyClass(p_u_class);
3384-
prop = prop_base;
3385-
}
3386-
else if (py_obj->ue_object->IsA<UEnum>())
3387-
{
3388-
UEnumProperty *prop_enum = NewObject<UEnumProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3389-
UNumericProperty *prop_underlying = NewObject<UByteProperty>(prop_enum, TEXT("UnderlyingType"), RF_Public);
3390-
prop_enum->SetEnum((UEnum*)py_obj->ue_object);
3391-
prop_enum->AddCppProperty(prop_underlying);
3392-
prop = prop_enum;
3393-
}
3394-
else if (py_obj->ue_object->IsA<UStruct>())
3395-
{
3396-
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3397-
prop_struct->Struct = (UScriptStruct*)py_obj->ue_object;
3398-
prop = prop_struct;
3399-
}
3381+
if (py_obj->ue_object->IsA<UClass>())
3382+
{
3383+
UClass *p_u_class = (UClass *)py_obj->ue_object;
3384+
UObjectProperty *prop_base = NewObject<UObjectProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3385+
prop_base->SetPropertyClass(p_u_class);
3386+
prop = prop_base;
3387+
}
3388+
else if (py_obj->ue_object->IsA<UEnum>())
3389+
{
3390+
UEnumProperty *prop_enum = NewObject<UEnumProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3391+
UNumericProperty *prop_underlying = NewObject<UByteProperty>(prop_enum, TEXT("UnderlyingType"), RF_Public);
3392+
prop_enum->SetEnum((UEnum*)py_obj->ue_object);
3393+
prop_enum->AddCppProperty(prop_underlying);
3394+
prop = prop_enum;
3395+
}
3396+
else if (py_obj->ue_object->IsA<UStruct>())
3397+
{
3398+
UStructProperty *prop_struct = NewObject<UStructProperty>(function, UTF8_TO_TCHAR(p_name), RF_Public);
3399+
prop_struct->Struct = (UScriptStruct*)py_obj->ue_object;
3400+
prop = prop_struct;
3401+
}
34003402
}
34013403

34023404
if (prop)

Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,26 @@ PyObject *py_ue_sequencer_set_playback_range(ue_PyUObject *self, PyObject * args
915915
Py_RETURN_NONE;
916916
}
917917

918+
PyObject *py_ue_sequencer_get_playback_range(ue_PyUObject *self, PyObject * args)
919+
{
920+
921+
ue_py_check(self);
922+
923+
ULevelSequence *seq = ue_py_check_type<ULevelSequence>(self);
924+
if (!seq)
925+
return PyErr_Format(PyExc_Exception, "uobject is not a LevelSequence");
926+
UMovieScene *scene = seq->GetMovieScene();
927+
928+
#if ENGINE_MINOR_VERSION < 20
929+
scene->GetPlaybackRange();
930+
#else
931+
TRange<FFrameNumber> range = scene->GetPlaybackRange();
932+
933+
return Py_BuildValue("(OO)", py_ue_new_fframe_number(range.GetLowerBoundValue()), py_ue_new_fframe_number(range.GetUpperBoundValue()));
934+
935+
#endif
936+
}
937+
918938
PyObject *py_ue_sequencer_set_working_range(ue_PyUObject *self, PyObject * args)
919939
{
920940

@@ -1013,6 +1033,26 @@ PyObject *py_ue_sequencer_set_section_range(ue_PyUObject *self, PyObject * args)
10131033
Py_RETURN_NONE;
10141034
}
10151035

1036+
PyObject *py_ue_sequencer_get_selection_range(ue_PyUObject *self, PyObject * args)
1037+
{
1038+
1039+
ue_py_check(self);
1040+
1041+
ULevelSequence *seq = ue_py_check_type<ULevelSequence>(self);
1042+
if (!seq)
1043+
return PyErr_Format(PyExc_Exception, "uobject is not a LevelSequence");
1044+
UMovieScene *scene = seq->GetMovieScene();
1045+
1046+
#if ENGINE_MINOR_VERSION < 20
1047+
scene->GetSelectionRange();
1048+
#else
1049+
TRange<FFrameNumber> range = scene->GetSelectionRange();
1050+
1051+
return Py_BuildValue("(OO)", py_ue_new_fframe_number(range.GetLowerBoundValue()), py_ue_new_fframe_number(range.GetUpperBoundValue()));
1052+
1053+
#endif
1054+
}
1055+
10161056

10171057
PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *self, PyObject * args)
10181058
{

Source/UnrealEnginePython/Private/UObject/UEPySequencer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ PyObject *py_ue_sequencer_set_playback_range(ue_PyUObject *, PyObject *);
1313
PyObject *py_ue_sequencer_set_view_range(ue_PyUObject *, PyObject *);
1414
PyObject *py_ue_sequencer_set_working_range(ue_PyUObject *, PyObject *);
1515
PyObject *py_ue_sequencer_set_section_range(ue_PyUObject *, PyObject *);
16+
PyObject *py_ue_sequencer_get_playback_range(ue_PyUObject *, PyObject *);
17+
PyObject *py_ue_sequencer_get_selection_range(ue_PyUObject *, PyObject *);
1618
PyObject *py_ue_sequencer_folders(ue_PyUObject *, PyObject *);
1719
PyObject *py_ue_sequencer_create_folder(ue_PyUObject *, PyObject *);
1820
PyObject *py_ue_sequencer_set_display_name(ue_PyUObject *, PyObject *);

0 commit comments

Comments
 (0)