void FSequencerActorBindingManager::SpawnOrDestroyObjectsForInstance( TSharedRef<FMovieSceneInstance> MovieSceneInstance, const bool bDestroyAll ) { bool bAnyLevelActorsChanged = false; // Get the list of puppet objects for the movie scene TArray< TSharedRef<FPuppetActorInfo> >& PuppetObjects = InstanceToPuppetObjectsMap.FindOrAdd( MovieSceneInstance ); UMovieScene* MovieScene = MovieSceneInstance->GetMovieScene(); // Remove any puppet objects that we no longer need { for( auto PuppetObjectIndex = 0; PuppetObjectIndex < PuppetObjects.Num(); ++PuppetObjectIndex ) { if( PuppetObjects[ PuppetObjectIndex ]->GetType() == EPuppetObjectType::Actor ) { TSharedRef< FPuppetActorInfo > PuppetActorInfo = StaticCastSharedRef< FPuppetActorInfo >( PuppetObjects[ PuppetObjectIndex ] ); // Figure out if we still need this puppet actor bool bShouldDestroyActor = true; if( !bDestroyAll ) { for( auto SpawnableIndex = 0; SpawnableIndex < MovieScene->GetSpawnableCount(); ++SpawnableIndex ) { auto& Spawnable = MovieScene->GetSpawnable( SpawnableIndex ); if( Spawnable.GetGuid() == PuppetActorInfo->SpawnableGuid ) { bShouldDestroyActor = false; break; } } } if( bShouldDestroyActor ) { AActor* PuppetActor = PuppetActorInfo->PuppetActor.Get(); if( PuppetActor != NULL ) { UWorld* PuppetWorld = PuppetActor->GetWorld(); if( ensure( PuppetWorld != NULL ) ) { // Destroy this actor { // Ignored unless called while game is running const bool bNetForce = false; // We don't want to dirty the level for puppet actor changes const bool bShouldModifyLevel = false; if( !bAnyLevelActorsChanged ) { DeselectAllPuppetObjects(); } // Actor should never be selected in the editor at this point. We took care of that up above. ensure( !PuppetActor->IsSelected() ); const bool bWasDestroyed = PuppetWorld->DestroyActor( PuppetActor, bNetForce, bShouldModifyLevel ); if( bWasDestroyed ) { bAnyLevelActorsChanged = true; PuppetObjects.RemoveAt( PuppetObjectIndex-- ); } else { // @todo sequencer: At least one puppet couldn't be cleaned up! } } } } else { // Actor is no longer valid (probably the world was destroyed) } } } else { check(0); // Unhandled type } } } if( !bDestroyAll ) { for( auto SpawnableIndex = 0; SpawnableIndex < MovieScene->GetSpawnableCount(); ++SpawnableIndex ) { FMovieSceneSpawnable& Spawnable = MovieScene->GetSpawnable( SpawnableIndex ); // Must have a valid world for us to be able to do this if( ActorWorld != NULL ) { // Do we already have a puppet for this spawnable? bool bIsAlreadySpawned = false; for( auto PuppetIndex = 0; PuppetIndex < PuppetObjects.Num(); ++PuppetIndex ) { auto& PuppetObject = PuppetObjects[ PuppetIndex ]; if( PuppetObject->SpawnableGuid == Spawnable.GetGuid() ) { bIsAlreadySpawned = true; break; } } if( !bIsAlreadySpawned ) { UClass* GeneratedClass = Spawnable.GetClass(); if ( GeneratedClass != NULL && GeneratedClass->IsChildOf(AActor::StaticClass())) { AActor* ActorCDO = CastChecked< AActor >( GeneratedClass->ClassDefaultObject ); const FVector SpawnLocation = ActorCDO->GetRootComponent()->RelativeLocation; const FRotator SpawnRotation = ActorCDO->GetRootComponent()->RelativeRotation; // @todo sequencer: We should probably spawn these in a specific sub-level! // World->CurrentLevel = ???; const FName PuppetActorName = NAME_None; // Override the object flags so that RF_Transactional is not set. Puppet actors are never transactional // @todo sequencer: These actors need to avoid any transaction history. However, RF_Transactional can currently be set on objects on the fly! const EObjectFlags ObjectFlags = RF_Transient; // NOTE: We are omitting RF_Transactional intentionally // @todo sequencer livecapture: Consider using SetPlayInEditorWorld() and RestoreEditorWorld() here instead // @todo sequencer actors: We need to make sure puppet objects aren't copied into PIE/SIE sessions! They should be omitted from that duplication! // Spawn the puppet actor FActorSpawnParameters SpawnInfo; SpawnInfo.Name = PuppetActorName; SpawnInfo.ObjectFlags = ObjectFlags; AActor* NewActor = ActorWorld->SpawnActor( GeneratedClass, &SpawnLocation, &SpawnRotation, SpawnInfo ); if( NewActor ) { // @todo sequencer: We're naming the actor based off of the spawnable's name. Is that really what we want? FActorLabelUtilities::SetActorLabelUnique(NewActor, Spawnable.GetName()); // Actor was spawned OK! // Keep track of this actor TSharedRef< FPuppetActorInfo > NewPuppetInfo( new FPuppetActorInfo() ); NewPuppetInfo->SpawnableGuid = Spawnable.GetGuid(); NewPuppetInfo->PuppetActor = NewActor; PuppetObjects.Add( NewPuppetInfo ); } else { // Actor failed to spawn // @todo sequencer: What should we do when this happens to one or more actors? } } } } } } }
void UActorAnimationPlayer::SpawnActorsForMovie(TSharedRef<FMovieSceneSequenceInstance> MovieSceneInstance) { UWorld* WorldPtr = World.Get(); if (WorldPtr == nullptr) { return; } UMovieScene* MovieScene = MovieSceneInstance->GetSequence()->GetMovieScene(); if (MovieScene == nullptr) { return; } TArray<FSpawnedActorInfo>* FoundSpawnedActors = InstanceToSpawnedActorMap.Find(MovieSceneInstance); if (FoundSpawnedActors != nullptr) { // Remove existing spawned actors for this movie DestroyActorsForMovie( MovieSceneInstance ); } TArray<FSpawnedActorInfo>& SpawnedActorList = InstanceToSpawnedActorMap.Add(MovieSceneInstance, TArray<FSpawnedActorInfo>()); for (auto SpawnableIndex = 0; SpawnableIndex < MovieScene->GetSpawnableCount(); ++SpawnableIndex) { auto& Spawnable = MovieScene->GetSpawnable(SpawnableIndex); UClass* GeneratedClass = Spawnable.GetClass(); if ((GeneratedClass == nullptr) || !GeneratedClass->IsChildOf(AActor::StaticClass())) { continue; } AActor* ActorCDO = CastChecked<AActor>(GeneratedClass->ClassDefaultObject); const FVector SpawnLocation = ActorCDO->GetRootComponent()->RelativeLocation; const FRotator SpawnRotation = ActorCDO->GetRootComponent()->RelativeRotation; FActorSpawnParameters SpawnInfo; { SpawnInfo.ObjectFlags = RF_NoFlags; } AActor* NewActor = WorldPtr->SpawnActor(GeneratedClass, &SpawnLocation, &SpawnRotation, SpawnInfo); if (NewActor) { // Actor was spawned OK! FSpawnedActorInfo NewInfo; { NewInfo.RuntimeGuid = Spawnable.GetGuid(); NewInfo.SpawnedActor = NewActor; } SpawnedActorList.Add(NewInfo); } } }
void URuntimeMovieScenePlayer::SpawnActorsForMovie( TSharedRef<FMovieSceneInstance> MovieSceneInstance ) { UWorld* WorldPtr = World.Get(); if( WorldPtr != NULL && MovieSceneBindings != NULL ) { UMovieScene* MovieScene = MovieSceneInstance->GetMovieScene(); if( MovieScene != NULL ) { TArray<FSpawnedActorInfo>* FoundSpawnedActors = InstanceToSpawnedActorMap.Find( MovieSceneInstance ); if( FoundSpawnedActors ) { // Remove existing spawned actors for this movie DestroyActorsForMovie( MovieSceneInstance ); } TArray<FSpawnedActorInfo>& SpawnedActorList = InstanceToSpawnedActorMap.Add( MovieSceneInstance, TArray<FSpawnedActorInfo>() ); for( auto SpawnableIndex = 0; SpawnableIndex < MovieScene->GetSpawnableCount(); ++SpawnableIndex ) { auto& Spawnable = MovieScene->GetSpawnable( SpawnableIndex ); UClass* GeneratedClass = Spawnable.GetClass(); if ( GeneratedClass != NULL ) { const bool bIsActorBlueprint = GeneratedClass->IsChildOf( AActor::StaticClass() ); if ( bIsActorBlueprint ) { AActor* ActorCDO = CastChecked< AActor >( GeneratedClass->ClassDefaultObject ); const FVector SpawnLocation = ActorCDO->GetRootComponent()->RelativeLocation; const FRotator SpawnRotation = ActorCDO->GetRootComponent()->RelativeRotation; FActorSpawnParameters SpawnInfo; SpawnInfo.ObjectFlags = RF_NoFlags; AActor* NewActor = WorldPtr->SpawnActor( GeneratedClass, &SpawnLocation, &SpawnRotation, SpawnInfo ); if( NewActor ) { // Actor was spawned OK! FSpawnedActorInfo NewInfo; NewInfo.RuntimeGuid = Spawnable.GetGuid(); NewInfo.SpawnedActor = NewActor; SpawnedActorList.Add( NewInfo ); } } } } } } }