We use a custom import tool to generate Level sequences from Maya export files, this involves creating spawnable bindings and modifying component parameters on the actor and then calling CopyObjectTemplate to fix those param changes to the spawnable. The next time the Level sequence loads and the actor gets spawned it would spawn with the changes made earlier.
However In UE5.6 (maybe earlier) When we create a spawnable binding we use ISequencer::CreateBinding, this now no longer creates a standard spawnable, it creates a custom possessable (change made for fortnight i believe) so we can no longer use UMovieScene::FindSpawnable (it returns Null) and CopyObjectTemplate.
I took a look at the ISequencer and SequencerUtilities code, and there is a way to create a standard spawnable binding so you can continue using FindSpawnable and CopyObjectTemplate as before.
Instead of calling ISequencer::CreateBinding directly, try using FSequencer::CreateBinding with a FCreateBindingParams where bSpawnable is set to true. This forces the creation of the “old-style” spawnable rather than the newer possessable bindings.
With bSpawnable set, CreateOrReplaceBinding will call MakeNewSpawnable() internally, giving you a valid spawnable GUID. You should be able to then use that GUID with CopyObjectTemplate just like in your previous workflow.
The rest of the available FCreateBindingParams are listed in SequencerUtilities.h
Thank you for the info, however I believe there is an issue with using the old style spawnables, I need to double check this but I believe the old style spawnables no longer give you the option to right click on the binding and change the actor class! (Menu option is missing), will get back to you with more info.
After investigation I find that setting bSpawnable to true still creates a custom binding and that the MovieScene spawnables array remains empty. This means I cant use MovieScene::FindSpawnable to then call CopyObjectTemplate.
After some digging, I ran into the problem you described. It appears the bSpawnable property still results in a custom binding and the spawnables array stays empty.
What worked for me was calling UMovieScene::AddSpawnable directly. That function does populate the Spawnables array so you can then call FindSpawnable and use CopyObjectTemplate like before.
Here’s a minimal wrapper I tested from an Editor Utility Widget:
bool UMySequencerHelper::CreateSpawnable(ULevelSequence* Sequence, UClass* ClassToSpawn, const FString& BindingDisplayName)
{
if (!Sequence || !ClassToSpawn)
{
UE_LOG(LogTemp, Warning, TEXT("CreateSpawnable: invalid Sequence or Class"));
return false;
}
UMovieScene* MovieScene = Sequence->GetMovieScene();
if (!MovieScene)
{
UE_LOG(LogTemp, Warning, TEXT("CreateSpawnable: MovieScene is null"));
return false;
}
AActor* Template = NewObject<AActor>(Sequence, ClassToSpawn, NAME_None, RF_Transactional);
if (!Template)
{
UE_LOG(LogTemp, Error, TEXT("CreateSpawnable: Failed to create template for %s"), *ClassToSpawn->GetName());
return false;
}
FMovieSceneSpawnable::MarkSpawnableTemplate(*Template);
// Add to the MovieScene
FGuid SpawnableGuid = MovieScene->AddSpawnable(BindingDisplayName, *Template);
if (!SpawnableGuid.IsValid())
{
UE_LOG(LogTemp, Error, TEXT("CreateSpawnable: AddSpawnable failed for %s"), *BindingDisplayName);
return false;
}
// You may add tracks here
if (UMovieSceneSpawnTrack* SpawnTrack = MovieScene->AddTrack<UMovieSceneSpawnTrack>(SpawnableGuid))
{
if (UMovieSceneSpawnSection* SpawnSection = Cast<UMovieSceneSpawnSection>(SpawnTrack->CreateNewSection()))
{
SpawnTrack->AddSection(*SpawnSection);
SpawnSection->GetChannel().SetDefault(true);
}
}
#if WITH_EDITOR
Sequence->MarkPackageDirty();
#endif
return true;
}
With this approach, MovieScene->FindSpawnable returns a valid entry. Please let me know if this helps.