Files
UnrealEngineUWP/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceModule.cpp
max chen e79d483962 Sequencer: Follow up to 17449329. Move output message inside if
#preflight 6136ee48d9c85a000100d865

#ROBOMERGE-AUTHOR: max.chen
#ROBOMERGE-SOURCE: CL 17450045 via CL 17910610 via CL 18360659 via CL 18360813
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v895-18170469)

[CL 18360865 by max chen in ue5-release-engine-test branch]
2021-12-02 18:04:55 -05:00

345 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "LevelSequenceModule.h"
#include "Modules/ModuleManager.h"
#include "LevelSequence.h"
#include "LevelSequenceActor.h"
#include "LevelSequenceActorSpawner.h"
#include "MovieSceneSequencePlayer.h"
#include "UObject/UObjectBaseUtility.h"
DEFINE_LOG_CATEGORY(LogLevelSequence);
void FLevelSequenceModule::StartupModule()
{
OnCreateMovieSceneObjectSpawnerDelegateHandle = RegisterObjectSpawner(FOnCreateMovieSceneObjectSpawner::CreateStatic(&FLevelSequenceActorSpawner::CreateObjectSpawner));
}
void FLevelSequenceModule::ShutdownModule()
{
UnregisterObjectSpawner(OnCreateMovieSceneObjectSpawnerDelegateHandle);
}
namespace
{
static AActor* FindActorBySequenceName(const FString& SequenceNameStr, UWorld* InWorld)
{
for (ULevel* Level : InWorld->GetLevels())
{
if (Level)
{
for (AActor* Actor : Level->Actors)
{
if (ALevelSequenceActor* LevelSequenceActor = Cast<ALevelSequenceActor>(Actor))
{
ULevelSequence* LevelSequence = LevelSequenceActor->GetSequence();
if (LevelSequence && GetNameSafe(LevelSequence) == SequenceNameStr)
{
return Actor;
}
}
}
}
}
return nullptr;
}
TArray<TWeakObjectPtr<UMovieSceneSequencePlayer>> GetLevelSequencePlayers(UWorld* InWorld, const TCHAR** InStr, FOutputDevice& Ar)
{
TArray<TWeakObjectPtr<UMovieSceneSequencePlayer>> LevelSequencePlayers;
FString SequencesString = FParse::Token(*InStr, 0);
TArray<FString> Splits;
SequencesString.ParseIntoArray(Splits, TEXT(","));
for (FString Split : Splits)
{
AActor* FoundActor = FindActorBySequenceName(Split, InWorld);
if (ALevelSequenceActor* LevelSequenceActor = Cast<ALevelSequenceActor>(FoundActor))
{
UMovieSceneSequencePlayer* Player = LevelSequenceActor->GetSequencePlayer();
if (!Player)
{
LevelSequenceActor->InitializePlayer();
}
if (Player)
{
LevelSequencePlayers.Add(Player);
}
}
}
return LevelSequencePlayers;
}
bool HandleLevelSequencePlay(UWorld* InWorld, const TCHAR** InStr, FOutputDevice& Ar)
{
TArray<TWeakObjectPtr<UMovieSceneSequencePlayer> > LevelSequencePlayers = GetLevelSequencePlayers(InWorld, InStr, Ar);
if (LevelSequencePlayers.Num() == 0)
{
Ar.Log(TEXT("No level sequences found."));
return false;
}
for (TWeakObjectPtr<UMovieSceneSequencePlayer> LevelSequencePlayer : LevelSequencePlayers)
{
if (LevelSequencePlayer.Get())
{
LevelSequencePlayer.Get()->Play();
}
}
return true;
}
bool HandleLevelSequencePause(UWorld* InWorld, const TCHAR** InStr, FOutputDevice& Ar)
{
TArray<TWeakObjectPtr<UMovieSceneSequencePlayer> > LevelSequencePlayers = GetLevelSequencePlayers(InWorld, InStr, Ar);
if (LevelSequencePlayers.Num() == 0)
{
Ar.Log(TEXT("No level sequences found."));
return false;
}
for (TWeakObjectPtr<UMovieSceneSequencePlayer> LevelSequencePlayer : LevelSequencePlayers)
{
if (LevelSequencePlayer.Get())
{
LevelSequencePlayer.Get()->Pause();
}
}
return true;
}
bool HandleLevelSequenceStop(UWorld* InWorld, const TCHAR** InStr, FOutputDevice& Ar)
{
TArray<TWeakObjectPtr<UMovieSceneSequencePlayer> > LevelSequencePlayers = GetLevelSequencePlayers(InWorld, InStr, Ar);
if (LevelSequencePlayers.Num() == 0)
{
Ar.Log(TEXT("No level sequences found."));
return false;
}
for (TWeakObjectPtr<UMovieSceneSequencePlayer> LevelSequencePlayer : LevelSequencePlayers)
{
if (LevelSequencePlayer.Get())
{
LevelSequencePlayer.Get()->Stop();
}
}
return true;
}
bool HandleLevelSequenceSetPlaybackPosition(UWorld* InWorld, const TCHAR** InStr, FOutputDevice& Ar)
{
TArray<TWeakObjectPtr<UMovieSceneSequencePlayer> > LevelSequencePlayers = GetLevelSequencePlayers(InWorld, InStr, Ar);
if (LevelSequencePlayers.Num() == 0)
{
Ar.Log(TEXT("No level sequences found."));
return false;
}
FString FrameNumberString = FParse::Token(*InStr, 0);
if (!FChar::IsDigit(**FrameNumberString))
{
Ar.Logf(TEXT("Invalid frame number to set playback position to: %s"), *FrameNumberString);
return false;
}
int32 FrameNumber = FCString::Atoi(*FrameNumberString);
Ar.Logf(TEXT("Setting playback position to: %d"), FrameNumber);
for (TWeakObjectPtr<UMovieSceneSequencePlayer> LevelSequencePlayer : LevelSequencePlayers)
{
if (LevelSequencePlayer.Get())
{
FMovieSceneSequencePlaybackParams PlaybackParams(FFrameTime(FrameNumber), EUpdatePositionMethod::Play);
LevelSequencePlayer.Get()->SetPlaybackPosition(PlaybackParams);
}
}
return true;
}
bool HandleLevelSequencePlayTo(UWorld* InWorld, const TCHAR** InStr, FOutputDevice& Ar)
{
TArray<TWeakObjectPtr<UMovieSceneSequencePlayer> > LevelSequencePlayers = GetLevelSequencePlayers(InWorld, InStr, Ar);
if (LevelSequencePlayers.Num() == 0)
{
Ar.Log(TEXT("No level sequences found."));
return false;
}
FString FrameNumberString = FParse::Token(*InStr, 0);
if (!FChar::IsDigit(**FrameNumberString))
{
Ar.Logf(TEXT("Invalid frame number to play to: %s"), *FrameNumberString);
return false;
}
int32 FrameNumber = FCString::Atoi(*FrameNumberString);
Ar.Logf(TEXT("Playing to: %d"), FrameNumber);
for (TWeakObjectPtr<UMovieSceneSequencePlayer> LevelSequencePlayer : LevelSequencePlayers)
{
if (LevelSequencePlayer.Get())
{
FMovieSceneSequencePlaybackParams PlaybackParams(FFrameTime(FrameNumber), EUpdatePositionMethod::Play);
FMovieSceneSequencePlayToParams PlayToParams;
LevelSequencePlayer.Get()->PlayTo(PlaybackParams, PlayToParams);
}
}
return true;
}
bool HandleLevelSequenceSetClockSource(UWorld* InWorld, const TCHAR** InStr, FOutputDevice& Ar)
{
TArray<TWeakObjectPtr<UMovieSceneSequencePlayer> > LevelSequencePlayers = GetLevelSequencePlayers(InWorld, InStr, Ar);
if (LevelSequencePlayers.Num() == 0)
{
Ar.Log(TEXT("No level sequences found."));
return false;
}
FString ClockSource = FParse::Token(*InStr, 0);
TSharedPtr<FMovieSceneTimeController> TimeController;
if (ClockSource.Compare("Tick", ESearchCase::IgnoreCase) == 0)
{
TimeController = MakeShared<FMovieSceneTimeController_Tick>();
}
else if (ClockSource.Compare("Audio", ESearchCase::IgnoreCase) == 0)
{
TimeController = MakeShared<FMovieSceneTimeController_AudioClock>();
}
else if (ClockSource.Compare("Platform", ESearchCase::IgnoreCase) == 0)
{
TimeController = MakeShared<FMovieSceneTimeController_PlatformClock>();
}
else if (ClockSource.Compare("RelativeTimecode", ESearchCase::IgnoreCase) == 0)
{
TimeController = MakeShared<FMovieSceneTimeController_RelativeTimecodeClock>();
}
else if (ClockSource.Compare("Timecode", ESearchCase::IgnoreCase) == 0)
{
TimeController = MakeShared<FMovieSceneTimeController_TimecodeClock>();
}
else if (ClockSource.Compare("PlayEveryFrame", ESearchCase::IgnoreCase) == 0)
{
TimeController = MakeShared<FMovieSceneTimeController_PlayEveryFrame>();
}
else
{
Ar.Log(TEXT("Unknown clock source. Valid clock sources are: Tick, Audio, Platform, RelativeTimecode, Timecode, PlayEveryFrame"));
return false;
}
for (TWeakObjectPtr<UMovieSceneSequencePlayer> LevelSequencePlayer : LevelSequencePlayers)
{
if (LevelSequencePlayer.Get())
{
LevelSequencePlayer.Get()->SetTimeController(TimeController);
}
}
return true;
}
} // empty namespace
bool FLevelSequenceModule::Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar)
{
if (FParse::Command(&Cmd, TEXT("Sequencer")))
{
if (FParse::Command(&Cmd, TEXT("Play")))
{
if (HandleLevelSequencePlay(InWorld, &Cmd, Ar))
{
return true;
}
}
else if (FParse::Command(&Cmd, TEXT("Pause")))
{
if (HandleLevelSequencePause(InWorld, &Cmd, Ar))
{
return true;
}
}
else if (FParse::Command(&Cmd, TEXT("Stop")))
{
if (HandleLevelSequenceStop(InWorld, &Cmd, Ar))
{
return true;
}
}
else if (FParse::Command(&Cmd, TEXT("SetPlaybackPosition")))
{
if (HandleLevelSequenceSetPlaybackPosition(InWorld, &Cmd, Ar))
{
return true;
}
}
else if (FParse::Command(&Cmd, TEXT("PlayTo")))
{
if (HandleLevelSequencePlayTo(InWorld, &Cmd, Ar))
{
return true;
}
}
else if (FParse::Command(&Cmd, TEXT("SetClockSource")))
{
if (HandleLevelSequenceSetClockSource(InWorld, &Cmd, Ar))
{
return true;
}
}
// show usage
Ar.Log(TEXT("Usage: Sequencer <Command>"));
Ar.Log(TEXT(""));
Ar.Log(TEXT("Command"));
Ar.Log(TEXT(" Play <SequenceName> = Start playback forwards from the current time cursor position, using the current play rate"));
Ar.Log(TEXT(" Pause <SequenceName> = Pause playback"));
Ar.Log(TEXT(" Stop <SequenceName> = Stop playback and move the cursor to the end (or start, for reversed playback) of the sequence"));
Ar.Log(TEXT(" SetPlaybackPosition <SequenceName> <FrameNumber> = Set the current time of the player by evaluating from the current time to the specified time"));
Ar.Log(TEXT(" PlayTo <SequenceName> <FrameNumber> = Play from the current position to the requested position and pause"));
Ar.Log(TEXT(" SetClockSource <SequenceName> <ClockSource, ie. Tick, Audio, PlayEveryFrame> = Set the clock source"));
}
return false;
}
FDelegateHandle FLevelSequenceModule::RegisterObjectSpawner(FOnCreateMovieSceneObjectSpawner InOnCreateMovieSceneObjectSpawner)
{
OnCreateMovieSceneObjectSpawnerDelegates.Add(InOnCreateMovieSceneObjectSpawner);
return OnCreateMovieSceneObjectSpawnerDelegates.Last().GetHandle();
}
void FLevelSequenceModule::UnregisterObjectSpawner(FDelegateHandle InHandle)
{
OnCreateMovieSceneObjectSpawnerDelegates.RemoveAll([=](const FOnCreateMovieSceneObjectSpawner& Delegate) { return Delegate.GetHandle() == InHandle; });
}
void FLevelSequenceModule::GenerateObjectSpawners(TArray<TSharedRef<IMovieSceneObjectSpawner>>& OutSpawners) const
{
for (const FOnCreateMovieSceneObjectSpawner& SpawnerFactory : OnCreateMovieSceneObjectSpawnerDelegates)
{
check(SpawnerFactory.IsBound());
OutSpawners.Add(SpawnerFactory.Execute());
}
// Now sort the spawners. Editor spawners should come first so they override runtime versions of the same supported type in-editor.
// @TODO: we could also sort by most-derived type here to allow for type specific behaviors
OutSpawners.Sort([](TSharedRef<IMovieSceneObjectSpawner> LHS, TSharedRef<IMovieSceneObjectSpawner> RHS)
{
return LHS->IsEditor() > RHS->IsEditor();
});
}
IMPLEMENT_MODULE(FLevelSequenceModule, LevelSequence);