SequenceRecorder

SequenceRecorder

#Overview

name: SequenceRecorder

This variable is created as a Console Variable (cvar).

It is referenced in 19 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of SequenceRecorder is to provide functionality for recording gameplay and actor movements in Unreal Engine, allowing developers to create cinematic sequences or capture in-game actions for later use or analysis.

SequenceRecorder is primarily used in the editor environment and is part of the Unreal Engine’s editor toolset. Based on the callsites, it interacts with several subsystems and modules:

  1. Sequencer module
  2. MediaCompositingEditor module
  3. GameplayAbilities system
  4. ActorGroupDetailsCustomization

The value of this variable is typically set when the SequenceRecorder module is loaded or initialized. It’s often accessed through the FModuleManager to get the module instance.

Other variables that interact with SequenceRecorder include:

Developers should be aware of the following when using SequenceRecorder:

  1. It’s primarily an editor-time tool, not meant for runtime use.
  2. It can be extended with custom functionality using ISequenceRecorderExtender.
  3. It interacts with the Sequencer system for creating and manipulating sequences.
  4. It has the ability to record actor movements and gameplay actions.

Best practices when using SequenceRecorder:

  1. Ensure the module is loaded before attempting to use its functionality.
  2. Use the provided interfaces and extension points rather than directly modifying the core implementation.
  3. Be mindful of performance implications when recording extensive gameplay or complex scenes.
  4. Properly manage any custom extensions added to the SequenceRecorder to avoid memory leaks or conflicts.
  5. Use the SequenceRecorder in conjunction with other Unreal Engine tools like Sequencer for best results in creating cinematic content.

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/SequenceRecorderModule.cpp:894

Scope: file

Source code excerpt:


static FAutoConsoleCommand CVarEnableSequenceRecorder(
	TEXT("SequenceRecorder"),
	TEXT("Enables the Sequence Recorder tab"),
	FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray<FString>& Args)
		{
			FSequenceRecorderModule& SequenceRecorder = FModuleManager::GetModuleChecked<FSequenceRecorderModule>("SequenceRecorder");
			SequenceRecorder.TabSpawnerEntry->SetMenuType(ETabSpawnerMenuType::Enabled);
		}),

#Loc: <Workspace>/Engine/Plugins/Media/MediaCompositing/Source/MediaCompositingEditor/Private/MediaCompositingEditor.cpp:30

Scope (from outer to inner):

file
class        class FMediaCompositingEditorModule : public IModuleInterface
function     virtual void StartupModule

Source code excerpt:

		PropertyTrackEditorBindingHandle = SequencerModule.RegisterPropertyTrackEditor<FMediaPlayerPropertyTrackEditor>();

		ISequenceRecorder& SequenceRecorder = FModuleManager::LoadModuleChecked<ISequenceRecorder>("SequenceRecorder");
		RecorderExtender = MakeShared<FMediaSequenceRecorderExtender>();
		SequenceRecorder.AddSequenceRecorderExtender(RecorderExtender);
	}
	
	virtual void ShutdownModule() override
	{
		ISequenceRecorder* SequenceRecorder = FModuleManager::Get().GetModulePtr<ISequenceRecorder>("SequenceRecorder");
		if (SequenceRecorder && RecorderExtender.IsValid())
		{
			SequenceRecorder->RemoveSequenceRecorderExtender(RecorderExtender);
		}
		RecorderExtender.Reset();

		FMediaCompositingEditorStyle::Destroy();

		ISequencerModule* SequencerModulePtr = FModuleManager::Get().GetModulePtr<ISequencerModule>("Sequencer");	

#Loc: <Workspace>/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueManager.cpp:456

Scope (from outer to inner):

file
function     AGameplayCueNotify_Actor* UGameplayCueManager::GetInstancedCueActor

Source code excerpt:

#if WITH_EDITOR
			// let things know that we 'spawned'
			ISequenceRecorder& SequenceRecorder = FModuleManager::LoadModuleChecked<ISequenceRecorder>("SequenceRecorder");
			SequenceRecorder.NotifyActorStartRecording(RecycledCue);
#endif

			return RecycledCue;
		}
	}

#Loc: <Workspace>/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueManager.cpp:551

Scope (from outer to inner):

file
function     void UGameplayCueManager::NotifyGameplayCueActorFinished

Source code excerpt:

#if WITH_EDITOR
			// let things know that we 'de-spawned'
			ISequenceRecorder& SequenceRecorder	= FModuleManager::LoadModuleChecked<ISequenceRecorder>("SequenceRecorder");
			SequenceRecorder.NotifyActorStopRecording(Actor);
#endif
			return;
		}

		UE_CLOG((GameplayCueActorRecycleDebug > 0), LogAbilitySystem, Error, TEXT("Could not Recycle CueActor %s, Destroying"), *GetNameSafe(Actor));
	}	

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/ActorGroupDetailsCustomization.cpp:110

Scope (from outer to inner):

file
function     TSharedRef<SWidget> FActorGroupDetailsCustomization::CreateRecordingGroupButton
lambda-function

Source code excerpt:

		.IsEnabled_Lambda([this, LocalCommandPtr]()
		{
			return SequenceRecorder.Pin()->GetCommandList()->CanExecuteAction(LocalCommandPtr.Pin().ToSharedRef());
		})
		.OnClicked(FOnClicked::CreateLambda([this, LocalCommandPtr]()
		{
			return SequenceRecorder.Pin()->GetCommandList()->ExecuteAction(LocalCommandPtr.Pin().ToSharedRef()) ? FReply::Handled() : FReply::Unhandled();
		}))
		[
			SNew(SHorizontalBox)
			+SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			.AutoWidth()

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/ActorGroupDetailsCustomization.cpp:140

Scope (from outer to inner):

file
function     TSharedRef<SWidget> FActorGroupDetailsCustomization::FillRecordingProfileOptions

Source code excerpt:

{
	const bool bShouldCloseWindowAfterMenuSelection = true;
	FMenuBuilder MenuBuilder(bShouldCloseWindowAfterMenuSelection, SequenceRecorder.Pin()->GetCommandList());

	TSharedPtr<SSequenceRecorder> LocalSequenceRecorder = SequenceRecorder.Pin();
	const FSequenceRecorderCommands& Commands = FSequenceRecorderCommands::Get();
	MenuBuilder.BeginSection("CurrentActorGroup", LOCTEXT("CurrentRecordingActorGroupMenu", "Current Actor Group"));
	{
		MenuBuilder.AddMenuEntry(Commands.DuplicateRecordingGroup);
	}
	MenuBuilder.EndSection();

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/ActorGroupDetailsCustomization.cpp:241

Scope (from outer to inner):

file
function     void FActorGroupDetailsCustomization::HandleRecordingGroupNameCommitted

Source code excerpt:


			// cbb: Force load to update sequence names, etc
			SequenceRecorder.Pin()->HandleLoadRecordingActorGroup(NewName);
		}
	}
}

#undef LOCTEXT_NAMESPACE

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/ActorGroupDetailsCustomization.h:22

Scope (from outer to inner):

file
class        class FActorGroupDetailsCustomization : public IDetailCustomization
function     FActorGroupDetailsCustomization

Source code excerpt:

	FActorGroupDetailsCustomization(TWeakPtr<SSequenceRecorder> InSequenceRecorder)
	{
		SequenceRecorder = InSequenceRecorder;
	}

	/** IDetailCustomization interface */
	virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;

private:

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/ActorGroupDetailsCustomization.h:33

Scope (from outer to inner):

file
class        class FActorGroupDetailsCustomization : public IDetailCustomization

Source code excerpt:

	void HandleRecordingGroupNameCommitted(const FText& InText, ETextCommit::Type InCommitType);
	TSharedPtr<SEditableTextBox> SequenceRecorderGroupNameTextBox;
	TWeakPtr<SSequenceRecorder> SequenceRecorder;
};

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/SSequenceRecorder.cpp:342

Scope (from outer to inner):

file
class        class SSequenceRecorderDeprecationMessage : public SCompoundWidget
function     FReply DismissWarningForever

Source code excerpt:

		if (GConfig)
		{
			GConfig->SetBool(TEXT("SequenceRecorder"), TEXT("HasDismissedDeprecationWarning"), true, GEditorIni);

			if (FEngineAnalytics::IsAvailable())
			{
				FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.SequenceRecorder.DeprecationWarning.Dimissed"));
			}
		}

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/SSequenceRecorder.cpp:358

Scope (from outer to inner):

file
class        class SSequenceRecorderDeprecationMessage : public SCompoundWidget
function     EVisibility GetWarningMessageVisibility

Source code excerpt:

		{
			bool bDismissed = false;
			GConfig->GetBool(TEXT("SequenceRecorder"), TEXT("HasDismissedDeprecationWarning"), bDismissed, GEditorIni);

			return bDismissed ? EVisibility::Collapsed : EVisibility::Visible;
		}

		return EVisibility::Collapsed;
	}

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/SequenceRecorder.cpp:94

Scope (from outer to inner):

file
function     FSequenceRecorder& FSequenceRecorder::Get

Source code excerpt:

FSequenceRecorder& FSequenceRecorder::Get()
{
	static FSequenceRecorder SequenceRecorder;
	return SequenceRecorder;
}


bool FSequenceRecorder::IsRecordingQueued(AActor* Actor) const
{
	for (UActorRecording* QueuedRecording : QueuedActorRecordings)

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/SequenceRecorderModule.cpp:771

Scope (from outer to inner):

file
class        class FSequenceRecorderModule : public ISequenceRecorder, private FSelfRegisteringExec

Source code excerpt:



	/** Add an extension to the SequenceRecorder */
	virtual void AddSequenceRecorderExtender(TSharedPtr<ISequenceRecorderExtender> SequenceRecorderExternder) override
	{
		FSequenceRecorder::Get().GetSequenceRecorderExtenders().Add(SequenceRecorderExternder);

		// Rebuild the UI
		TSharedPtr<SDockTab> SequenceRecorderTabPtr = SequenceRecorderTab.Pin();

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/SequenceRecorderModule.cpp:784

Scope (from outer to inner):

file
class        class FSequenceRecorderModule : public ISequenceRecorder, private FSelfRegisteringExec

Source code excerpt:

	}

	/** Remove an extension from the SequenceRecorder */
	virtual void RemoveSequenceRecorderExtender(TSharedPtr<ISequenceRecorderExtender> SequenceRecorderExternder) override
	{
		FSequenceRecorder::Get().GetSequenceRecorderExtenders().Remove(SequenceRecorderExternder);
		if (!IsEngineExitRequested())
		{
			// Rebuild the UI

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/SequenceRecorderModule.cpp:863

Scope (from outer to inner):

file
class        class FSequenceRecorderModule : public ISequenceRecorder, private FSelfRegisteringExec
function     static TSharedRef<SDockTab> SpawnSequenceRecorderTab

Source code excerpt:

		MajorTab->SetContent(SNew(SSequenceRecorder));

		FSequenceRecorderModule& SequenceRecorder = FModuleManager::GetModuleChecked<FSequenceRecorderModule>("SequenceRecorder");
		SequenceRecorder.SequenceRecorderTab = MajorTab;

		return MajorTab.ToSharedRef();
	}

	static void DrawDebug(UCanvas* InCanvas, APlayerController* InPlayerController)
	{

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Private/SequenceRecorderModule.cpp:903

Scope: file

Source code excerpt:

	ECVF_Default);

IMPLEMENT_MODULE( FSequenceRecorderModule, SequenceRecorder )

#undef LOCTEXT_NAMESPACE

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorder/Public/ISequenceRecorder.h:161

Scope (from outer to inner):

file
class        class ISequenceRecorder : public IModuleInterface

Source code excerpt:

	virtual FOnRecordingGroupAdded& OnRecordingGroupAdded() = 0;

	/** Add an extension to the SequenceRecorder */
	virtual void AddSequenceRecorderExtender(TSharedPtr<ISequenceRecorderExtender> SequenceRecorderExternder) = 0;

	/** Remove an extension from the SequenceRecorder */
	virtual void RemoveSequenceRecorderExtender(TSharedPtr<ISequenceRecorderExtender> SequenceRecorderExternder) = 0;

	/**
	* Play the current single node instance on the PreviewComponent from time [0, GetLength()], and record to NewAsset
	*
	* @param: PreviewComponent - this component should contains SingleNodeInstance with time-line based asset, currently support AnimSequence or AnimComposite

#Loc: <Workspace>/Engine/Source/Editor/SequenceRecorderSections/Private/MovieScene3DAttachSectionRecorder.cpp:56

Scope (from outer to inner):

file
function     void FMovieScene3DAttachSectionRecorder::Record

Source code excerpt:

		AActor* AttachedToActor = SequenceRecorderUtils::GetAttachment(ActorToRecord.Get(), SocketName, ComponentName);

		ISequenceRecorder& SequenceRecorder = FModuleManager::GetModuleChecked<ISequenceRecorder>("SequenceRecorder");
		FGuid Guid = SequenceRecorder.GetRecordingGuid(AttachedToActor);
		if(AttachedToActor && Guid.IsValid())
		{
			// create the track if we haven't already
			if(!AttachTrack.IsValid())
			{
				AttachTrack = MovieScene->AddTrack<UMovieScene3DAttachTrack>(ObjectGuid);

#Loc: <Workspace>/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp:4964

Scope (from outer to inner):

file
function     int32 FEngineLoop::Init

Source code excerpt:

	}

	FModuleManager::Get().LoadModule(TEXT("SequenceRecorder"));
	FModuleManager::Get().LoadModule(TEXT("SequenceRecorderSections"));
#endif

	GIsRunning = true;

	if (!GIsEditor)