Skip to content

Commit 8dc1632

Browse files
author
Roberto De Ioris
committed
improved sequencer api, added structs comparation
1 parent 2ec484c commit 8dc1632

File tree

6 files changed

+264
-18
lines changed

6 files changed

+264
-18
lines changed

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -561,25 +561,30 @@ static PyMethodDef ue_PyUObject_methods[] = {
561561
{ "sequencer_possessable_tracks", (PyCFunction)py_ue_sequencer_possessable_tracks, METH_VARARGS, "" },
562562
#if WITH_EDITOR
563563
{ "sequencer_folders", (PyCFunction)py_ue_sequencer_folders, METH_VARARGS, "" },
564+
{ "sequencer_create_folder", (PyCFunction)py_ue_sequencer_create_folder, METH_VARARGS, "" },
564565
{ "sequencer_set_display_name", (PyCFunction)py_ue_sequencer_set_display_name, METH_VARARGS, "" },
565566
{ "sequencer_get_display_name", (PyCFunction)py_ue_sequencer_get_display_name, METH_VARARGS, "" },
566567
{ "sequencer_changed", (PyCFunction)py_ue_sequencer_changed, METH_VARARGS, "" },
568+
{ "sequencer_add_camera_cut_track", (PyCFunction)py_ue_sequencer_add_camera_cut_track, METH_VARARGS, "" },
569+
{ "sequencer_add_actor", (PyCFunction)py_ue_sequencer_add_actor, METH_VARARGS, "" },
570+
{ "sequencer_make_new_spawnable", (PyCFunction)py_ue_sequencer_make_new_spawnable, METH_VARARGS, "" },
571+
572+
{ "sequencer_add_possessable", (PyCFunction)py_ue_sequencer_add_possessable, METH_VARARGS, "" },
573+
{ "sequencer_track_add_section", (PyCFunction)py_ue_sequencer_track_add_section, METH_VARARGS, "" },
574+
575+
{ "sequencer_section_add_key", (PyCFunction)py_ue_sequencer_section_add_key, METH_VARARGS, "" },
567576
#endif
568577
{ "sequencer_sections", (PyCFunction)py_ue_sequencer_sections, METH_VARARGS, "" },
569578
{ "sequencer_track_sections", (PyCFunction)py_ue_sequencer_track_sections, METH_VARARGS, "" },
570579
{ "sequencer_possessables", (PyCFunction)py_ue_sequencer_possessables, METH_VARARGS, "" },
571580
{ "sequencer_possessables_guid", (PyCFunction)py_ue_sequencer_possessables_guid, METH_VARARGS, "" },
572581
{ "sequencer_find_possessable", (PyCFunction)py_ue_sequencer_find_possessable, METH_VARARGS, "" },
582+
{ "sequencer_find_spawnable", (PyCFunction)py_ue_sequencer_find_spawnable, METH_VARARGS, "" },
573583
{ "sequencer_add_master_track", (PyCFunction)py_ue_sequencer_add_master_track, METH_VARARGS, "" },
574-
{ "sequencer_add_camera_cut_track", (PyCFunction)py_ue_sequencer_add_camera_cut_track, METH_VARARGS, "" },
575584

576-
{ "sequencer_add_track", (PyCFunction)py_ue_sequencer_add_track, METH_VARARGS, "" },
577-
{ "sequencer_add_actor", (PyCFunction)py_ue_sequencer_add_actor, METH_VARARGS, "" },
578585

579-
{ "sequencer_add_possessable", (PyCFunction)py_ue_sequencer_add_possessable, METH_VARARGS, "" },
580-
{ "sequencer_track_add_section", (PyCFunction)py_ue_sequencer_track_add_section, METH_VARARGS, "" },
586+
{ "sequencer_add_track", (PyCFunction)py_ue_sequencer_add_track, METH_VARARGS, "" },
581587

582-
{ "sequencer_section_add_key", (PyCFunction)py_ue_sequencer_section_add_key, METH_VARARGS, "" },
583588

584589
// Material
585590
{ "set_material", (PyCFunction)py_ue_set_material, METH_VARARGS, "" },
@@ -625,8 +630,8 @@ void ue_pydelegates_cleanup(ue_PyUObject *self) {
625630
UE_LOG(LogPython, Warning, TEXT("Removing UPythonDelegate %p from ue_PyUObject %p mapped to UObject %p"), py_delegate, self, self->ue_object);
626631
#endif
627632
py_delegate->RemoveFromRoot();
633+
}
628634
}
629-
}
630635
self->python_delegates_gc->clear();
631636
delete self->python_delegates_gc;
632637
self->python_delegates_gc = nullptr;
@@ -1348,7 +1353,7 @@ void unreal_engine_py_log_error() {
13481353
}
13491354

13501355
PyErr_Clear();
1351-
}
1356+
}
13521357

13531358
// retrieve a UWorld from a generic UObject (if possible)
13541359
UWorld *ue_get_uworld(ue_PyUObject *py_obj) {
@@ -1787,6 +1792,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) {
17871792

17881793
}
17891794

1795+
17901796
// check if a python object is a wrapper to a UObject
17911797
ue_PyUObject *ue_is_pyuobject(PyObject *obj) {
17921798
if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyUObjectType))

Source/UnrealEnginePython/Private/UEPySequencer.cpp

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "Sections/MovieSceneBoolSection.h"
1919
#include "Sections/MovieScene3DTransformSection.h"
2020
#include "Sections/MovieSceneVectorSection.h"
21+
#include "Runtime/MovieScene/Public/MovieSceneFolder.h"
22+
#include "Runtime/MovieScene/Public/MovieSceneSpawnable.h"
2123
#endif
2224

2325
#if WITH_EDITOR
@@ -129,6 +131,32 @@ PyObject *py_ue_sequencer_find_possessable(ue_PyUObject *self, PyObject * args)
129131
return ret;
130132
}
131133

134+
PyObject *py_ue_sequencer_find_spawnable(ue_PyUObject *self, PyObject * args) {
135+
136+
ue_py_check(self);
137+
138+
char *guid;
139+
if (!PyArg_ParseTuple(args, "s:sequencer_find_spawnable", &guid)) {
140+
return NULL;
141+
}
142+
143+
if (!self->ue_object->IsA<ULevelSequence>())
144+
return PyErr_Format(PyExc_Exception, "uobject is not a LevelSequence");
145+
146+
FGuid f_guid;
147+
if (!FGuid::Parse(FString(guid), f_guid)) {
148+
return PyErr_Format(PyExc_Exception, "invalid GUID");
149+
}
150+
151+
ULevelSequence *seq = (ULevelSequence *)self->ue_object;
152+
153+
FMovieSceneSpawnable *spawnable = seq->MovieScene->FindSpawnable(f_guid);
154+
PyObject *ret = py_ue_new_uscriptstruct(spawnable->StaticStruct(), (uint8 *)spawnable);
155+
Py_INCREF(ret);
156+
return ret;
157+
}
158+
159+
#if WITH_EDITOR
132160
PyObject *py_ue_sequencer_add_possessable(ue_PyUObject *self, PyObject * args) {
133161

134162
ue_py_check(self);
@@ -213,6 +241,45 @@ PyObject *py_ue_sequencer_add_actor(ue_PyUObject *self, PyObject * args) {
213241
return PyUnicode_FromString(TCHAR_TO_UTF8(*new_guid.ToString()));
214242
}
215243

244+
PyObject *py_ue_sequencer_make_new_spawnable(ue_PyUObject *self, PyObject * args) {
245+
246+
ue_py_check(self);
247+
248+
PyObject *py_obj;
249+
if (!PyArg_ParseTuple(args, "O:sequencer_add_spawnable", &py_obj)) {
250+
return NULL;
251+
}
252+
253+
if (!self->ue_object->IsA<ULevelSequence>())
254+
return PyErr_Format(PyExc_Exception, "uobject is not a LevelSequence");
255+
256+
ue_PyUObject *py_ue_obj = ue_is_pyuobject(py_obj);
257+
if (!py_ue_obj)
258+
return PyErr_Format(PyExc_Exception, "argument is not a uobject");
259+
260+
if (!py_ue_obj->ue_object->IsA<AActor>())
261+
return PyErr_Format(PyExc_Exception, "argument is not an actor");
262+
263+
AActor *actor = (AActor *)py_ue_obj->ue_object;
264+
265+
ULevelSequence *seq = (ULevelSequence *)self->ue_object;
266+
267+
// try to open the editor for the asset
268+
FAssetEditorManager::Get().OpenEditorForAsset(seq);
269+
270+
IAssetEditorInstance *editor = FAssetEditorManager::Get().FindEditorForAsset(seq, true);
271+
if (!editor) {
272+
return PyErr_Format(PyExc_Exception, "unable to access sequencer");
273+
}
274+
275+
FLevelSequenceEditorToolkit *toolkit = (FLevelSequenceEditorToolkit *)editor;
276+
ISequencer *sequencer = toolkit->GetSequencer().Get();
277+
FGuid new_guid = sequencer->MakeNewSpawnable(*actor);
278+
279+
return PyUnicode_FromString(TCHAR_TO_UTF8(*new_guid.ToString()));
280+
}
281+
#endif
282+
216283
PyObject *py_ue_sequencer_master_tracks(ue_PyUObject *self, PyObject * args) {
217284

218285
ue_py_check(self);
@@ -287,12 +354,35 @@ PyObject *py_ue_sequencer_folders(ue_PyUObject *self, PyObject * args) {
287354
if (!self->ue_object->IsA<ULevelSequence>())
288355
return PyErr_Format(PyExc_Exception, "uobject is not a LevelSequence");
289356

357+
PyObject *py_obj = nullptr;
358+
if (!PyArg_ParseTuple(args, "|O:sequencer_folders", &py_obj)) {
359+
return NULL;
360+
}
361+
362+
UMovieSceneFolder *parent_folder = nullptr;
363+
364+
if (py_obj) {
365+
ue_PyUObject *ue_py_obj = ue_is_pyuobject(py_obj);
366+
if (!ue_py_obj) {
367+
return PyErr_Format(PyExc_Exception, "argument is not a UObject");
368+
}
369+
parent_folder = Cast<UMovieSceneFolder>(ue_py_obj->ue_object);
370+
if (!parent_folder) {
371+
return PyErr_Format(PyExc_Exception, "argument is not a UMovieSceneFolder");
372+
}
373+
}
374+
290375
ULevelSequence *seq = (ULevelSequence *)self->ue_object;
291376
UMovieScene *scene = seq->GetMovieScene();
292377

293378
PyObject *py_folders = PyList_New(0);
294379

295-
TArray<UMovieSceneFolder *> folders = scene->GetRootFolders();
380+
TArray<UMovieSceneFolder *> folders;
381+
if (!parent_folder)
382+
folders = scene->GetRootFolders();
383+
else {
384+
folders = parent_folder->GetChildFolders();
385+
}
296386

297387
for (UMovieSceneFolder *folder : folders) {
298388
ue_PyUObject *ret = ue_get_python_wrapper((UObject *)folder);
@@ -305,6 +395,54 @@ PyObject *py_ue_sequencer_folders(ue_PyUObject *self, PyObject * args) {
305395

306396
return py_folders;
307397
}
398+
399+
PyObject *py_ue_sequencer_create_folder(ue_PyUObject *self, PyObject * args) {
400+
401+
ue_py_check(self);
402+
403+
if (!self->ue_object->IsA<ULevelSequence>())
404+
return PyErr_Format(PyExc_Exception, "uobject is not a LevelSequence");
405+
406+
PyObject *py_obj = nullptr;
407+
char *name;
408+
if (!PyArg_ParseTuple(args, "s|O:sequencer_create_folder", &name, &py_obj)) {
409+
return NULL;
410+
}
411+
412+
UMovieSceneFolder *parent_folder = nullptr;
413+
414+
if (py_obj) {
415+
ue_PyUObject *ue_py_obj = ue_is_pyuobject(py_obj);
416+
if (!ue_py_obj) {
417+
return PyErr_Format(PyExc_Exception, "argument is not a UObject");
418+
}
419+
parent_folder = Cast<UMovieSceneFolder>(ue_py_obj->ue_object);
420+
if (!parent_folder) {
421+
return PyErr_Format(PyExc_Exception, "argument is not a UMovieSceneFolder");
422+
}
423+
}
424+
425+
ULevelSequence *seq = (ULevelSequence *)self->ue_object;
426+
UMovieScene *scene = seq->GetMovieScene();
427+
428+
UMovieSceneFolder *new_folder = NewObject<UMovieSceneFolder>(scene, NAME_None, RF_Transactional);
429+
new_folder->SetFolderName(FName(name));
430+
431+
if (parent_folder) {
432+
parent_folder->Modify();
433+
parent_folder->AddChildFolder(new_folder);
434+
}
435+
else {
436+
scene->Modify();
437+
scene->GetRootFolders().Add(new_folder);
438+
}
439+
440+
PyObject *ret = (PyObject *)ue_get_python_wrapper(new_folder);
441+
if (!ret) {
442+
return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state");
443+
}
444+
return ret;
445+
}
308446
#endif
309447

310448
PyObject *py_ue_sequencer_sections(ue_PyUObject *self, PyObject * args) {
@@ -358,6 +496,7 @@ PyObject *py_ue_sequencer_track_sections(ue_PyUObject *self, PyObject * args) {
358496
return py_sections;
359497
}
360498

499+
#if WITH_EDITOR
361500
PyObject *py_ue_sequencer_track_add_section(ue_PyUObject *self, PyObject * args) {
362501

363502
ue_py_check(self);
@@ -378,6 +517,7 @@ PyObject *py_ue_sequencer_track_add_section(ue_PyUObject *self, PyObject * args)
378517
Py_INCREF(ret);
379518
return ret;
380519
}
520+
#endif
381521

382522
PyObject *py_ue_sequencer_add_master_track(ue_PyUObject *self, PyObject * args) {
383523

@@ -418,6 +558,7 @@ PyObject *py_ue_sequencer_add_master_track(ue_PyUObject *self, PyObject * args)
418558
return ret;
419559
}
420560

561+
#if WITH_EDITOR
421562
PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *self, PyObject * args) {
422563

423564
ue_py_check(self);
@@ -526,6 +667,7 @@ PyObject *py_ue_sequencer_add_camera_cut_track(ue_PyUObject *self, PyObject * ar
526667
Py_INCREF(ret);
527668
return ret;
528669
}
670+
#endif
529671

530672
PyObject *py_ue_sequencer_add_track(ue_PyUObject *self, PyObject * args) {
531673

Source/UnrealEnginePython/Private/UEPySequencer.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,30 @@ PyObject *py_ue_sequencer_possessable_tracks(ue_PyUObject *, PyObject *);
99
PyObject *py_ue_sequencer_track_sections(ue_PyUObject *, PyObject *);
1010
#if WITH_EDITOR
1111
PyObject *py_ue_sequencer_folders(ue_PyUObject *, PyObject *);
12+
PyObject *py_ue_sequencer_create_folder(ue_PyUObject *, PyObject *);
1213
PyObject *py_ue_sequencer_set_display_name(ue_PyUObject *, PyObject *);
1314
PyObject *py_ue_sequencer_get_display_name(ue_PyUObject *, PyObject *);
1415
PyObject *py_ue_sequencer_changed(ue_PyUObject *, PyObject *);
16+
PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *, PyObject *);
17+
18+
PyObject *py_ue_sequencer_add_camera_cut_track(ue_PyUObject *, PyObject *);
19+
20+
PyObject *py_ue_sequencer_add_possessable(ue_PyUObject *, PyObject *);
21+
22+
PyObject *py_ue_sequencer_track_add_section(ue_PyUObject *, PyObject *);
23+
PyObject *py_ue_sequencer_add_actor(ue_PyUObject *, PyObject *);
24+
PyObject *py_ue_sequencer_make_new_spawnable(ue_PyUObject *, PyObject *);
1525
#endif
1626
PyObject *py_ue_sequencer_sections(ue_PyUObject *, PyObject *);
1727
PyObject *py_ue_sequencer_possessables(ue_PyUObject *, PyObject *);
1828
PyObject *py_ue_sequencer_possessables_guid(ue_PyUObject *, PyObject *);
29+
1930
PyObject *py_ue_sequencer_find_possessable(ue_PyUObject *, PyObject *);
31+
PyObject *py_ue_sequencer_find_spawnable(ue_PyUObject *, PyObject *);
2032

2133
PyObject *py_ue_sequencer_add_master_track(ue_PyUObject *, PyObject *);
2234

23-
PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *, PyObject *);
24-
2535

26-
PyObject *py_ue_sequencer_add_camera_cut_track(ue_PyUObject *, PyObject *);
27-
28-
PyObject *py_ue_sequencer_add_possessable(ue_PyUObject *, PyObject *);
29-
30-
PyObject *py_ue_sequencer_track_add_section(ue_PyUObject *, PyObject *);
3136

3237
PyObject *py_ue_sequencer_add_track(ue_PyUObject *, PyObject *);
33-
PyObject *py_ue_sequencer_add_actor(ue_PyUObject *, PyObject *);
38+

Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,37 @@ static int ue_py_uscriptstruct_init(ue_PyUScriptStruct *self, PyObject *args, Py
202202
return 0;
203203
}
204204

205+
static PyObject *ue_py_uscriptstruct_richcompare(ue_PyUScriptStruct *u_struct1, PyObject *py_obj, int op) {
206+
ue_PyUScriptStruct *u_struct2 = py_ue_is_uscriptstruct(py_obj);
207+
if (!u_struct2 || (op != Py_EQ && op != Py_NE)) {
208+
return PyErr_Format(PyExc_NotImplementedError, "can only compare with another UScriptStruct");
209+
}
210+
211+
bool equals = (u_struct1->u_struct == u_struct2->u_struct && !memcmp(u_struct1->data, u_struct2->data, u_struct1->u_struct->GetStructureSize()));
212+
213+
if (op == Py_EQ) {
214+
if (equals) {
215+
Py_INCREF(Py_True);
216+
return Py_True;
217+
}
218+
Py_INCREF(Py_False);
219+
return Py_False;
220+
}
221+
222+
if (equals) {
223+
Py_INCREF(Py_False);
224+
return Py_False;
225+
}
226+
Py_INCREF(Py_True);
227+
return Py_True;
228+
}
229+
205230

206231
void ue_python_init_uscriptstruct(PyObject *ue_module) {
207232
ue_PyUScriptStructType.tp_new = PyType_GenericNew;
208233

234+
ue_PyUScriptStructType.tp_richcompare = (richcmpfunc)ue_py_uscriptstruct_richcompare;
235+
209236
ue_PyUScriptStructType.tp_init = (initproc)ue_py_uscriptstruct_init;
210237

211238
if (PyType_Ready(&ue_PyUScriptStructType) < 0)

0 commit comments

Comments
 (0)