Skip to content

Commit 120e16d

Browse files
author
Roberto De Ioris
committed
added automation for level sequence exporter
1 parent 9920aac commit 120e16d

File tree

3 files changed

+297
-17
lines changed

3 files changed

+297
-17
lines changed

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,11 @@ static PyMethodDef ue_PyUObject_methods[] = {
802802
{ "capture_stop", (PyCFunction)py_ue_capture_stop, METH_VARARGS, "" },
803803
{ "capture_load_from_config", (PyCFunction)py_ue_capture_load_from_config, METH_VARARGS, "" },
804804

805+
#if WITH_EDITOR
806+
{ "in_editor_capture", (PyCFunction)py_ue_in_editor_capture, METH_VARARGS, "" },
807+
{ "set_level_sequence_asset", (PyCFunction)py_ue_set_level_sequence_asset, METH_VARARGS, "" },
808+
#endif
809+
805810
// Pawn
806811
{ "get_controller", (PyCFunction)py_ue_pawn_get_controller, METH_VARARGS, "" },
807812

Source/UnrealEnginePython/Private/UObject/UEPyCapture.cpp

Lines changed: 288 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,294 @@
22

33
#include "Runtime/MovieSceneCapture/Public/MovieSceneCapture.h"
44

5+
#if WITH_EDITOR
6+
7+
/*
8+
9+
This is taken as-is (more or less) from MovieSceneCaptureDialogModule.cpp
10+
to automate sequencer capturing
11+
12+
*/
13+
14+
#include "AudioDevice.h"
15+
#include "Editor/EditorEngine.h"
16+
#include "Slate/SceneViewport.h"
17+
#include "AutomatedLevelSequenceCapture.h"
18+
19+
struct FInEditorCapture : TSharedFromThis<FInEditorCapture>
20+
{
21+
22+
static TWeakPtr<FInEditorCapture> CreateInEditorCapture(UMovieSceneCapture* InCaptureObject)
23+
{
24+
// 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);
27+
return Capture->AsShared();
28+
}
29+
30+
UWorld* GetWorld() const
31+
{
32+
return CapturingFromWorld;
33+
}
34+
35+
private:
36+
FInEditorCapture()
37+
{
38+
CapturingFromWorld = nullptr;
39+
CaptureObject = nullptr;
40+
}
41+
42+
void Start(UMovieSceneCapture* InCaptureObject)
43+
{
44+
check(InCaptureObject);
45+
46+
CapturingFromWorld = nullptr;
47+
OnlyStrongReference = MakeShareable(this);
48+
49+
CaptureObject = InCaptureObject;
50+
51+
ULevelEditorPlaySettings* PlayInEditorSettings = GetMutableDefault<ULevelEditorPlaySettings>();
52+
53+
bScreenMessagesWereEnabled = GAreScreenMessagesEnabled;
54+
GAreScreenMessagesEnabled = false;
55+
56+
if (!InCaptureObject->Settings.bEnableTextureStreaming)
57+
{
58+
const int32 UndefinedTexturePoolSize = -1;
59+
IConsoleVariable* CVarStreamingPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.PoolSize"));
60+
if (CVarStreamingPoolSize)
61+
{
62+
BackedUpStreamingPoolSize = CVarStreamingPoolSize->GetInt();
63+
CVarStreamingPoolSize->Set(UndefinedTexturePoolSize, ECVF_SetByConsole);
64+
}
65+
66+
IConsoleVariable* CVarUseFixedPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.UseFixedPoolSize"));
67+
if (CVarUseFixedPoolSize)
68+
{
69+
BackedUpUseFixedPoolSize = CVarUseFixedPoolSize->GetInt();
70+
CVarUseFixedPoolSize->Set(0, ECVF_SetByConsole);
71+
}
72+
}
73+
74+
FObjectWriter(PlayInEditorSettings, BackedUpPlaySettings);
75+
OverridePlaySettings(PlayInEditorSettings);
76+
77+
CaptureObject->AddToRoot();
78+
CaptureObject->OnCaptureFinished().AddRaw(this, &FInEditorCapture::OnEnd);
79+
80+
UGameViewportClient::OnViewportCreated().AddRaw(this, &FInEditorCapture::OnStart);
81+
FEditorDelegates::EndPIE.AddRaw(this, &FInEditorCapture::OnEndPIE);
82+
83+
FAudioDevice* AudioDevice = GEngine->GetMainAudioDevice();
84+
if (AudioDevice != nullptr)
85+
{
86+
TransientMasterVolume = AudioDevice->GetTransientMasterVolume();
87+
AudioDevice->SetTransientMasterVolume(0.0f);
88+
}
89+
90+
GEditor->RequestPlaySession(true, nullptr, false);
91+
}
92+
93+
void OverridePlaySettings(ULevelEditorPlaySettings* PlayInEditorSettings)
94+
{
95+
const FMovieSceneCaptureSettings& Settings = CaptureObject->GetSettings();
96+
97+
PlayInEditorSettings->NewWindowWidth = Settings.Resolution.ResX;
98+
PlayInEditorSettings->NewWindowHeight = Settings.Resolution.ResY;
99+
PlayInEditorSettings->CenterNewWindow = true;
100+
PlayInEditorSettings->LastExecutedPlayModeType = EPlayModeType::PlayMode_InEditorFloating;
101+
102+
TSharedRef<SWindow> CustomWindow = SNew(SWindow)
103+
.Title(FText::FromString("Movie Render - Preview"))
104+
.AutoCenter(EAutoCenter::PrimaryWorkArea)
105+
.UseOSWindowBorder(true)
106+
.FocusWhenFirstShown(false)
107+
.ActivationPolicy(EWindowActivationPolicy::Never)
108+
.HasCloseButton(true)
109+
.SupportsMaximize(false)
110+
.SupportsMinimize(true)
111+
.MaxWidth(Settings.Resolution.ResX)
112+
.MaxHeight(Settings.Resolution.ResY)
113+
.SizingRule(ESizingRule::FixedSize);
114+
115+
FSlateApplication::Get().AddWindow(CustomWindow);
116+
117+
PlayInEditorSettings->CustomPIEWindow = CustomWindow;
118+
119+
// Reset everything else
120+
PlayInEditorSettings->GameGetsMouseControl = false;
121+
PlayInEditorSettings->ShowMouseControlLabel = false;
122+
PlayInEditorSettings->ViewportGetsHMDControl = false;
123+
PlayInEditorSettings->ShouldMinimizeEditorOnVRPIE = true;
124+
PlayInEditorSettings->EnableGameSound = false;
125+
PlayInEditorSettings->bOnlyLoadVisibleLevelsInPIE = false;
126+
PlayInEditorSettings->bPreferToStreamLevelsInPIE = false;
127+
PlayInEditorSettings->PIEAlwaysOnTop = false;
128+
PlayInEditorSettings->DisableStandaloneSound = true;
129+
PlayInEditorSettings->AdditionalLaunchParameters = TEXT("");
130+
PlayInEditorSettings->BuildGameBeforeLaunch = EPlayOnBuildMode::PlayOnBuild_Never;
131+
PlayInEditorSettings->LaunchConfiguration = EPlayOnLaunchConfiguration::LaunchConfig_Default;
132+
PlayInEditorSettings->SetPlayNetMode(EPlayNetMode::PIE_Standalone);
133+
PlayInEditorSettings->SetRunUnderOneProcess(true);
134+
PlayInEditorSettings->SetPlayNetDedicated(false);
135+
PlayInEditorSettings->SetPlayNumberOfClients(1);
136+
}
137+
138+
void OnStart()
139+
{
140+
for (const FWorldContext& Context : GEngine->GetWorldContexts())
141+
{
142+
if (Context.WorldType == EWorldType::PIE)
143+
{
144+
FSlatePlayInEditorInfo* SlatePlayInEditorSession = GEditor->SlatePlayInEditorMap.Find(Context.ContextHandle);
145+
if (SlatePlayInEditorSession)
146+
{
147+
CapturingFromWorld = Context.World();
148+
149+
TSharedPtr<SWindow> Window = SlatePlayInEditorSession->SlatePlayInEditorWindow.Pin();
150+
151+
const FMovieSceneCaptureSettings& Settings = CaptureObject->GetSettings();
152+
153+
SlatePlayInEditorSession->SlatePlayInEditorWindowViewport->SetViewportSize(Settings.Resolution.ResX, Settings.Resolution.ResY);
154+
155+
FVector2D PreviewWindowSize(Settings.Resolution.ResX, Settings.Resolution.ResY);
156+
157+
// Keep scaling down the window size while we're bigger than half the destop width/height
158+
{
159+
FDisplayMetrics DisplayMetrics;
160+
FSlateApplication::Get().GetDisplayMetrics(DisplayMetrics);
161+
162+
while (PreviewWindowSize.X >= DisplayMetrics.PrimaryDisplayWidth*.5f || PreviewWindowSize.Y >= DisplayMetrics.PrimaryDisplayHeight*.5f)
163+
{
164+
PreviewWindowSize *= .5f;
165+
}
166+
}
167+
168+
// Resize and move the window into the desktop a bit
169+
FVector2D PreviewWindowPosition(50, 50);
170+
Window->ReshapeWindow(PreviewWindowPosition, PreviewWindowSize);
171+
172+
if (CaptureObject->Settings.GameModeOverride != nullptr)
173+
{
174+
CachedGameMode = CapturingFromWorld->GetWorldSettings()->DefaultGameMode;
175+
CapturingFromWorld->GetWorldSettings()->DefaultGameMode = CaptureObject->Settings.GameModeOverride;
176+
}
177+
178+
CaptureObject->Initialize(SlatePlayInEditorSession->SlatePlayInEditorWindowViewport, Context.PIEInstance);
179+
}
180+
return;
181+
}
182+
}
183+
184+
// todo: error?
185+
}
186+
187+
void Shutdown()
188+
{
189+
FEditorDelegates::EndPIE.RemoveAll(this);
190+
UGameViewportClient::OnViewportCreated().RemoveAll(this);
191+
CaptureObject->OnCaptureFinished().RemoveAll(this);
192+
193+
GAreScreenMessagesEnabled = bScreenMessagesWereEnabled;
194+
195+
if (!CaptureObject->Settings.bEnableTextureStreaming)
196+
{
197+
IConsoleVariable* CVarStreamingPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.PoolSize"));
198+
if (CVarStreamingPoolSize)
199+
{
200+
CVarStreamingPoolSize->Set(BackedUpStreamingPoolSize, ECVF_SetByConsole);
201+
}
202+
203+
IConsoleVariable* CVarUseFixedPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.UseFixedPoolSize"));
204+
if (CVarUseFixedPoolSize)
205+
{
206+
CVarUseFixedPoolSize->Set(BackedUpUseFixedPoolSize, ECVF_SetByConsole);
207+
}
208+
}
209+
210+
if (CaptureObject->Settings.GameModeOverride != nullptr)
211+
{
212+
CapturingFromWorld->GetWorldSettings()->DefaultGameMode = CachedGameMode;
213+
}
214+
215+
FObjectReader(GetMutableDefault<ULevelEditorPlaySettings>(), BackedUpPlaySettings);
216+
217+
FAudioDevice* AudioDevice = GEngine->GetMainAudioDevice();
218+
if (AudioDevice != nullptr)
219+
{
220+
AudioDevice->SetTransientMasterVolume(TransientMasterVolume);
221+
}
222+
223+
CaptureObject->Close();
224+
CaptureObject->RemoveFromRoot();
225+
226+
}
227+
void OnEndPIE(bool bIsSimulating)
228+
{
229+
Shutdown();
230+
OnlyStrongReference = nullptr;
231+
}
232+
233+
void OnEnd()
234+
{
235+
Shutdown();
236+
OnlyStrongReference = nullptr;
237+
238+
GEditor->RequestEndPlayMap();
239+
}
240+
241+
TSharedPtr<FInEditorCapture> OnlyStrongReference;
242+
UWorld* CapturingFromWorld;
243+
244+
bool bScreenMessagesWereEnabled;
245+
float TransientMasterVolume;
246+
int32 BackedUpStreamingPoolSize;
247+
int32 BackedUpUseFixedPoolSize;
248+
TArray<uint8> BackedUpPlaySettings;
249+
UMovieSceneCapture* CaptureObject;
250+
251+
TSubclassOf<AGameModeBase> CachedGameMode;
252+
};
253+
254+
PyObject *py_ue_in_editor_capture(ue_PyUObject * self, PyObject * args)
255+
{
256+
ue_py_check(self);
257+
258+
UMovieSceneCapture *capture = ue_py_check_type<UMovieSceneCapture>(self);
259+
if (!capture)
260+
return PyErr_Format(PyExc_Exception, "uobject is not a UMovieSceneCapture");
261+
262+
FInEditorCapture::CreateInEditorCapture(capture);
263+
264+
Py_RETURN_NONE;
265+
}
266+
267+
PyObject *py_ue_set_level_sequence_asset(ue_PyUObject *self, PyObject *args)
268+
{
269+
ue_py_check(self);
270+
271+
PyObject *py_sequence = nullptr;
272+
273+
if (!PyArg_ParseTuple(args, "O:set_level_sequence_asset", &py_sequence))
274+
{
275+
return nullptr;
276+
}
277+
278+
ULevelSequence *sequence = ue_py_check_type<ULevelSequence>(py_sequence);
279+
if (!sequence)
280+
{
281+
return PyErr_Format(PyExc_Exception, "uobject is not a ULevelSequence");
282+
}
283+
284+
UAutomatedLevelSequenceCapture *capture = ue_py_check_type<UAutomatedLevelSequenceCapture>(self);
285+
if (!capture)
286+
return PyErr_Format(PyExc_Exception, "uobject is not a UAutomatedLevelSequenceCapture");
287+
288+
capture->SetLevelSequenceAsset(sequence->GetPathName());
289+
290+
Py_RETURN_NONE;
291+
}
292+
#endif
5293

6294
PyObject *py_ue_capture_initialize(ue_PyUObject * self, PyObject * args)
7295
{
@@ -39,22 +327,6 @@ PyObject *py_ue_capture_initialize(ue_PyUObject * self, PyObject * args)
39327
}
40328

41329
}
42-
else
43-
{
44-
for (const FWorldContext &Context : GEngine->GetWorldContexts())
45-
{
46-
if (Context.WorldType == EWorldType::PIE)
47-
{
48-
if (Context.GameViewport)
49-
{
50-
UE_LOG(LogPython, Error, TEXT("Found Viewport at %p"), Context.GameViewport);
51-
FSlatePlayInEditorInfo *SlatePIEInfo = GEditor->SlatePlayInEditorMap.Find(Context.ContextHandle);
52-
53-
capture->Initialize(SlatePIEInfo->SlatePlayInEditorWindowViewport);
54-
}
55-
}
56-
}
57-
}
58330
#endif
59331
Py_RETURN_NONE;
60332
}

Source/UnrealEnginePython/Private/UObject/UEPyCapture.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@
77
PyObject *py_ue_capture_initialize(ue_PyUObject *, PyObject *);
88
PyObject *py_ue_capture_start(ue_PyUObject *, PyObject *);
99
PyObject *py_ue_capture_load_from_config(ue_PyUObject *, PyObject *);
10-
PyObject *py_ue_capture_stop(ue_PyUObject *, PyObject *);
10+
PyObject *py_ue_capture_stop(ue_PyUObject *, PyObject *);
11+
12+
PyObject *py_ue_in_editor_capture(ue_PyUObject *, PyObject *);
13+
PyObject *py_ue_set_level_sequence_asset(ue_PyUObject *, PyObject *);

0 commit comments

Comments
 (0)