Files
UnrealEngineUWP/Engine/Plugins/MovieScene/SequencerScripting/Source/SequencerScriptingEditor/Private/SequencerTools.cpp

979 lines
38 KiB
C++
Raw Normal View History

// Copyright Epic Games, Inc. All Rights Reserved.
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
#include "SequencerTools.h"
#include "Animation/AnimSequence.h"
#include "Engine/SkeletalMesh.h"
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
#include "AutomatedLevelSequenceCapture.h"
#include "Channels/MovieSceneBoolChannel.h"
#include "LevelSequenceActor.h"
#include "Channels/MovieSceneEvent.h"
#include "FbxExporter.h"
#include "Channels/MovieSceneFloatChannel.h"
#include "MovieSceneToolsUserSettings.h"
#include "Channels/MovieSceneIntegerChannel.h"
#include "MovieSceneToolHelpers.h"
#include "Engine/World.h"
#include "MovieSceneEventUtils.h"
#include "INodeAndChannelMappings.h"
#include "MovieSceneSequenceEditor.h"
#include "LevelSequence.h"
#include "Sections/MovieSceneEventSectionBase.h"
#include "CineCameraActor.h"
#include "Components/SkeletalMeshComponent.h"
#include "MovieScenePossessable.h"
#include "ScopedTransaction.h"
#include "Exporters/AnimSeqExportOption.h"
#include "K2Node_CustomEvent.h"
#include "BlueprintFunctionNodeSpawner.h"
#include "BlueprintActionMenuItem.h"
#include "EdGraphSchema_K2.h"
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
#include "LevelSequenceAnimSequenceLink.h"
#include "AnimSequenceLevelSequenceLink.h"
#include "Compilation/MovieSceneCompiledDataManager.h"
#include "MovieSceneSpawnable.h"
#include "SequencerScriptingRange.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(SequencerTools)
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
#define LOCTEXT_NAMESPACE "SequencerTools"
bool USequencerToolsFunctionLibrary::RenderMovie(UMovieSceneCapture* InCaptureSettings, FOnRenderMovieStopped OnFinishedCallback)
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
{
IMovieSceneCaptureDialogModule& MovieSceneCaptureModule = FModuleManager::Get().LoadModuleChecked<IMovieSceneCaptureDialogModule>("MovieSceneCaptureDialog");
// Because this comes from the Python/BP layer we need to soft-validate the state before we pass it onto functions that do a assert-based validation.
if (!InCaptureSettings)
{
FFrame::KismetExecutionMessage(TEXT("Cannot start Render Sequence to Movie with null capture settings."), ELogVerbosity::Error);
return false;
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
if (IsRenderingMovie())
{
FFrame::KismetExecutionMessage(TEXT("Capture already in progress."), ELogVerbosity::Error);
return false;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
// If they're capturing a level sequence we'll do some additional checking as there are more parameters on the Automated Level Sequence capture.
UAutomatedLevelSequenceCapture* LevelSequenceCapture = Cast<UAutomatedLevelSequenceCapture>(InCaptureSettings);
if (LevelSequenceCapture)
{
if (!LevelSequenceCapture->LevelSequenceAsset.IsValid())
{
// UE_LOG(LogTemp, Warning, TEXT("No Level Sequence Asset specified in UAutomatedLevelSequenceCapture."));
FFrame::KismetExecutionMessage(TEXT("No Level Sequence Asset specified in UAutomatedLevelSequenceCapture."), ELogVerbosity::Error);
return false;
}
if (!LevelSequenceCapture->bUseCustomStartFrame && !LevelSequenceCapture->bUseCustomEndFrame)
{
// If they don't want to use a custom start/end frame we override the default values to be the length of the sequence, as the default is [0,1)
ULevelSequence* LevelSequence = Cast<ULevelSequence>(LevelSequenceCapture->LevelSequenceAsset.TryLoad());
if (!LevelSequence)
{
const FString ErrorMessage = FString::Printf(TEXT("Specified Level Sequence Asset failed to load. Specified Asset Path: %s"), *LevelSequenceCapture->LevelSequenceAsset.GetAssetPathString());
FFrame::KismetExecutionMessage(*ErrorMessage, ELogVerbosity::Error);
return false;
}
FFrameRate DisplayRate = LevelSequence->GetMovieScene()->GetDisplayRate();
FFrameRate TickResolution = LevelSequence->GetMovieScene()->GetTickResolution();
LevelSequenceCapture->Settings.CustomFrameRate = DisplayRate;
LevelSequenceCapture->Settings.bUseCustomFrameRate = true;
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
LevelSequenceCapture->Settings.bUseRelativeFrameNumbers = false;
TRange<FFrameNumber> Range = LevelSequence->GetMovieScene()->GetPlaybackRange();
FFrameNumber StartFrame = UE::MovieScene::DiscreteInclusiveLower(Range);
FFrameNumber EndFrame = UE::MovieScene::DiscreteExclusiveUpper(Range);
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
FFrameNumber RoundedStartFrame = FFrameRate::TransformTime(StartFrame, TickResolution, DisplayRate).CeilToFrame();
FFrameNumber RoundedEndFrame = FFrameRate::TransformTime(EndFrame, TickResolution, DisplayRate).CeilToFrame();
LevelSequenceCapture->CustomStartFrame = RoundedStartFrame;
LevelSequenceCapture->CustomEndFrame = RoundedEndFrame;
}
}
auto LocalCaptureStoppedCallback = [OnFinishedCallback](bool bSuccess)
{
OnFinishedCallback.ExecuteIfBound(bSuccess);
};
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
MovieSceneCaptureModule.StartCapture(InCaptureSettings);
MovieSceneCaptureModule.GetCurrentCapture()->CaptureStoppedDelegate.AddLambda(LocalCaptureStoppedCallback);
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4071915) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4060527 by Anousack.Kitisa Added support for importing FBX user properties as metadata on StaticMesh when importing FBX. Added support for exporting StaticMesh metadata as FBX user properties when exporting StaticMesh to FBX. #jira UESP-567 Change 4060835 by Jamie.Dale Added assign method to Python exposed structs This lets you assign the value of one struct instance onto another instance (rather than copy the pointer in Python). It also accepts anything that casts to the destination struct. Change 4060838 by Jamie.Dale Include unary operator function tooltips in doc string Change 4060843 by Jamie.Dale Fixed PythonizeValue including deprecated properties in the init function for a struct Change 4060908 by Jamie.Dale Fixed some name conflicts in generated Python glue Change 4061065 by Jamie.Dale Stubbed struct return values are now default constructed Change 4061205 by David.Hibbitts Added blueprint functions to create a message bus source, for use in projects where the Editor UI is not available or is impractical. Added a blueprint function to get available subject names for the LiveLink Client Added a RemoveSource method to ILiveLinkClient Added a GetSubjectNames method to ILiveLinkClient Fixed a crash when RequestShutdown was called on a MessageBusSource after the HeartbeatManager had already been shut down. Change 4061421 by Patrick.Boutot [AJA] Warn the user if he requested the key and the backbuffer is not setup properly. #jira UE-58614 Change 4061620 by Jamie.Dale Made the Sphinx config a template so we can inject the current engine version into it Change 4062578 by Jamie.Dale Optimized Python stub and doc gen file writes - Files are now only written when they've changed. - We now only remove files that are stale. - No requests to generate stub and doc files are queued before the first Tick. Change 4062634 by Jamie.Dale No longer export FDateTime defaults to struct __init__ as they can be non-deterministic Change 4064275 by Jamie.Dale Added callbacks for when Python is initialized and shutdown so that external modules can hook-in appropriately Change 4064613 by James.McNatton Change to initialization for FVirtualCameraWaypoint and FVirtualCameraSettingsPreset to remove non-deterministic constructors and a few resulting cleanup items Change 4064878 by Patrick.Boutot Add timecode provider plugin to capture from the Audio jack. Change 4064910 by Patrick.Boutot [AJA] Add AjaTimecodeProvider that provider the timecode from a SDI input source. Change 4067451 by Jamie.Dale Added command line options to enable all plugins, optionally excluding certain plugins Change 4067489 by Simon.Tourangeau Support for DX12 quad buffer stereo rendering Change 4068640 by Patrick.Boutot Add a state to CustomTimeStep. Show the state of the CustomTimeStep in "stat fps". Change 4069147 by Patrick.Boutot Move Mediasmith console to Engine. Renamed to TimecodeSynchronizer. Change 4071727 by Matt.Hoffman Initial pass at exposing Sequencer's Render to Movie functionality to Python. All settings that can be adjusted via the UI can be set from Python and renders can be invoked for both in-editor capture as well as new process capture. A basic API is provided which enables querying if a render in progress and canceling an in progress one. #jira UESP-541 [CL 4071957 by JeanMichel Dignard in Main branch]
2018-05-14 17:38:22 -04:00
return true;
}
void USequencerToolsFunctionLibrary::CancelMovieRender()
{
IMovieSceneCaptureDialogModule& MovieSceneCaptureModule = FModuleManager::Get().LoadModuleChecked<IMovieSceneCaptureDialogModule>("MovieSceneCaptureDialog");
TSharedPtr<FMovieSceneCaptureBase> CurrentCapture = MovieSceneCaptureModule.GetCurrentCapture();
if (CurrentCapture.IsValid())
{
// We just invoke the capture's Cancel function. This will cause a shut-down of the capture (the same as the UI)
// which will invoke all of the necessary callbacks as well. We don't null out CurrentCapture because that is done
// as the result of its shutdown callbacks.
CurrentCapture->Cancel();
}
}
TArray<FSequencerBoundObjects> USequencerToolsFunctionLibrary::GetBoundObjects(UWorld* InWorld, ULevelSequence* InSequence, const TArray<FMovieSceneBindingProxy>& InBindings, const FSequencerScriptingRange& InRange)
{
ALevelSequenceActor* OutActor;
FMovieSceneSequencePlaybackSettings Settings;
FLevelSequenceCameraSettings CameraSettings;
ULevelSequencePlayer* Player = ULevelSequencePlayer::CreateLevelSequencePlayer(InWorld, InSequence, Settings, OutActor);
// Evaluation needs to occur in order to obtain spawnables
FFrameRate Resolution = InSequence->GetMovieScene()->GetTickResolution();
TRange<FFrameNumber> SpecifiedRange = InRange.ToNative(Resolution);
Player->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(SpecifiedRange.GetLowerBoundValue().Value, EUpdatePositionMethod::Play));
FMovieSceneSequenceID SequenceId = Player->State.FindSequenceId(InSequence);
TArray<FSequencerBoundObjects> BoundObjects;
for (FMovieSceneBindingProxy Binding : InBindings)
{
FMovieSceneObjectBindingID ObjectBinding = UE::MovieScene::FFixedObjectBindingID(Binding.BindingID, SequenceId);
BoundObjects.Add(FSequencerBoundObjects(Binding, Player->GetBoundObjects(ObjectBinding)));
}
Player->Stop();
InWorld->DestroyActor(OutActor);
return BoundObjects;
}
TArray<FSequencerBoundObjects> USequencerToolsFunctionLibrary::GetObjectBindings(UWorld* InWorld, ULevelSequence* InSequence, const TArray<UObject*>& InObjects, const FSequencerScriptingRange& InRange)
{
ALevelSequenceActor* OutActor;
FMovieSceneSequencePlaybackSettings Settings;
FLevelSequenceCameraSettings CameraSettings;
ULevelSequencePlayer* Player = ULevelSequencePlayer::CreateLevelSequencePlayer(InWorld, InSequence, Settings, OutActor);
FFrameRate Resolution = InSequence->GetMovieScene()->GetTickResolution();
TRange<FFrameNumber> SpecifiedRange = InRange.ToNative(Resolution);
Player->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(SpecifiedRange.GetLowerBoundValue().Value, EUpdatePositionMethod::Play));
TArray<FSequencerBoundObjects> BoundObjects;
for (UObject* Object : InObjects)
{
TArray<FMovieSceneObjectBindingID> ObjectBindings = Player->GetObjectBindings(Object);
for (FMovieSceneObjectBindingID ObjectBinding : ObjectBindings)
{
FMovieSceneSequenceID SequenceID = ObjectBinding.ResolveSequenceID(MovieSceneSequenceID::Root, *Player);
FMovieSceneBindingProxy Binding(ObjectBinding.GetGuid(), Player->State.FindSequence(SequenceID));
BoundObjects.Add(FSequencerBoundObjects(Binding, TArray<UObject*>({ Object })));
}
}
Player->Stop();
InWorld->DestroyActor(OutActor);
return BoundObjects;
}
void GatherDescendantBindings(const FMovieSceneBindingProxy& Binding, UMovieSceneSequence* Sequence, TArray<FMovieSceneBindingProxy>& AllBindings)
{
UMovieScene* MovieScene = Sequence->GetMovieScene();
for (int32 Index = 0; Index < MovieScene->GetPossessableCount(); ++Index)
{
FMovieScenePossessable& Possessable = MovieScene->GetPossessable(Index);
if (Possessable.GetParent() == Binding.BindingID)
{
FMovieSceneBindingProxy ChildBinding(Possessable.GetGuid(), Sequence);
AllBindings.Add(ChildBinding);
GatherDescendantBindings(ChildBinding, Sequence, AllBindings);
}
}
}
bool ExportFBXInternal(const FSequencerExportFBXParams& InParams, UMovieSceneSequencePlayer* Player)
{
UWorld* World = InParams.World;
UMovieSceneSequence* Sequence = InParams.Sequence;
UMovieSceneSequence* RootSequence = InParams.RootSequence;
TArray<FMovieSceneBindingProxy> BindingProxies = InParams.Bindings;
Sequencer: Remove Master from Sequencer - Remove all instances of Master from the UI - ie. Replace Create Master Sequence with Create Sequence with Shots - Internally, remove Master - Master Tracks in the MovieScene can just be Tracks Deprecations (Properties): - UMovieScene:MasterTracks deprecated for Tracks - UMovieSceneFolder:ChildMasterTracks deprecated for ChildTracks - FLevelSequencePlayerSnapshot: MasterName, MasterTime for RootName, RootTime - UMoviePipelineSetting_BlueprintBase: bIsValidOnMaster for bIsValidOnPrimary Deprecations (Functions): - UMovieScene: GetMasterTracks, FindMasterTracksByType, FindMasterTracksByExactType, AddMasterTrack, RemoveMasterTrack deprecated for GetTracks, FindTracksByType, FindTracksByExactType, AddTrack, RemoveTrack - UMovieSceneFolder: GetChildMasterTracks, AddChildMasterTrack, RemoveChildMasterTrack deprecated for GetChildTracks, AddChildTracks, RemoveChildTrack - FMovieSceneTrackEditor: FFindOrCreateMasterTrackResult, FindOrCreateMasterTrack deprecated for FindOrCreateRootTrackResult, FindOrCreateRootTrack - ULevelSequenceDirector: GetMasterSequenceTime deprecated for ULevelSequenceDirector::GetRootSequenceTime - UDaySequenceDirector: GetMasterSequenceTime deprecated for UDaySequenceDirector::GetRootSequenceTime - UMoviePipelineSetting: IsValidOnMaster for IsValidOnPrimary - UMoviePipelineBlueprintLibrary: GetMasterTimecode, GetMasterFrameNumber for GetRootTimecode, GetRootFrameNumber - UMoviePipeline: GetPipelineMasterConfig for GetPipelinePrimaryConfig - UMovieSceneAudioTrack: IsAMasterTrack Classes Renamed: - FAnimTypePreAnimatedStateMasterStorage for FAnimTypePreAnimatedStateRootStorage - UMovieSceneMasterInstantiatorSystem for UMovieSceneRootInstantiatorSystem - ULevelSequenceMasterSequenceSettings to ULevelSequenceSequenceWithShotsSetting Note, the following instances of master still occur and a "KnownCase" has been added for them in CheckAcceptableWords.cs: - Deprecated properties (MasterTracks -> Tracks) and functions (ie. GetMasterTracks -> GetTracks) - masterclip in FCPXML since it's an industry standard term - masteraudiosubmix in AudioCaptureProtocol - mastersubmix in MoviePipelineAudioRendering - masteertimecode, masterframenumber, masterconfig, validonmaster in MovieRenderPipeline - mastersequencetime, mastertime, mastername in LevelSequence #jira UE-158660 #preflight 634645e48a0a7b2adc5722e7 #rb matt.hoffman, andrew.rodham [CL 22739302 by Max Chen in ue5-main branch]
2022-10-24 18:22:10 -04:00
TArray<UMovieSceneTrack*> Tracks = InParams.Tracks;
UFbxExportOption* OverrideOptions = InParams.OverrideOptions;
FString FBXFileName = InParams.FBXFileName;
if (!RootSequence)
{
RootSequence = Sequence;
}
if (!RootSequence)
{
return false;
}
UnFbx::FFbxExporter* Exporter = UnFbx::FFbxExporter::GetInstance();
//Show the fbx export dialog options
Exporter->SetExportOptionsOverride(OverrideOptions);
UMovieScene* MovieScene = Sequence->GetMovieScene();
TArray<FMovieSceneBindingProxy> AllBindings;
for (const FMovieSceneBindingProxy& Binding : BindingProxies)
{
AllBindings.Add(Binding);
GatherDescendantBindings(Binding, Sequence, AllBindings);
}
TArray<FGuid> Bindings;
for (const FMovieSceneBindingProxy& Proxy : AllBindings)
{
if (Proxy.Sequence == Sequence)
{
Bindings.Add(Proxy.BindingID);
}
}
Player->State.AssignSequence(MovieSceneSequenceID::Root, *RootSequence, *Player);
FMovieSceneSequenceIDRef Template = Player->State.FindSequenceId(Sequence);
UnFbx::FFbxExporter::FLevelSequenceNodeNameAdapter NodeNameAdapter(MovieScene, Player, Template);
FMovieSceneSequenceHierarchy Hierarchy = FMovieSceneSequenceHierarchy();
UMovieSceneCompiledDataManager::CompileHierarchy(RootSequence, &Hierarchy, EMovieSceneServerClientMask::All);
const FMovieSceneSubSequenceData* SubSequenceData = Hierarchy.FindSubData(Template);
FMovieSceneSequenceTransform RootToLocalTransform;
FFrameTime StartTime = FFrameRate::TransformTime(UE::MovieScene::DiscreteInclusiveLower(MovieScene->GetPlaybackRange()).Value, MovieScene->GetTickResolution(), MovieScene->GetDisplayRate());
if (SubSequenceData)
{
RootToLocalTransform = SubSequenceData->RootToSequenceTransform;
Sequencer: Proper support for zero-timescale sub-sequence sections. The intention behind setting zero-timescale on a section is to hold at a single frame (the StartFrameOffset) while playing this sub section in its parent sequence. Previously, this 'kind of' worked, but in practice there were divide by zeros happening and this was causing bugs under certain circumstances, as well as some odd behavior. To support this change required a bit of a refactor of FMovieSceneSequenceTransform and its 'Warping'. Warping previously just indicated looping, but now it can also indicate timescales of zero. In cases of zero timescale transforms, we keep transforms split into FMovieSceneNestedSequenceTransforms rather than combining them. Some logic that directly accessed the internal FMovieSceneTimeTransform 'LinearTransform' also had to be refactored to properly use the FMovieSceneSequenceTransform's accessor functions for doing things like inverse. When dealing with zero timescale in FMovieSceneTimeTransforms, there is the ability for loss of information when multiplying and inverting, and so to compensate for that we need every hierarchical step of the transforms stored. This also necessitated some changes in logic for TMovieSceneTimeArray and how it stores its TransformStack, as it was depending on the inverse of an inverse being a lossless operation when acting on a FMovieSceneTimeTransform. See https://docs.google.com/document/d/1ftdIyi9J8At6fw31K5awKCUK5-75uz7F-MWAq5b1vWc/edit#heading=h.fclfl8j8p52c. #jira UE-146012 [REVIEW] [at]ludovic.chabant [at]max.chen [CL 26734557 by david bromberg in ue5-main branch]
2023-08-01 06:45:24 -04:00
StartTime = UE::MovieScene::DiscreteInclusiveLower(SubSequenceData->PlayRange.Value) * RootToLocalTransform.InverseNoLooping();
}
bool bDidExport = false;
{
Sequencer- Refactor Bindings to support inherited Custom Bindings. With this checkin, the binding system inside Level Sequences has been refactored to allow C++ custom binding classes inheriting from a new class, UMovieSceneCustomBinding. Custom bindings are held as instanced UObjects inside FMovieSceneBindingReference, alongside the Universal Object Locator. In the case where a custom binding has been specified, the UOL will be ignored. The intention with this change is to allow developers to create their own arbitrary methods of binding any UObject to a track inside Sequencer. Examples of this include: * Runtime dynamic bindings to spawned NPC or player characters (e.g. in UEFN) with a different spawned preview character * Blueprint-specified dynamic bindings * Spawnable bindings based on something other than a AActor template * Scene Graph/Prefabs Alongside the base UMovieSceneCustomBinding class, a new hierarchy of spawnable custom binding classes has been created as the basis for allowing spawnable bindings that don't require object templates, and may instead require other asset references, for example UEFN NPC character spawnables requiring an NPC Character Definition asset. This hierarchy is currently. UMovieSceneCustomBinding <- UMovieSceneSpawnableBindingBase <- UMovieSceneSpawnableActorBindingBase <- UMovieSceneSpawnableActorBinding. This hierarchy allows for spawnables of non-actor types, spawnables of actor types not based on templates, and finally UMovieSceneSpawnableActorBinding, which is a re-implementation of FMovieSceneSpawnable inside the custom binding system. Going forward, we will be moving to deprecate FMovieSceneSpawnable in UE Sequencer in favor of the custom spawnable binding types. Sequences with FMovieSceneSpawnables will continue to function as normal, but new spawnables in new sequences will use UMovieSceneSpawnableActorBinding under the hood. These will technically have FMovieScenePossessable structs created for them for now rather than FMovieSceneSpawnable structs. This should be mostly invisible to the user. In addition, I've added a separate hierarchy of custom bindings called 'Replaceable' bindings. A 'Replaceable' is a binding type that will expect in runtime to always be overridden by a different object that may not be available in editor. UMovieSceneReplaceableBinding will hold in EDITORONLY_DATA a UMovieSceneSpawnableBindingBase to provide a preview while within Sequencer. Included in this is a UMovieSceneReplaceableActorBinding, which uses the UMovieSceneSpawnableActorBinding internally to spawn its preview, and has no implementation to find the actor during runtime- it relies on the user overriding the actor binding using the existing BindingOverrides method on LevelSequenceActor. Next Steps: * UEFN custom bindings will be built upon this system, to allow UEFN users multiple ways to override bindings. * UEFN custom spawnable bindings will be built upon this system, to allow UEFN users a way to spawn actors and objects within Sequencer with their lifetime managed by Sequencer * With this change, we have a cleaner way of incorporating the 'dynamic binding' work that uses the Director Blueprint to create a spawnable or possessable. This should be incorporated into the UCustomBinding hierarchy. * Once Verse supports it, we should add Verse custom binding logic * We need to add a Universal Object Locator type that can reference any other binding in the sequence hierarchy. This will allow us to adapt the existing 'Spawnable Parent' possessable binding logic to reference any other type of binding, not just spawnable ones. * Eventually we will fully deprecate FMovieSceneSpawnable Further notes: * A previous imagined version of this system used the cache as a way to allow locators to spawn actors and register them with Sequencer. This change removes this code. * Custom Spawnable Bindings use the Binding Lifetime Track to determine their spawn lifetime rather than the old spawn track. This unifies the concept of the lifetime of an object binding within sequencer for both spawnables and possessables. * As FMovieScenePossessable and FMovieSceneBindingReferences allows multiple bindings per guid, this change now allows multiple spawnables to be spawned and controlled by a single binding track. However, some of the editor tooling code doesn't currently handle this properly and at times assumes a single binding. This should be resolved one way or the other. * The UX for this allows UCustomBindings to handle creating bindings from any dragged in object using a priority system- Sequencer will ask all classes in priority order if they support binding creation from that object. * The UX supports unique overlay icons and tooltips for different types of bindings * The UX allows each binding type to decide whether it can convert a current binding into its own type and then do so * Currently there is some manual instanced detail customization for UMovieSceneCustomSpawnableActorBinding. We use instanced customization so that the UX has the sequencer context. This should both be improved (to allow ways to choose a class/template via this UI), as well as extended so that clients outside of the Movie Scene plugin can register instanced detail customizations for their own binding types. * Where possible, Sequencer APIs around spawnables have been refactored to take guids rather than FMovieSceneSpawnable references. In particular, custom spawnables do still use the spawn register, but do not use actor spawners- instead the UMovieSceneCustomBinding class is given the responsiblity of spawning/destroying the object/actor. This created an awkward API for USD export, which had overridden the spawn register to unhide/hide actors rather than spawning/destroying them. This could use some more work. MetaHumanPerformanceExportUtils will also need to be refactored at some point to use the custom spawnable binding system. * FSequencerUtilities::CreateBinding and CreateGenericBinding has been refactored to accept binding parameters and now supports creating custom bindings including spawnables, as well as replacing existing bindings and adding additional bindings to an existing guid. [REVIEW] [at]ue-sequencer #jira UE-199299, FORT-582815, UE-209594 #rb Andrew.Rodham, daniel.coelho, Max.Chen [CL 32218187 by david bromberg in ue5-main branch]
2024-03-13 12:48:46 -04:00
FSpawnableRestoreState SpawnableRestoreState(MovieScene, Player->GetSharedPlaybackState().ToSharedPtr());
if (SpawnableRestoreState.bWasChanged)
{
// Evaluate at the beginning of the subscene time to ensure that spawnables are created before export
Player->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(StartTime, EUpdatePositionMethod::Play));
}
FAnimExportSequenceParameters AESP;
AESP.Player = Player;
AESP.RootToLocalTransform = RootToLocalTransform;
AESP.MovieSceneSequence = Sequence;
AESP.RootMovieSceneSequence = RootSequence;
bDidExport = MovieSceneToolHelpers::ExportFBX(World, AESP, Bindings, Tracks, NodeNameAdapter, Template, FBXFileName);
}
Player->Stop();
Exporter->SetExportOptionsOverride(nullptr);
return bDidExport;
}
bool USequencerToolsFunctionLibrary::ExportLevelSequenceFBX(const FSequencerExportFBXParams& InParams)
{
ALevelSequenceActor* OutActor;
FMovieSceneSequencePlaybackSettings Settings;
FLevelSequenceCameraSettings CameraSettings;
ULevelSequence* RootSequence = InParams.RootSequence;
if (!RootSequence)
{
RootSequence = InParams.Sequence;
}
if (!RootSequence)
{
FFrame::KismetExecutionMessage(TEXT("Cannot export level sequence. Sequence is invalid."), ELogVerbosity::Error);
return false;
}
ULevelSequencePlayer* Player = ULevelSequencePlayer::CreateLevelSequencePlayer(InParams.World, RootSequence, Settings, OutActor);
bool bSuccess = ExportFBXInternal(InParams, Player);
InParams.World->DestroyActor(OutActor);
return bSuccess;
}
static USkeletalMeshComponent* GetSkelMeshComponent(IMovieScenePlayer* Player, const FMovieSceneBindingProxy& Binding)
{
FMovieSceneSequenceIDRef Template = MovieSceneSequenceID::Root;
for (TWeakObjectPtr<UObject> RuntimeObject : Player->FindBoundObjects(Binding.BindingID, Template))
{
if (AActor* Actor = Cast<AActor>(RuntimeObject.Get()))
{
for (UActorComponent* Component : Actor->GetComponents())
{
if (USkeletalMeshComponent* SkeletalMeshComp = Cast<USkeletalMeshComponent>(Component))
{
return SkeletalMeshComp;
}
}
}
else if (USkeletalMeshComponent* SkeletalMeshComponent = Cast<USkeletalMeshComponent>(RuntimeObject.Get()))
{
if (SkeletalMeshComponent->GetSkeletalMeshAsset())
{
return SkeletalMeshComponent;
}
}
}
return nullptr;
}
bool USequencerToolsFunctionLibrary::ExportAnimSequence(UWorld* World, ULevelSequence* Sequence, UAnimSequence* AnimSequence, UAnimSeqExportOption* ExportOptions,const FMovieSceneBindingProxy& Binding, bool bCreateLink)
{
UMovieScene* MovieScene = Sequence->GetMovieScene();
if (Binding.Sequence != Sequence || !AnimSequence)
{
return false;
}
ALevelSequenceActor* OutActor;
FMovieSceneSequencePlaybackSettings Settings;
FLevelSequenceCameraSettings CameraSettings;
FMovieSceneSequenceIDRef Template = MovieSceneSequenceID::Root;
FMovieSceneSequenceTransform RootToLocalTransform;
ULevelSequencePlayer* Player = ULevelSequencePlayer::CreateLevelSequencePlayer(World, Sequence, Settings, OutActor);
bool bResult = false;
{
Sequencer- Refactor Bindings to support inherited Custom Bindings. With this checkin, the binding system inside Level Sequences has been refactored to allow C++ custom binding classes inheriting from a new class, UMovieSceneCustomBinding. Custom bindings are held as instanced UObjects inside FMovieSceneBindingReference, alongside the Universal Object Locator. In the case where a custom binding has been specified, the UOL will be ignored. The intention with this change is to allow developers to create their own arbitrary methods of binding any UObject to a track inside Sequencer. Examples of this include: * Runtime dynamic bindings to spawned NPC or player characters (e.g. in UEFN) with a different spawned preview character * Blueprint-specified dynamic bindings * Spawnable bindings based on something other than a AActor template * Scene Graph/Prefabs Alongside the base UMovieSceneCustomBinding class, a new hierarchy of spawnable custom binding classes has been created as the basis for allowing spawnable bindings that don't require object templates, and may instead require other asset references, for example UEFN NPC character spawnables requiring an NPC Character Definition asset. This hierarchy is currently. UMovieSceneCustomBinding <- UMovieSceneSpawnableBindingBase <- UMovieSceneSpawnableActorBindingBase <- UMovieSceneSpawnableActorBinding. This hierarchy allows for spawnables of non-actor types, spawnables of actor types not based on templates, and finally UMovieSceneSpawnableActorBinding, which is a re-implementation of FMovieSceneSpawnable inside the custom binding system. Going forward, we will be moving to deprecate FMovieSceneSpawnable in UE Sequencer in favor of the custom spawnable binding types. Sequences with FMovieSceneSpawnables will continue to function as normal, but new spawnables in new sequences will use UMovieSceneSpawnableActorBinding under the hood. These will technically have FMovieScenePossessable structs created for them for now rather than FMovieSceneSpawnable structs. This should be mostly invisible to the user. In addition, I've added a separate hierarchy of custom bindings called 'Replaceable' bindings. A 'Replaceable' is a binding type that will expect in runtime to always be overridden by a different object that may not be available in editor. UMovieSceneReplaceableBinding will hold in EDITORONLY_DATA a UMovieSceneSpawnableBindingBase to provide a preview while within Sequencer. Included in this is a UMovieSceneReplaceableActorBinding, which uses the UMovieSceneSpawnableActorBinding internally to spawn its preview, and has no implementation to find the actor during runtime- it relies on the user overriding the actor binding using the existing BindingOverrides method on LevelSequenceActor. Next Steps: * UEFN custom bindings will be built upon this system, to allow UEFN users multiple ways to override bindings. * UEFN custom spawnable bindings will be built upon this system, to allow UEFN users a way to spawn actors and objects within Sequencer with their lifetime managed by Sequencer * With this change, we have a cleaner way of incorporating the 'dynamic binding' work that uses the Director Blueprint to create a spawnable or possessable. This should be incorporated into the UCustomBinding hierarchy. * Once Verse supports it, we should add Verse custom binding logic * We need to add a Universal Object Locator type that can reference any other binding in the sequence hierarchy. This will allow us to adapt the existing 'Spawnable Parent' possessable binding logic to reference any other type of binding, not just spawnable ones. * Eventually we will fully deprecate FMovieSceneSpawnable Further notes: * A previous imagined version of this system used the cache as a way to allow locators to spawn actors and register them with Sequencer. This change removes this code. * Custom Spawnable Bindings use the Binding Lifetime Track to determine their spawn lifetime rather than the old spawn track. This unifies the concept of the lifetime of an object binding within sequencer for both spawnables and possessables. * As FMovieScenePossessable and FMovieSceneBindingReferences allows multiple bindings per guid, this change now allows multiple spawnables to be spawned and controlled by a single binding track. However, some of the editor tooling code doesn't currently handle this properly and at times assumes a single binding. This should be resolved one way or the other. * The UX for this allows UCustomBindings to handle creating bindings from any dragged in object using a priority system- Sequencer will ask all classes in priority order if they support binding creation from that object. * The UX supports unique overlay icons and tooltips for different types of bindings * The UX allows each binding type to decide whether it can convert a current binding into its own type and then do so * Currently there is some manual instanced detail customization for UMovieSceneCustomSpawnableActorBinding. We use instanced customization so that the UX has the sequencer context. This should both be improved (to allow ways to choose a class/template via this UI), as well as extended so that clients outside of the Movie Scene plugin can register instanced detail customizations for their own binding types. * Where possible, Sequencer APIs around spawnables have been refactored to take guids rather than FMovieSceneSpawnable references. In particular, custom spawnables do still use the spawn register, but do not use actor spawners- instead the UMovieSceneCustomBinding class is given the responsiblity of spawning/destroying the object/actor. This created an awkward API for USD export, which had overridden the spawn register to unhide/hide actors rather than spawning/destroying them. This could use some more work. MetaHumanPerformanceExportUtils will also need to be refactored at some point to use the custom spawnable binding system. * FSequencerUtilities::CreateBinding and CreateGenericBinding has been refactored to accept binding parameters and now supports creating custom bindings including spawnables, as well as replacing existing bindings and adding additional bindings to an existing guid. [REVIEW] [at]ue-sequencer #jira UE-199299, FORT-582815, UE-209594 #rb Andrew.Rodham, daniel.coelho, Max.Chen [CL 32218187 by david bromberg in ue5-main branch]
2024-03-13 12:48:46 -04:00
FSpawnableRestoreState SpawnableRestoreState(MovieScene, Player->GetSharedPlaybackState().ToSharedPtr());
if (SpawnableRestoreState.bWasChanged)
{
// Evaluate at the beginning of the subscene time to ensure that spawnables are created before export
FFrameTime StartTime = FFrameRate::TransformTime(UE::MovieScene::DiscreteInclusiveLower(MovieScene->GetPlaybackRange()).Value, MovieScene->GetTickResolution(), MovieScene->GetDisplayRate());
Player->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(StartTime, EUpdatePositionMethod::Play));
// Cannot transact changes due to in-flight spawnable transaction
ExportOptions->bTransactRecording = false;
}
USkeletalMeshComponent* SkeletalMeshComp = GetSkelMeshComponent(Player, Binding);
if (SkeletalMeshComp && SkeletalMeshComp->GetSkeletalMeshAsset() && SkeletalMeshComp->GetSkeletalMeshAsset()->GetSkeleton())
{
AnimSequence->SetSkeleton(SkeletalMeshComp->GetSkeletalMeshAsset()->GetSkeleton());
FAnimExportSequenceParameters AESQ;
AESQ.Player = Player;
AESQ.RootToLocalTransform = RootToLocalTransform;
AESQ.MovieSceneSequence = Sequence;
AESQ.RootMovieSceneSequence = Sequence;
bResult = MovieSceneToolHelpers::ExportToAnimSequence(AnimSequence, ExportOptions, AESQ, SkeletalMeshComp);
}
}
Player->Stop();
World->DestroyActor(OutActor);
//create the link to the anim sequence
if (bResult && bCreateLink)
{
return LinkAnimSequence(Sequence, AnimSequence, ExportOptions, Binding);
}
return bResult;
}
void USequencerToolsFunctionLibrary::ClearLinkedAnimSequences(ULevelSequence* LevelSequence)
{
if (LevelSequence)
{
if (IInterface_AssetUserData* LevelSequenceUserDataInterface = Cast< IInterface_AssetUserData >(LevelSequence))
{
ULevelSequenceAnimSequenceLink* LevelAnimLink = LevelSequenceUserDataInterface->GetAssetUserData< ULevelSequenceAnimSequenceLink >();
if (LevelAnimLink)
{
for (int32 Index = 0; Index < LevelAnimLink->AnimSequenceLinks.Num(); ++Index)
{
FLevelSequenceAnimSequenceLinkItem& LevelAnimLinkItem = LevelAnimLink->AnimSequenceLinks[Index];
if (UAnimSequence* AnimSequence = LevelAnimLinkItem.ResolveAnimSequence())
{
if (IInterface_AssetUserData* AnimAssetUserData = Cast< IInterface_AssetUserData >(AnimSequence))
{
UAnimSequenceLevelSequenceLink* AnimLevelLink = AnimAssetUserData->GetAssetUserData< UAnimSequenceLevelSequenceLink >();
if (AnimLevelLink)
{
ULevelSequence* AnimLevelSequence = AnimLevelLink->ResolveLevelSequence();
if (AnimLevelSequence && AnimLevelSequence == LevelSequence)
{
AnimAssetUserData->RemoveUserDataOfClass(UAnimSequenceLevelSequenceLink::StaticClass());
}
}
}
}
}
LevelSequenceUserDataInterface->RemoveUserDataOfClass(ULevelSequenceAnimSequenceLink::StaticClass());
}
}
}
}
bool USequencerToolsFunctionLibrary::LinkAnimSequence(ULevelSequence* Sequence, UAnimSequence* AnimSequence, const UAnimSeqExportOption* ExportOptions,const FMovieSceneBindingProxy& Binding)
{
if (!Sequence || !AnimSequence || !ExportOptions || Binding.Sequence != Sequence)
{
return false;
}
if (Sequence && Sequence->GetClass()->ImplementsInterface(UInterface_AssetUserData::StaticClass())
&& AnimSequence->GetClass()->ImplementsInterface(UInterface_AssetUserData::StaticClass()))
{
Sequence->Modify();
AnimSequence->Modify();
if (IInterface_AssetUserData* AnimAssetUserData = Cast< IInterface_AssetUserData >(AnimSequence))
{
UAnimSequenceLevelSequenceLink* AnimLevelLink = AnimAssetUserData->GetAssetUserData< UAnimSequenceLevelSequenceLink >();
if (!AnimLevelLink)
{
AnimLevelLink = NewObject<UAnimSequenceLevelSequenceLink>(AnimSequence, NAME_None, RF_Public | RF_Transactional);
AnimAssetUserData->AddAssetUserData(AnimLevelLink);
}
AnimLevelLink->SetLevelSequence(Sequence);
AnimLevelLink->SkelTrackGuid = Binding.BindingID;
}
if (IInterface_AssetUserData* AssetUserDataInterface = Cast< IInterface_AssetUserData >(Sequence))
{
bool bAddItem = true;
ULevelSequenceAnimSequenceLink* LevelAnimLink = AssetUserDataInterface->GetAssetUserData< ULevelSequenceAnimSequenceLink >();
if (LevelAnimLink)
{
for (FLevelSequenceAnimSequenceLinkItem& LevelAnimLinkItem : LevelAnimLink->AnimSequenceLinks)
{
if (LevelAnimLinkItem.IsEqual(Binding.BindingID, ExportOptions->bUseCustomTimeRange,
ExportOptions->CustomStartFrame, ExportOptions->CustomEndFrame, ExportOptions->CustomDisplayRate))
{
bAddItem = false;
UAnimSequence* OtherAnimSequence = LevelAnimLinkItem.ResolveAnimSequence();
if (OtherAnimSequence != AnimSequence)
{
if (IInterface_AssetUserData* OtherAnimAssetUserData = Cast< IInterface_AssetUserData >(OtherAnimSequence))
{
UAnimSequenceLevelSequenceLink* OtherAnimLevelLink = OtherAnimAssetUserData->GetAssetUserData< UAnimSequenceLevelSequenceLink >();
if (OtherAnimLevelLink)
{
OtherAnimSequence->Modify();
OtherAnimAssetUserData->RemoveUserDataOfClass(UAnimSequenceLevelSequenceLink::StaticClass());
}
}
}
LevelAnimLinkItem.PathToAnimSequence = FSoftObjectPath(AnimSequence);
LevelAnimLinkItem.bExportMorphTargets = ExportOptions->bExportMorphTargets;
LevelAnimLinkItem.bExportAttributeCurves = ExportOptions->bExportAttributeCurves;
LevelAnimLinkItem.bExportMaterialCurves = ExportOptions->bExportMaterialCurves;
LevelAnimLinkItem.bExportTransforms = ExportOptions->bExportTransforms;
LevelAnimLinkItem.Interpolation = ExportOptions->Interpolation;
LevelAnimLinkItem.CurveInterpolation = ExportOptions->CurveInterpolation;
LevelAnimLinkItem.bRecordInWorldSpace = ExportOptions->bRecordInWorldSpace;
LevelAnimLinkItem.bEvaluateAllSkeletalMeshComponents = ExportOptions->bEvaluateAllSkeletalMeshComponents;
LevelAnimLinkItem.IncludeAnimationNames = ExportOptions->IncludeAnimationNames;
LevelAnimLinkItem.ExcludeAnimationNames = ExportOptions->ExcludeAnimationNames;
LevelAnimLinkItem.WarmUpFrames = ExportOptions->WarmUpFrames;
LevelAnimLinkItem.DelayBeforeStart = ExportOptions->DelayBeforeStart;
LevelAnimLinkItem.bUseCustomTimeRange = ExportOptions->bUseCustomTimeRange;
LevelAnimLinkItem.CustomStartFrame = ExportOptions->CustomStartFrame;
LevelAnimLinkItem.CustomEndFrame = ExportOptions->CustomEndFrame;
LevelAnimLinkItem.CustomDisplayRate = ExportOptions->CustomDisplayRate;
break;
}
}
}
else
{
LevelAnimLink = NewObject<ULevelSequenceAnimSequenceLink>(Sequence, NAME_None, RF_Public | RF_Transactional);
}
if (bAddItem == true)
{
FLevelSequenceAnimSequenceLinkItem LevelAnimLinkItem;
LevelAnimLinkItem.SkelTrackGuid = Binding.BindingID;
LevelAnimLinkItem.PathToAnimSequence = FSoftObjectPath(AnimSequence);
LevelAnimLinkItem.bExportMorphTargets = ExportOptions->bExportMorphTargets;
LevelAnimLinkItem.bExportAttributeCurves = ExportOptions->bExportAttributeCurves;
LevelAnimLinkItem.Interpolation = ExportOptions->Interpolation;
LevelAnimLinkItem.CurveInterpolation = ExportOptions->CurveInterpolation;
LevelAnimLinkItem.bExportMaterialCurves = ExportOptions->bExportMaterialCurves;
LevelAnimLinkItem.bExportTransforms = ExportOptions->bExportTransforms;
LevelAnimLinkItem.bRecordInWorldSpace = ExportOptions->bRecordInWorldSpace;
LevelAnimLinkItem.bEvaluateAllSkeletalMeshComponents = ExportOptions->bEvaluateAllSkeletalMeshComponents;
LevelAnimLinkItem.IncludeAnimationNames = ExportOptions->IncludeAnimationNames;
LevelAnimLinkItem.ExcludeAnimationNames = ExportOptions->ExcludeAnimationNames;
LevelAnimLinkItem.WarmUpFrames = ExportOptions->WarmUpFrames;
LevelAnimLinkItem.DelayBeforeStart = ExportOptions->DelayBeforeStart;
LevelAnimLinkItem.bUseCustomTimeRange = ExportOptions->bUseCustomTimeRange;
LevelAnimLinkItem.CustomStartFrame = ExportOptions->CustomStartFrame;
LevelAnimLinkItem.CustomEndFrame = ExportOptions->CustomEndFrame;
LevelAnimLinkItem.CustomDisplayRate = ExportOptions->CustomDisplayRate;
LevelAnimLink->AnimSequenceLinks.Add(LevelAnimLinkItem);
AssetUserDataInterface->AddAssetUserData(LevelAnimLink);
}
}
}
return true;
}
UAnimSequenceLevelSequenceLink* USequencerToolsFunctionLibrary::GetLevelSequenceLinkFromAnimSequence(UAnimSequence* InAnimSequence)
{
if (IInterface_AssetUserData* AnimAssetUserData = Cast< IInterface_AssetUserData >(InAnimSequence))
{
UAnimSequenceLevelSequenceLink* AnimLevelLink = AnimAssetUserData->GetAssetUserData< UAnimSequenceLevelSequenceLink >();
return AnimLevelLink;
}
return nullptr;
}
ULevelSequenceAnimSequenceLink* USequencerToolsFunctionLibrary::GetAnimSequenceLinkFromLevelSequence(ULevelSequence* InLevelSequence)
{
if (IInterface_AssetUserData* AssetUserDataInterface = Cast< IInterface_AssetUserData >(InLevelSequence))
{
ULevelSequenceAnimSequenceLink* LevelAnimLink = AssetUserDataInterface->GetAssetUserData< ULevelSequenceAnimSequenceLink >();
return LevelAnimLink;
}
return nullptr;
}
TArray<FGuid> AddActors(UWorld* World, UMovieSceneSequence* InSequence, UMovieScene* InMovieScene, IMovieScenePlayer* Player, FMovieSceneSequenceIDRef TemplateID,const TArray<TWeakObjectPtr<AActor> >& InActors)
{
TArray<FGuid> PossessableGuids;
if (InMovieScene->IsReadOnly())
{
return PossessableGuids;
}
for (TWeakObjectPtr<AActor> WeakActor : InActors)
{
if (AActor* Actor = WeakActor.Get())
{
FGuid ExistingGuid = Player->FindObjectId(*Actor, TemplateID);
if (!ExistingGuid.IsValid())
{
InMovieScene->Modify();
const FGuid PossessableGuid = InMovieScene->AddPossessable(Actor->GetActorLabel(), Actor->GetClass());
PossessableGuids.Add(PossessableGuid);
InSequence->BindPossessableObject(PossessableGuid, *Actor, World);
InMovieScene->FindPossessable(PossessableGuid)->FixupPossessedObjectClass(InSequence, World);
//TODO New to figure way to call void FLevelSequenceEditorToolkit::AddDefaultTracksForActor(AActor& Actor, const FGuid Binding)
if (Actor->IsA<ACameraActor>())
{
MovieSceneToolHelpers::CreateCameraCutSectionForCamera(InMovieScene, PossessableGuid, 0);
}
}
}
}
return PossessableGuids;
}
void ImportFBXCamera(UnFbx::FFbxImporter* FbxImporter, UWorld* World, UMovieSceneSequence* Sequence, UMovieScene* InMovieScene, IMovieScenePlayer* Player, FMovieSceneSequenceIDRef TemplateID, TMap<FGuid, FString>& InObjectBindingMap, bool bMatchByNameOnly, bool bCreateCameras)
{
if (bCreateCameras)
{
TArray<FbxCamera*> AllCameras;
MovieSceneToolHelpers::GetCameras(FbxImporter->Scene->GetRootNode(), AllCameras);
// Find unmatched cameras
TArray<FbxCamera*> UnmatchedCameras;
for (auto Camera : AllCameras)
{
FString NodeName = MovieSceneToolHelpers::GetCameraName(Camera);
bool bMatched = false;
for (auto InObjectBinding : InObjectBindingMap)
{
FString ObjectName = InObjectBinding.Value;
if (ObjectName == NodeName)
{
// Look for a valid bound object, otherwise need to create a new camera and assign this binding to it
bool bFoundBoundObject = false;
TArrayView<TWeakObjectPtr<>> BoundObjects = Player->FindBoundObjects(InObjectBinding.Key, TemplateID);
for (auto BoundObject : BoundObjects)
{
if (BoundObject.IsValid())
{
bFoundBoundObject = true;
break;
}
}
}
}
if (!bMatched)
{
UnmatchedCameras.Add(Camera);
}
}
// If there are new cameras, clear the object binding map so that we're only assigning values to the newly created cameras
if (UnmatchedCameras.Num() != 0)
{
InObjectBindingMap.Reset();
bMatchByNameOnly = true;
}
// Add any unmatched cameras
for (auto UnmatchedCamera : UnmatchedCameras)
{
FString CameraName = MovieSceneToolHelpers::GetCameraName(UnmatchedCamera);
AActor* NewCamera = nullptr;
if (UnmatchedCamera->GetApertureMode() == FbxCamera::eFocalLength)
{
FActorSpawnParameters SpawnParams;
NewCamera = World->SpawnActor<ACineCameraActor>(SpawnParams);
NewCamera->SetActorLabel(*CameraName);
}
else
{
FActorSpawnParameters SpawnParams;
NewCamera = World->SpawnActor<ACameraActor>(SpawnParams);
NewCamera->SetActorLabel(*CameraName);
}
// Copy camera properties before adding default tracks so that initial camera properties match and can be restored after sequencer finishes
MovieSceneToolHelpers::CopyCameraProperties(UnmatchedCamera, NewCamera);
TArray<TWeakObjectPtr<AActor> > NewCameras;
NewCameras.Add(NewCamera);
TArray<FGuid> NewCameraGuids = AddActors(World, Sequence,InMovieScene, Player, TemplateID,NewCameras);
if (NewCameraGuids.Num())
{
InObjectBindingMap.Add(NewCameraGuids[0]);
InObjectBindingMap[NewCameraGuids[0]] = CameraName;
}
}
}
//everything created now import it in.
MovieSceneToolHelpers::ImportFBXCameraToExisting(FbxImporter, Sequence, Player, TemplateID, InObjectBindingMap, bMatchByNameOnly, true);
}
bool ImportFBXInternal(UWorld* World, UMovieSceneSequence* Sequence, const TArray<FMovieSceneBindingProxy>& InBindings, UMovieSceneUserImportFBXSettings* ImportFBXSettings, const FString& ImportFilename, UMovieSceneSequencePlayer* Player)
{
UMovieScene* MovieScene = Sequence->GetMovieScene();
if (!MovieScene || MovieScene->IsReadOnly())
{
return false;
}
TArray<FMovieSceneBindingProxy> AllBindings;
for (const FMovieSceneBindingProxy& Binding : InBindings)
{
AllBindings.Add(Binding);
GatherDescendantBindings(Binding, Sequence, AllBindings);
}
TMap<FGuid, FString> ObjectBindingMap;
for (const FMovieSceneBindingProxy& Binding : AllBindings)
{
FString Name = MovieScene->GetObjectDisplayName(Binding.BindingID).ToString();
ObjectBindingMap.Add(Binding.BindingID, Name);
}
FFBXInOutParameters InOutParams;
if (!MovieSceneToolHelpers::ReadyFBXForImport(ImportFilename, ImportFBXSettings, InOutParams))
{
return false;
}
const bool bMatchByNameOnly = ImportFBXSettings->bMatchByNameOnly;
UnFbx::FFbxImporter* FbxImporter = UnFbx::FFbxImporter::GetInstance();
bool bResult = false;
FScopedTransaction ImportFBXTransaction(NSLOCTEXT("Sequencer", "ImportFBX", "Import FBX"));
{
Sequencer- Refactor Bindings to support inherited Custom Bindings. With this checkin, the binding system inside Level Sequences has been refactored to allow C++ custom binding classes inheriting from a new class, UMovieSceneCustomBinding. Custom bindings are held as instanced UObjects inside FMovieSceneBindingReference, alongside the Universal Object Locator. In the case where a custom binding has been specified, the UOL will be ignored. The intention with this change is to allow developers to create their own arbitrary methods of binding any UObject to a track inside Sequencer. Examples of this include: * Runtime dynamic bindings to spawned NPC or player characters (e.g. in UEFN) with a different spawned preview character * Blueprint-specified dynamic bindings * Spawnable bindings based on something other than a AActor template * Scene Graph/Prefabs Alongside the base UMovieSceneCustomBinding class, a new hierarchy of spawnable custom binding classes has been created as the basis for allowing spawnable bindings that don't require object templates, and may instead require other asset references, for example UEFN NPC character spawnables requiring an NPC Character Definition asset. This hierarchy is currently. UMovieSceneCustomBinding <- UMovieSceneSpawnableBindingBase <- UMovieSceneSpawnableActorBindingBase <- UMovieSceneSpawnableActorBinding. This hierarchy allows for spawnables of non-actor types, spawnables of actor types not based on templates, and finally UMovieSceneSpawnableActorBinding, which is a re-implementation of FMovieSceneSpawnable inside the custom binding system. Going forward, we will be moving to deprecate FMovieSceneSpawnable in UE Sequencer in favor of the custom spawnable binding types. Sequences with FMovieSceneSpawnables will continue to function as normal, but new spawnables in new sequences will use UMovieSceneSpawnableActorBinding under the hood. These will technically have FMovieScenePossessable structs created for them for now rather than FMovieSceneSpawnable structs. This should be mostly invisible to the user. In addition, I've added a separate hierarchy of custom bindings called 'Replaceable' bindings. A 'Replaceable' is a binding type that will expect in runtime to always be overridden by a different object that may not be available in editor. UMovieSceneReplaceableBinding will hold in EDITORONLY_DATA a UMovieSceneSpawnableBindingBase to provide a preview while within Sequencer. Included in this is a UMovieSceneReplaceableActorBinding, which uses the UMovieSceneSpawnableActorBinding internally to spawn its preview, and has no implementation to find the actor during runtime- it relies on the user overriding the actor binding using the existing BindingOverrides method on LevelSequenceActor. Next Steps: * UEFN custom bindings will be built upon this system, to allow UEFN users multiple ways to override bindings. * UEFN custom spawnable bindings will be built upon this system, to allow UEFN users a way to spawn actors and objects within Sequencer with their lifetime managed by Sequencer * With this change, we have a cleaner way of incorporating the 'dynamic binding' work that uses the Director Blueprint to create a spawnable or possessable. This should be incorporated into the UCustomBinding hierarchy. * Once Verse supports it, we should add Verse custom binding logic * We need to add a Universal Object Locator type that can reference any other binding in the sequence hierarchy. This will allow us to adapt the existing 'Spawnable Parent' possessable binding logic to reference any other type of binding, not just spawnable ones. * Eventually we will fully deprecate FMovieSceneSpawnable Further notes: * A previous imagined version of this system used the cache as a way to allow locators to spawn actors and register them with Sequencer. This change removes this code. * Custom Spawnable Bindings use the Binding Lifetime Track to determine their spawn lifetime rather than the old spawn track. This unifies the concept of the lifetime of an object binding within sequencer for both spawnables and possessables. * As FMovieScenePossessable and FMovieSceneBindingReferences allows multiple bindings per guid, this change now allows multiple spawnables to be spawned and controlled by a single binding track. However, some of the editor tooling code doesn't currently handle this properly and at times assumes a single binding. This should be resolved one way or the other. * The UX for this allows UCustomBindings to handle creating bindings from any dragged in object using a priority system- Sequencer will ask all classes in priority order if they support binding creation from that object. * The UX supports unique overlay icons and tooltips for different types of bindings * The UX allows each binding type to decide whether it can convert a current binding into its own type and then do so * Currently there is some manual instanced detail customization for UMovieSceneCustomSpawnableActorBinding. We use instanced customization so that the UX has the sequencer context. This should both be improved (to allow ways to choose a class/template via this UI), as well as extended so that clients outside of the Movie Scene plugin can register instanced detail customizations for their own binding types. * Where possible, Sequencer APIs around spawnables have been refactored to take guids rather than FMovieSceneSpawnable references. In particular, custom spawnables do still use the spawn register, but do not use actor spawners- instead the UMovieSceneCustomBinding class is given the responsiblity of spawning/destroying the object/actor. This created an awkward API for USD export, which had overridden the spawn register to unhide/hide actors rather than spawning/destroying them. This could use some more work. MetaHumanPerformanceExportUtils will also need to be refactored at some point to use the custom spawnable binding system. * FSequencerUtilities::CreateBinding and CreateGenericBinding has been refactored to accept binding parameters and now supports creating custom bindings including spawnables, as well as replacing existing bindings and adding additional bindings to an existing guid. [REVIEW] [at]ue-sequencer #jira UE-199299, FORT-582815, UE-209594 #rb Andrew.Rodham, daniel.coelho, Max.Chen [CL 32218187 by david bromberg in ue5-main branch]
2024-03-13 12:48:46 -04:00
FSpawnableRestoreState SpawnableRestoreState(MovieScene, Player->GetSharedPlaybackState().ToSharedPtr());
if (SpawnableRestoreState.bWasChanged)
{
// Evaluate at the beginning of the subscene time to ensure that spawnables are created before export
FFrameTime StartTime = FFrameRate::TransformTime(UE::MovieScene::DiscreteInclusiveLower(MovieScene->GetPlaybackRange()).Value, MovieScene->GetTickResolution(), MovieScene->GetDisplayRate());
Player->SetPlaybackPosition(FMovieSceneSequencePlaybackParams(StartTime, EUpdatePositionMethod::Play));
}
ImportFBXCamera(FbxImporter, World, Sequence, MovieScene, Player, MovieSceneSequenceID::Root, ObjectBindingMap, bMatchByNameOnly, ImportFBXSettings->bCreateCameras);
bResult = MovieSceneToolHelpers::ImportFBXIfReady(World, Sequence, Player, MovieSceneSequenceID::Root, ObjectBindingMap, ImportFBXSettings, InOutParams);
}
Player->Stop();
return bResult;
}
bool USequencerToolsFunctionLibrary::ImportLevelSequenceFBX(UWorld* World, ULevelSequence* Sequence, const TArray<FMovieSceneBindingProxy>& InBindings, UMovieSceneUserImportFBXSettings* ImportFBXSettings, const FString& ImportFilename)
{
ALevelSequenceActor* OutActor;
FMovieSceneSequencePlaybackSettings Settings;
FLevelSequenceCameraSettings CameraSettings;
ULevelSequencePlayer* Player = ULevelSequencePlayer::CreateLevelSequencePlayer(World, Sequence, Settings, OutActor);
bool bSuccess = ImportFBXInternal(World, Sequence, InBindings, ImportFBXSettings, ImportFilename, Player);
World->DestroyActor(OutActor);
return bSuccess;
}
bool USequencerToolsFunctionLibrary::ImportFBXToControlRig(UWorld* World, ULevelSequence* Sequence, const FString& ControlRigTrackName, const TArray<FString>& ControlRigNames,
UMovieSceneUserImportFBXControlRigSettings* ImportFBXControlRigSettings,
const FString& ImportFilename)
{
UMovieScene* MovieScene = Sequence->GetMovieScene();
if (!MovieScene || MovieScene->IsReadOnly())
{
return false;
}
bool bValid = false;
const TArray<FMovieSceneBinding>& Bindings = MovieScene->GetBindings();
for (const FMovieSceneBinding& Binding : Bindings)
{
if (Binding.GetName() == ControlRigTrackName)
{
ALevelSequenceActor* OutActor;
FMovieSceneSequencePlaybackSettings Settings;
FLevelSequenceCameraSettings CameraSettings;
ULevelSequencePlayer* Player = ULevelSequencePlayer::CreateLevelSequencePlayer(World, Sequence, Settings, OutActor);
const TArray<UMovieSceneTrack*>& Tracks = Binding.GetTracks();
TArray<FName> SelectedControls;
for (UMovieSceneTrack* Track : Tracks)
{
INodeAndChannelMappings* ChannelMapping = Cast<INodeAndChannelMappings>(Track);
if (ChannelMapping)
{
TArray<FRigControlFBXNodeAndChannels>* NodeAndChannels = ChannelMapping->GetNodeAndChannelMappings(nullptr);
//use passed in controls for selected, actually selected controls should almost be empty anyway since we just loaded/set everything up.
for (const FString& StringName : ControlRigNames)
{
FName Name(*StringName);
SelectedControls.Add(Name);
}
bValid = MovieSceneToolHelpers::ImportFBXIntoControlRigChannels(MovieScene,ImportFilename, ImportFBXControlRigSettings,
NodeAndChannels, SelectedControls, MovieScene->GetTickResolution());
if (NodeAndChannels)
{
delete NodeAndChannels;
}
}
}
return bValid;
}
}
return false;
}
bool USequencerToolsFunctionLibrary::ExportFBXFromControlRig(ULevelSequence* Sequence,
const FString& ActorWithControlRigTrack,
const UMovieSceneUserExportFBXControlRigSettings* ExportFBXControlRigSettings)
{
bool bValid = false;
if (!Sequence || !ExportFBXControlRigSettings)
{
return false;
}
UMovieScene* MovieScene = Sequence->GetMovieScene();
if (!MovieScene || MovieScene->IsReadOnly())
{
return false;
}
const TArray<FMovieSceneBinding>& Bindings = MovieScene->GetBindings();
for (const FMovieSceneBinding& Binding : Bindings)
{
if (Binding.GetName() != ActorWithControlRigTrack)
{
continue;
}
for (UMovieSceneTrack* Track : Binding.GetTracks())
{
INodeAndChannelMappings* ChannelMapping = Cast<INodeAndChannelMappings>(Track);
const UMovieSceneSection* Section = Track->GetSectionToKey();
if (!ChannelMapping || !Section)
{
continue;
}
TArray<FName> SelectedControls;
ChannelMapping->GetSelectedNodes(SelectedControls);
const FMovieSceneSequenceTransform RootToLocalTransform;
return MovieSceneToolHelpers::ExportFBXFromControlRigChannels(Section, ExportFBXControlRigSettings, SelectedControls, RootToLocalTransform);
}
}
return false;
}
FMovieSceneEvent USequencerToolsFunctionLibrary::CreateEvent(UMovieSceneSequence* InSequence, UMovieSceneEventSectionBase* InSection, const FSequencerQuickBindingResult& InEndpoint, const TArray<FString>& InPayload)
{
FMovieSceneEvent Event;
if (InEndpoint.EventEndpoint == nullptr)
{
FFrame::KismetExecutionMessage(TEXT("Invalid endpoint, event will not be initialized"), ELogVerbosity::Warning);
return Event;
}
UMovieScene* MovieScene = InSequence->GetMovieScene();
FGuid ObjectBindingID;
MovieScene->FindTrackBinding(*InSection->GetTypedOuter<UMovieSceneTrack>(), ObjectBindingID);
UClass* BoundObjectPinClass = nullptr;
if (FMovieScenePossessable* Possessable = MovieScene->FindPossessable(ObjectBindingID))
{
BoundObjectPinClass = const_cast<UClass*>(Possessable->GetPossessedObjectClass());
}
else if (FMovieSceneSpawnable* Spawnable = MovieScene->FindSpawnable(ObjectBindingID))
{
BoundObjectPinClass = Spawnable->GetObjectTemplate()->GetClass();
}
InSection->Modify();
FMovieSceneEventUtils::BindEventSectionToBlueprint(InSection, InEndpoint.EventEndpoint->GetBlueprint());
UEdGraphPin* BoundObjectPin = FMovieSceneDirectorBlueprintUtils::FindCallTargetPin(InEndpoint.EventEndpoint, BoundObjectPinClass);
FMovieSceneEventUtils::SetEndpoint(&Event, InSection, InEndpoint.EventEndpoint, BoundObjectPin);
if (InEndpoint.PayloadNames.Num() != InPayload.Num())
{
const FString Message = FString::Printf(TEXT("Wrong number of payload values, expecting %i got %i"), InEndpoint.PayloadNames.Num(), InPayload.Num());
FFrame::KismetExecutionMessage(*Message, ELogVerbosity::Warning);
return Event;
}
for (int32 Index = 0; Index < InEndpoint.PayloadNames.Num(); Index++)
{
const FName PayloadName = FName(InEndpoint.PayloadNames[Index]);
if (!Event.PayloadVariables.Contains(PayloadName))
{
Event.PayloadVariables.Add(PayloadName);
Event.PayloadVariables[PayloadName].Value = InPayload[Index];
}
}
return Event;
}
bool USequencerToolsFunctionLibrary::IsEventEndpointValid(const FSequencerQuickBindingResult& InEndpoint)
{
return InEndpoint.EventEndpoint != nullptr;
}
FSequencerQuickBindingResult USequencerToolsFunctionLibrary::CreateQuickBinding(UMovieSceneSequence* InSequence, UObject* InObject, const FString& InFunctionName, bool bCallInEditor)
{
FSequencerQuickBindingResult Result;
FMovieSceneSequenceEditor* SequenceEditor = FMovieSceneSequenceEditor::Find(InSequence);
if (!SequenceEditor)
{
return Result;
}
UBlueprint* Blueprint = SequenceEditor->GetOrCreateDirectorBlueprint(InSequence);
if (!Blueprint)
{
return Result;
}
UMovieScene* MovieScene = InSequence->GetMovieScene();
FMovieSceneDirectorBlueprintEndpointDefinition EndpointDefinition;
EndpointDefinition.EndpointType = EMovieSceneDirectorBlueprintEndpointType::Event;
EndpointDefinition.EndpointName = InFunctionName;
EndpointDefinition.PossibleCallTargetClass = InObject->GetClass();
EndpointDefinition.AddExtraOutputPin(InObject->GetName(), UEdGraphSchema_K2::PC_Object, InObject->GetClass());
UFunction* Function = InObject->GetClass()->FindFunctionByName(FName(InFunctionName));
if (Function == nullptr)
{
const FString Message = FString::Printf(TEXT("Cannot find function %s in class %s"), *(InFunctionName), *(InObject->GetClass()->GetName()));
FFrame::KismetExecutionMessage(*Message, ELogVerbosity::Warning);
return Result;
}
UBlueprintFunctionNodeSpawner* BlueprintFunctionNodeSpawner = UBlueprintFunctionNodeSpawner::Create(Function);
FBlueprintActionMenuItem Action(BlueprintFunctionNodeSpawner);
UK2Node_CustomEvent* NewEventEndpoint = FMovieSceneDirectorBlueprintUtils::CreateEventEndpoint(Blueprint, EndpointDefinition);
NewEventEndpoint->bCallInEditor = bCallInEditor;
Result.EventEndpoint = NewEventEndpoint;
UEdGraphPin* ThenPin = NewEventEndpoint->FindPin(UEdGraphSchema_K2::PN_Then, EGPD_Output);
UEdGraphPin* BoundObjectPin = FMovieSceneDirectorBlueprintUtils::FindCallTargetPin(NewEventEndpoint, EndpointDefinition.PossibleCallTargetClass);
FVector2D NodePosition(NewEventEndpoint->NodePosX + 400.f, NewEventEndpoint->NodePosY);
UEdGraphNode* NewNode = Action.PerformAction(NewEventEndpoint->GetGraph(), BoundObjectPin ? BoundObjectPin : ThenPin, NodePosition);
if (NewNode == nullptr)
{
const FString Message = FString::Printf(TEXT("Failed creating blueprint event node for function %s"), *InFunctionName);
FFrame::KismetExecutionMessage(*Message, ELogVerbosity::Warning);
return Result;
}
// Link execution pins
UEdGraphPin* ExecPin = NewNode->FindPin(UEdGraphSchema_K2::PN_Execute, EGPD_Input);
if (ensure(ThenPin && ExecPin))
{
ThenPin->MakeLinkTo(ExecPin);
}
// Link payload parameters' pins
UK2Node_EditablePinBase* EditableNode = Cast<UK2Node_EditablePinBase>(NewEventEndpoint);
if (EditableNode)
{
for (UEdGraphPin* PayloadPin : NewNode->Pins)
{
if (PayloadPin != BoundObjectPin && PayloadPin->Direction == EGPD_Input && PayloadPin->PinType.PinCategory != UEdGraphSchema_K2::PC_Exec && PayloadPin->LinkedTo.Num() == 0)
{
Result.PayloadNames.Add(PayloadPin->PinName.ToString());
UEdGraphPin* NewPin = EditableNode->CreateUserDefinedPin(PayloadPin->PinName, PayloadPin->PinType, EGPD_Output);
if (NewNode != NewEventEndpoint && NewPin)
{
NewPin->MakeLinkTo(PayloadPin);
}
}
}
}
return Result;
}
#undef LOCTEXT_NAMESPACE // "SequencerTools"