void FHierarchicalLODUtilities::DestroyCluster(ALODActor* InActor) { // Find if it has a parent ALODActor AActor* Actor = CastChecked<AActor>(InActor); UWorld* World = Actor->GetWorld(); ALODActor* ParentLOD = GetParentLODActor(InActor); const FScopedTransaction Transaction(LOCTEXT("UndoAction_DeleteCluster", "Deleting a (invalid) Cluster")); Actor->Modify(); World->Modify(); if (ParentLOD != nullptr) { ParentLOD->Modify(); ParentLOD->RemoveSubActor(Actor); } // Clean out sub actors and update their LODParent while (InActor->SubActors.Num()) { AActor* SubActor = InActor->SubActors[0]; SubActor->Modify(); InActor->RemoveSubActor(SubActor); } // Also destroy the cluster's data DestroyClusterData(InActor); World->DestroyActor(InActor); if (ParentLOD != nullptr && !ParentLOD->HasValidSubActors()) { DestroyCluster(ParentLOD); } }
void UChildActorComponent::DestroyChildActor(const bool bRequiresRename) { // If we own an Actor, kill it now if(ChildActor != nullptr && !GExitPurge) { // if still alive, destroy, otherwise just clear the pointer if (!ChildActor->IsPendingKillOrUnreachable()) { #if WITH_EDITOR if (CachedInstanceData) { delete CachedInstanceData; CachedInstanceData = nullptr; } #else check(!CachedInstanceData); #endif // If we're already tearing down we won't be needing this if (!HasAnyFlags(RF_BeginDestroyed)) { CachedInstanceData = new FChildActorComponentInstanceData(this); } UWorld* World = ChildActor->GetWorld(); // World may be nullptr during shutdown if(World != nullptr) { UClass* ChildClass = ChildActor->GetClass(); // We would like to make certain that our name is not going to accidentally get taken from us while we're destroyed // so we increment ClassUnique beyond our index to be certain of it. This is ... a bit hacky. ChildClass->ClassUnique = FMath::Max(ChildClass->ClassUnique, ChildActor->GetFName().GetNumber()); if (bRequiresRename) { const FString ObjectBaseName = FString::Printf(TEXT("DESTROYED_%s_CHILDACTOR"), *ChildClass->GetName()); const ERenameFlags RenameFlags = ((GetWorld()->IsGameWorld() || IsLoading()) ? REN_DoNotDirty | REN_ForceNoResetLoaders : REN_DoNotDirty); ChildActor->Rename(*MakeUniqueObjectName(ChildActor->GetOuter(), ChildClass, *ObjectBaseName).ToString(), nullptr, RenameFlags); } World->DestroyActor(ChildActor); } } ChildActor = nullptr; } }
void FHierarchicalLODUtilities::DestroyLODActor(ALODActor* InActor) { const FScopedTransaction Transaction(LOCTEXT("UndoAction_DeleteLODActor", "Delete LOD Actor")); UWorld* World = InActor->GetWorld(); World->Modify(); InActor->Modify(); ALODActor* ParentActor = FHierarchicalLODUtilities::GetParentLODActor(InActor); FHierarchicalLODUtilities::DestroyCluster(InActor); World->DestroyActor(InActor); if (ParentActor && !ParentActor->HasValidSubActors()) { ParentActor->Modify(); FHierarchicalLODUtilities::DestroyLODActor(ParentActor); } }
void AGameplayDebuggerPlayerManager::UpdateAuthReplicators() { UWorld* World = GetWorld(); for (int32 Idx = PlayerData.Num() - 1; Idx >= 0; Idx--) { FGameplayDebuggerPlayerData& TestData = PlayerData[Idx]; if (!IsValid(TestData.Replicator) || !IsValid(TestData.Replicator->GetReplicationOwner())) { if (IsValid(TestData.Replicator)) { World->DestroyActor(TestData.Replicator); } if (IsValid(TestData.Controller)) { TestData.Controller->Cleanup(); } PlayerData.RemoveAt(Idx, 1, false); } } for (FConstPlayerControllerIterator It = World->GetPlayerControllerIterator(); It; It++) { APlayerController* TestPC = *It; if (TestPC && !TestPC->IsA<ADebugCameraController>()) { const bool bNeedsReplicator = (GetReplicator(*TestPC) == nullptr); if (bNeedsReplicator) { AGameplayDebuggerCategoryReplicator* Replicator = World->SpawnActorDeferred<AGameplayDebuggerCategoryReplicator>(AGameplayDebuggerCategoryReplicator::StaticClass(), FTransform::Identity); Replicator->SetReplicatorOwner(TestPC); Replicator->FinishSpawning(FTransform::Identity, true); } } } PrimaryActorTick.TickInterval = PlayerData.Num() ? 5.0f : 0.5f; }
SVisualLogger::~SVisualLogger() { UWorld* World = NULL; #if WITH_EDITOR FCategoryFiltersManager::Get().SavePresistentData(); UEditorEngine *EEngine = Cast<UEditorEngine>(GEngine); if (GIsEditor && EEngine != NULL) { // lets use PlayWorld during PIE/Simulate and regular world from editor otherwise, to draw debug information World = EEngine->PlayWorld != NULL ? EEngine->PlayWorld : EEngine->GetEditorWorldContext().World(); } else #endif if (!GIsEditor) { World = GEngine->GetWorld(); } if (World == NULL) { World = GWorld; } if (World) { for (TActorIterator<AVisualLoggerRenderingActor> It(World); It; ++It) { World->DestroyActor(*It); } } UDebugDrawService::Unregister(DrawOnCanvasDelegateHandle); VisualLoggerCanvasRenderer.Reset(); FVisualLogger::Get().RemoveDevice(InternalDevice.Get()); InternalDevice.Reset(); }
void UChildActorComponent::DestroyChildActor() { // If we own an Actor, kill it now if(ChildActor != nullptr && !GExitPurge) { // if still alive, destroy, otherwise just clear the pointer if(!ChildActor->IsPendingKill()) { #if WITH_EDITOR if (CachedInstanceData) { delete CachedInstanceData; } #else check(!CachedInstanceData); #endif CachedInstanceData = new FChildActorComponentInstanceData(this); UWorld* World = ChildActor->GetWorld(); // World may be nullptr during shutdown if(World != nullptr) { UClass* ChildClass = ChildActor->GetClass(); // We would like to make certain that our name is not going to accidentally get taken from us while we're destroyed // so we increment ClassUnique beyond our index to be certain of it. This is ... a bit hacky. ChildClass->ClassUnique = FMath::Max(ChildClass->ClassUnique, ChildActor->GetFName().GetNumber()); const FString ObjectBaseName = FString::Printf(TEXT("DESTROYED_%s_CHILDACTOR"), *ChildClass->GetName()); ChildActor->Rename(*MakeUniqueObjectName(ChildActor->GetOuter(), ChildClass, *ObjectBaseName).ToString(), nullptr, REN_DoNotDirty); World->DestroyActor(ChildActor); } } ChildActor = nullptr; } }
void UChildActorComponent::DestroyChildActor() { // If we own an Actor, kill it now unless we don't have authority on it, for that we rely on the server // If the level that the child actor is being removed then don't destory the child actor so re-adding it doesn't // need to create a new actor if (ChildActor && ChildActor->HasAuthority() && !GetOwner()->GetLevel()->bIsBeingRemoved) { if (!GExitPurge) { // if still alive, destroy, otherwise just clear the pointer if (!ChildActor->IsPendingKillOrUnreachable()) { #if WITH_EDITOR if (CachedInstanceData) { delete CachedInstanceData; CachedInstanceData = nullptr; } #else check(!CachedInstanceData); #endif // If we're already tearing down we won't be needing this if (!HasAnyFlags(RF_BeginDestroyed) && !IsUnreachable()) { CachedInstanceData = new FChildActorComponentInstanceData(this); } UWorld* World = ChildActor->GetWorld(); // World may be nullptr during shutdown if (World != nullptr) { UClass* ChildClass = ChildActor->GetClass(); // We would like to make certain that our name is not going to accidentally get taken from us while we're destroyed // so we increment ClassUnique beyond our index to be certain of it. This is ... a bit hacky. int32& ClassUnique = ChildActor->GetOutermost()->ClassUniqueNameIndexMap.FindOrAdd(ChildClass->GetFName()); ClassUnique = FMath::Max(ClassUnique, ChildActor->GetFName().GetNumber()); // If we are getting here due to garbage collection we can't rename, so we'll have to abandon this child actor name and pick up a new one if (!IsGarbageCollecting()) { const FString ObjectBaseName = FString::Printf(TEXT("DESTROYED_%s_CHILDACTOR"), *ChildClass->GetName()); const ERenameFlags RenameFlags = ((GetWorld()->IsGameWorld() || IsLoading()) ? REN_DoNotDirty | REN_ForceNoResetLoaders : REN_DoNotDirty); ChildActor->Rename(*MakeUniqueObjectName(ChildActor->GetOuter(), ChildClass, *ObjectBaseName).ToString(), nullptr, RenameFlags); } else { ChildActorName = NAME_None; if (CachedInstanceData) { CachedInstanceData->ChildActorName = NAME_None; } } World->DestroyActor(ChildActor); } } } ChildActor = nullptr; } }
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? } } } } } } }