Skip to content

Commit 8681a48

Browse files
author
Roberto De Ioris
committed
improved capture and asset export
1 parent 3308e81 commit 8681a48

File tree

8 files changed

+214
-45
lines changed

8 files changed

+214
-45
lines changed

Source/UnrealEnginePython/Private/UEPyEditor.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ PyObject *py_unreal_engine_import_asset(PyObject * self, PyObject * args)
416416
char * filename = PyString_AsString(PyObject_Str(assetsObject));
417417
#endif
418418
files.Add(UTF8_TO_TCHAR(filename));
419-
}
419+
}
420420
else
421421
{
422422
return PyErr_Format(PyExc_Exception, "Not a string nor valid list of string");
@@ -2334,5 +2334,46 @@ PyObject *py_unreal_engine_editor_sync_browser_to_assets(PyObject * self, PyObje
23342334

23352335
Py_RETURN_NONE;
23362336
}
2337+
2338+
PyObject *py_unreal_engine_export_assets(PyObject * self, PyObject * args)
2339+
{
2340+
2341+
if (!GEditor)
2342+
return PyErr_Format(PyExc_Exception, "no GEditor found");
2343+
2344+
PyObject * py_assets = nullptr;
2345+
char *filename;
2346+
2347+
if (!PyArg_ParseTuple(args, "Os:export_assets", &py_assets, &filename))
2348+
{
2349+
return nullptr;
2350+
}
2351+
2352+
TArray<UObject *> UObjects;
2353+
PyObject *py_iter = PyObject_GetIter(py_assets);
2354+
2355+
if (!py_iter)
2356+
{
2357+
return PyErr_Format(PyExc_Exception, "argument is not an iterable of UObject");
2358+
}
2359+
2360+
while (PyObject *py_item = PyIter_Next(py_iter))
2361+
{
2362+
UObject *Object = ue_py_check_type<UObject>(py_item);
2363+
if (!Object)
2364+
{
2365+
Py_DECREF(py_iter);
2366+
return PyErr_Format(PyExc_Exception, "argument is not an iterable of UObject");
2367+
}
2368+
UObjects.Add(Object);
2369+
}
2370+
2371+
Py_DECREF(py_iter);
2372+
2373+
FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
2374+
AssetToolsModule.Get().ExportAssets(UObjects, FString(UTF8_TO_TCHAR(filename)));
2375+
2376+
Py_RETURN_NONE;
2377+
}
23372378
#endif
23382379

Source/UnrealEnginePython/Private/UEPyEditor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,5 @@ PyObject *py_unreal_engine_show_viewer(PyObject *, PyObject *);
120120
PyObject *py_unreal_engine_unregister_settings(PyObject *, PyObject *);
121121

122122
PyObject *py_unreal_engine_request_play_session(PyObject *, PyObject *);
123+
PyObject *py_unreal_engine_export_assets(PyObject *, PyObject *);
123124
#endif

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "UObject/UEPyLandscape.h"
3636
#include "UObject/UEPyUserDefinedStruct.h"
3737
#include "UObject/UEPyDataTable.h"
38+
#include "UObject/UEPyExporter.h"
3839

3940

4041
#include "UEPyAssetUserData.h"
@@ -225,6 +226,7 @@ static PyMethodDef unreal_engine_methods[] = {
225226
{ "editor_select_actor", py_unreal_engine_editor_select_actor, METH_VARARGS, "" },
226227
{ "editor_deselect_actors", py_unreal_engine_editor_deselect_actors, METH_VARARGS, "" },
227228
{ "import_asset", py_unreal_engine_import_asset, METH_VARARGS, "" },
229+
{ "export_assets", py_unreal_engine_export_assets, METH_VARARGS, "" },
228230
{ "get_asset", py_unreal_engine_get_asset, METH_VARARGS, "" },
229231
{ "find_asset", py_unreal_engine_find_asset, METH_VARARGS, "" },
230232
{ "delete_object", py_unreal_engine_delete_object, METH_VARARGS, "" },
@@ -378,6 +380,8 @@ static PyMethodDef unreal_engine_methods[] = {
378380
{ "register_settings", py_unreal_engine_register_settings, METH_VARARGS, "" },
379381
{ "show_viewer", py_unreal_engine_show_viewer, METH_VARARGS, "" },
380382
{ "unregister_settings", py_unreal_engine_unregister_settings, METH_VARARGS, "" },
383+
384+
{ "in_editor_capture", py_unreal_engine_in_editor_capture, METH_VARARGS, "" },
381385
#endif
382386

383387
{ "clipboard_copy", py_unreal_engine_clipboard_copy, METH_VARARGS, "" },
@@ -546,6 +550,8 @@ static PyMethodDef ue_PyUObject_methods[] = {
546550
{ "data_table_get_all_rows", (PyCFunction)py_ue_data_table_get_all_rows, METH_VARARGS, "" },
547551
#endif
548552

553+
{ "export_to_file", (PyCFunction)py_ue_export_to_file, METH_VARARGS, "" },
554+
549555
{ "is_rooted", (PyCFunction)py_ue_is_rooted, METH_VARARGS, "" },
550556
{ "add_to_root", (PyCFunction)py_ue_add_to_root, METH_VARARGS, "" },
551557
{ "auto_root", (PyCFunction)py_ue_auto_root, METH_VARARGS, "" },
@@ -803,7 +809,6 @@ static PyMethodDef ue_PyUObject_methods[] = {
803809
{ "capture_load_from_config", (PyCFunction)py_ue_capture_load_from_config, METH_VARARGS, "" },
804810

805811
#if WITH_EDITOR
806-
{ "in_editor_capture", (PyCFunction)py_ue_in_editor_capture, METH_VARARGS, "" },
807812
{ "set_level_sequence_asset", (PyCFunction)py_ue_set_level_sequence_asset, METH_VARARGS, "" },
808813
#endif
809814

Source/UnrealEnginePython/Private/UObject/UEPyCapture.cpp

Lines changed: 115 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
/*
88
99
This is taken as-is (more or less) from MovieSceneCaptureDialogModule.cpp
10-
to automate sequencer capturing
10+
to automate sequencer capturing. The only relevant implementation is the support
11+
for a queue of UMovieSceneCapture objects
1112
1213
*/
1314

@@ -16,44 +17,61 @@ to automate sequencer capturing
1617
#include "Slate/SceneViewport.h"
1718
#include "AutomatedLevelSequenceCapture.h"
1819

19-
struct FInEditorCapture : TSharedFromThis<FInEditorCapture>
20+
struct FInEditorMultiCapture : TSharedFromThis<FInEditorMultiCapture>
2021
{
2122

22-
static TWeakPtr<FInEditorCapture> CreateInEditorCapture(UMovieSceneCapture* InCaptureObject)
23+
static TWeakPtr<FInEditorMultiCapture> CreateInEditorMultiCapture(TArray<UMovieSceneCapture*> InCaptureObjects)
2324
{
2425
// FInEditorCapture owns itself, so should only be kept alive by itself, or a pinned (=> temporary) weakptr
25-
FInEditorCapture* Capture = new FInEditorCapture;
26-
Capture->Start(InCaptureObject);
26+
FInEditorMultiCapture* Capture = new FInEditorMultiCapture;
27+
Capture->CaptureObjects = InCaptureObjects;
28+
for (UMovieSceneCapture *SceneCapture : Capture->CaptureObjects)
29+
{
30+
SceneCapture->AddToRoot();
31+
}
32+
Capture->Dequeue();
2733
return Capture->AsShared();
2834
}
2935

30-
UWorld* GetWorld() const
36+
private:
37+
FInEditorMultiCapture()
3138
{
32-
return CapturingFromWorld;
39+
CapturingFromWorld = nullptr;
3340
}
3441

35-
private:
36-
FInEditorCapture()
42+
void Die()
3743
{
38-
CapturingFromWorld = nullptr;
39-
CaptureObject = nullptr;
44+
for (UMovieSceneCapture *SceneCapture : CaptureObjects)
45+
{
46+
SceneCapture->RemoveFromRoot();
47+
}
48+
OnlyStrongReference = nullptr;
4049
}
4150

42-
void Start(UMovieSceneCapture* InCaptureObject)
51+
void Dequeue()
4352
{
44-
check(InCaptureObject);
53+
54+
if (CaptureObjects.Num() < 1)
55+
{
56+
Die();
57+
return;
58+
}
59+
60+
CurrentCaptureObject = CaptureObjects[0];
61+
62+
check(CurrentCaptureObject);
4563

4664
CapturingFromWorld = nullptr;
47-
OnlyStrongReference = MakeShareable(this);
4865

49-
CaptureObject = InCaptureObject;
66+
if (!OnlyStrongReference.IsValid())
67+
OnlyStrongReference = MakeShareable(this);
5068

5169
ULevelEditorPlaySettings* PlayInEditorSettings = GetMutableDefault<ULevelEditorPlaySettings>();
5270

5371
bScreenMessagesWereEnabled = GAreScreenMessagesEnabled;
5472
GAreScreenMessagesEnabled = false;
5573

56-
if (!InCaptureObject->Settings.bEnableTextureStreaming)
74+
if (!CurrentCaptureObject->Settings.bEnableTextureStreaming)
5775
{
5876
const int32 UndefinedTexturePoolSize = -1;
5977
IConsoleVariable* CVarStreamingPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.PoolSize"));
@@ -71,14 +89,18 @@ struct FInEditorCapture : TSharedFromThis<FInEditorCapture>
7189
}
7290
}
7391

92+
// cleanup from previous run
93+
BackedUpPlaySettings.Empty();
94+
7495
FObjectWriter(PlayInEditorSettings, BackedUpPlaySettings);
96+
7597
OverridePlaySettings(PlayInEditorSettings);
7698

77-
CaptureObject->AddToRoot();
78-
CaptureObject->OnCaptureFinished().AddRaw(this, &FInEditorCapture::OnEnd);
99+
//CurrentCaptureObject->AddToRoot();
100+
CurrentCaptureObject->OnCaptureFinished().AddRaw(this, &FInEditorMultiCapture::OnEnd);
79101

80-
UGameViewportClient::OnViewportCreated().AddRaw(this, &FInEditorCapture::OnStart);
81-
FEditorDelegates::EndPIE.AddRaw(this, &FInEditorCapture::OnEndPIE);
102+
UGameViewportClient::OnViewportCreated().AddRaw(this, &FInEditorMultiCapture::OnStart);
103+
FEditorDelegates::EndPIE.AddRaw(this, &FInEditorMultiCapture::OnEndPIE);
82104

83105
FAudioDevice* AudioDevice = GEngine->GetMainAudioDevice();
84106
if (AudioDevice != nullptr)
@@ -87,12 +109,19 @@ struct FInEditorCapture : TSharedFromThis<FInEditorCapture>
87109
AudioDevice->SetTransientMasterVolume(0.0f);
88110
}
89111

112+
// play at the next tick
113+
FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateRaw(this, &FInEditorMultiCapture::PlaySession), 0);
114+
}
115+
116+
bool PlaySession(float DeltaTime)
117+
{
90118
GEditor->RequestPlaySession(true, nullptr, false);
119+
return false;
91120
}
92121

93122
void OverridePlaySettings(ULevelEditorPlaySettings* PlayInEditorSettings)
94123
{
95-
const FMovieSceneCaptureSettings& Settings = CaptureObject->GetSettings();
124+
const FMovieSceneCaptureSettings& Settings = CurrentCaptureObject->GetSettings();
96125

97126
PlayInEditorSettings->NewWindowWidth = Settings.Resolution.ResX;
98127
PlayInEditorSettings->NewWindowHeight = Settings.Resolution.ResY;
@@ -150,7 +179,7 @@ struct FInEditorCapture : TSharedFromThis<FInEditorCapture>
150179

151180
TSharedPtr<SWindow> Window = SlatePlayInEditorSession->SlatePlayInEditorWindow.Pin();
152181

153-
const FMovieSceneCaptureSettings& Settings = CaptureObject->GetSettings();
182+
const FMovieSceneCaptureSettings& Settings = CurrentCaptureObject->GetSettings();
154183

155184
SlatePlayInEditorSession->SlatePlayInEditorWindowViewport->SetViewportSize(Settings.Resolution.ResX, Settings.Resolution.ResY);
156185

@@ -171,30 +200,29 @@ struct FInEditorCapture : TSharedFromThis<FInEditorCapture>
171200
FVector2D PreviewWindowPosition(50, 50);
172201
Window->ReshapeWindow(PreviewWindowPosition, PreviewWindowSize);
173202

174-
if (CaptureObject->Settings.GameModeOverride != nullptr)
203+
if (CurrentCaptureObject->Settings.GameModeOverride != nullptr)
175204
{
176205
CachedGameMode = CapturingFromWorld->GetWorldSettings()->DefaultGameMode;
177-
CapturingFromWorld->GetWorldSettings()->DefaultGameMode = CaptureObject->Settings.GameModeOverride;
206+
CapturingFromWorld->GetWorldSettings()->DefaultGameMode = CurrentCaptureObject->Settings.GameModeOverride;
178207
}
179208

180-
CaptureObject->Initialize(SlatePlayInEditorSession->SlatePlayInEditorWindowViewport, Context.PIEInstance);
209+
CurrentCaptureObject->Initialize(SlatePlayInEditorSession->SlatePlayInEditorWindowViewport, Context.PIEInstance);
181210
}
182211
return;
183212
}
184213
}
185214

186-
// todo: error?
187215
}
188216

189217
void Shutdown()
190218
{
191219
FEditorDelegates::EndPIE.RemoveAll(this);
192220
UGameViewportClient::OnViewportCreated().RemoveAll(this);
193-
CaptureObject->OnCaptureFinished().RemoveAll(this);
221+
CurrentCaptureObject->OnCaptureFinished().RemoveAll(this);
194222

195223
GAreScreenMessagesEnabled = bScreenMessagesWereEnabled;
196224

197-
if (!CaptureObject->Settings.bEnableTextureStreaming)
225+
if (!CurrentCaptureObject->Settings.bEnableTextureStreaming)
198226
{
199227
IConsoleVariable* CVarStreamingPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.PoolSize"));
200228
if (CVarStreamingPoolSize)
@@ -209,7 +237,7 @@ struct FInEditorCapture : TSharedFromThis<FInEditorCapture>
209237
}
210238
}
211239

212-
if (CaptureObject->Settings.GameModeOverride != nullptr)
240+
if (CurrentCaptureObject->Settings.GameModeOverride != nullptr)
213241
{
214242
CapturingFromWorld->GetWorldSettings()->DefaultGameMode = CachedGameMode;
215243
}
@@ -222,46 +250,93 @@ struct FInEditorCapture : TSharedFromThis<FInEditorCapture>
222250
AudioDevice->SetTransientMasterVolume(TransientMasterVolume);
223251
}
224252

225-
CaptureObject->Close();
226-
CaptureObject->RemoveFromRoot();
253+
CurrentCaptureObject->Close();
254+
//CurrentCaptureObject->RemoveFromRoot();
227255

228256
}
229257
void OnEndPIE(bool bIsSimulating)
230258
{
231259
Shutdown();
232-
OnlyStrongReference = nullptr;
260+
261+
Die();
262+
}
263+
264+
void NextCapture(bool bIsSimulating)
265+
{
266+
267+
FEditorDelegates::EndPIE.RemoveAll(this);
268+
// remove item from the TArray;
269+
CaptureObjects.RemoveAt(0);
270+
271+
if (CaptureObjects.Num() > 0)
272+
{
273+
Dequeue();
274+
}
275+
else
276+
{
277+
Die();
278+
}
233279
}
234280

235281
void OnEnd()
236282
{
237283
Shutdown();
238-
OnlyStrongReference = nullptr;
239284

285+
FEditorDelegates::EndPIE.AddRaw(this, &FInEditorMultiCapture::NextCapture);
240286
GEditor->RequestEndPlayMap();
241287
}
242288

243-
TSharedPtr<FInEditorCapture> OnlyStrongReference;
289+
TSharedPtr<FInEditorMultiCapture> OnlyStrongReference;
244290
UWorld* CapturingFromWorld;
245291

246292
bool bScreenMessagesWereEnabled;
247293
float TransientMasterVolume;
248294
int32 BackedUpStreamingPoolSize;
249295
int32 BackedUpUseFixedPoolSize;
250296
TArray<uint8> BackedUpPlaySettings;
251-
UMovieSceneCapture* CaptureObject;
297+
UMovieSceneCapture* CurrentCaptureObject;
252298

253299
TSubclassOf<AGameModeBase> CachedGameMode;
300+
TArray<UMovieSceneCapture*> CaptureObjects;
254301
};
255302

256-
PyObject *py_ue_in_editor_capture(ue_PyUObject * self, PyObject * args)
303+
PyObject *py_unreal_engine_in_editor_capture(PyObject * self, PyObject * args)
257304
{
258-
ue_py_check(self);
305+
PyObject *py_scene_captures;
259306

260-
UMovieSceneCapture *capture = ue_py_check_type<UMovieSceneCapture>(self);
307+
if (!PyArg_ParseTuple(args, "O:in_editor_capture", &py_scene_captures))
308+
{
309+
return nullptr;
310+
}
311+
312+
TArray<UMovieSceneCapture *> Captures;
313+
314+
UMovieSceneCapture *capture = ue_py_check_type<UMovieSceneCapture>(py_scene_captures);
261315
if (!capture)
262-
return PyErr_Format(PyExc_Exception, "uobject is not a UMovieSceneCapture");
316+
{
317+
PyObject *py_iter = PyObject_GetIter(py_scene_captures);
318+
if (!py_iter)
319+
{
320+
return PyErr_Format(PyExc_Exception, "argument is not a UMovieSceneCapture or an iterable of UMovieSceneCapture");
321+
}
322+
while (PyObject *py_item = PyIter_Next(py_iter))
323+
{
324+
capture = ue_py_check_type<UMovieSceneCapture>(py_item);
325+
if (!capture)
326+
{
327+
Py_DECREF(py_iter);
328+
return PyErr_Format(PyExc_Exception, "argument is not an iterable of UMovieSceneCapture");
329+
}
330+
Captures.Add(capture);
331+
}
332+
Py_DECREF(py_iter);
333+
}
334+
else
335+
{
336+
Captures.Add(capture);
337+
}
263338

264-
FInEditorCapture::CreateInEditorCapture(capture);
339+
FInEditorMultiCapture::CreateInEditorMultiCapture(Captures);
265340

266341
Py_RETURN_NONE;
267342
}

0 commit comments

Comments
 (0)