FString FMeshMergingTool::GetDefaultPackageName() const { FString PackageName = FPackageName::FilenameToLongPackageName(FPaths::GameContentDir() + TEXT("SM_MERGED")); USelection* SelectedActors = GEditor->GetSelectedActors(); // Iterate through selected actors and find first static mesh asset // Use this static mesh path as destination package name for a merged mesh for (FSelectionIterator Iter(*SelectedActors); Iter; ++Iter) { AActor* Actor = Cast<AActor>(*Iter); if (Actor) { FString ActorName = Actor->GetName(); PackageName = FString::Printf(TEXT("%s_%s"), *PackageName, *ActorName); break; } } if (PackageName.IsEmpty()) { PackageName = MakeUniqueObjectName(NULL, UPackage::StaticClass(), *PackageName).ToString(); } return PackageName; }
//* Destroys the constructed components. void AActor::DestroyConstructedComponents() { // Remove all existing components TInlineComponentArray<UActorComponent*> PreviouslyAttachedComponents; GetComponents(PreviouslyAttachedComponents); // We need the hierarchy to be torn down in attachment order, so do a quick sort PreviouslyAttachedComponents.Remove(nullptr); PreviouslyAttachedComponents.Sort([](UActorComponent& A, UActorComponent& B) { if (USceneComponent* BSC = Cast<USceneComponent>(&B)) { if (BSC->AttachParent == &A) { return false; } } return true; }); for (UActorComponent* Component : PreviouslyAttachedComponents) { if (Component) { bool bDestroyComponent = false; if (Component->IsCreatedByConstructionScript()) { bDestroyComponent = true; } else { UActorComponent* OuterComponent = Component->GetTypedOuter<UActorComponent>(); while (OuterComponent) { if (OuterComponent->IsCreatedByConstructionScript()) { bDestroyComponent = true; break; } OuterComponent = OuterComponent->GetTypedOuter<UActorComponent>(); } } if (bDestroyComponent) { if (Component == RootComponent) { RootComponent = NULL; } Component->DestroyComponent(); // Rename component to avoid naming conflicts in the case where we rerun the SCS and name the new components the same way. FName const NewBaseName( *(FString::Printf(TEXT("TRASH_%s"), *Component->GetClass()->GetName())) ); FName const NewObjectName = MakeUniqueObjectName(this, GetClass(), NewBaseName); Component->Rename(*NewObjectName.ToString(), this, REN_ForceNoResetLoaders|REN_DontCreateRedirectors|REN_NonTransactional); } } } }
AActor* UVREditorMode::SpawnTransientSceneActor(TSubclassOf<AActor> ActorClass, const FString& ActorName, const bool bWithSceneComponent) const { const bool bWasWorldPackageDirty = GetWorld()->GetOutermost()->IsDirty(); // @todo vreditor: Needs respawn if world changes (map load, etc.) Will that always restart the editor mode anyway? FActorSpawnParameters ActorSpawnParameters; ActorSpawnParameters.Name = MakeUniqueObjectName( GetWorld(), ActorClass, *ActorName ); // @todo vreditor: Without this, SpawnActor() can return us an existing PendingKill actor of the same name! WTF? ActorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; ActorSpawnParameters.ObjectFlags = EObjectFlags::RF_Transient; check( ActorClass != nullptr ); AActor* NewActor = GetWorld()->SpawnActor< AActor >( ActorClass, ActorSpawnParameters ); NewActor->SetActorLabel( ActorName ); if( bWithSceneComponent ) { // Give the new actor a root scene component, so we can attach multiple sibling components to it USceneComponent* SceneComponent = NewObject<USceneComponent>( NewActor ); NewActor->AddOwnedComponent( SceneComponent ); NewActor->SetRootComponent( SceneComponent ); SceneComponent->RegisterComponent(); } // Don't dirty the level file after spawning a transient actor if( !bWasWorldPackageDirty ) { GetWorld()->GetOutermost()->SetDirtyFlag( false ); } return NewActor; }
/** * A helper that will take a blueprint and copy it into a new, temporary * package (intended for throwaway purposes). * * @param BlueprintToClone The blueprint you wish to duplicate. * @return A new temporary blueprint copy of what was passed in. */ static UBlueprint* DuplicateBlueprint(UBlueprint const* const BlueprintToClone) { UPackage* TempPackage = CreateTempPackage(BlueprintToClone->GetName()); FString TempBlueprintName = MakeUniqueObjectName(TempPackage, UBlueprint::StaticClass(), BlueprintToClone->GetFName()).ToString(); return Cast<UBlueprint>(StaticDuplicateObject(BlueprintToClone, TempPackage, *TempBlueprintName)); }
VObject* VObject::StaticAllocateObject(const VClass* InClass, FName InName) { if( !InClass ) { debugf(TEXT("Invalid class for object %s"), InName.toString().c_str()); return NULL; } VObject* Obj = NULL; if( InName == NAME_None ) { InName = MakeUniqueObjectName(InClass); } else { Obj = StaticFindObject(InClass, InName); } if( Obj == NULL ) { (*InClass->_ClassStaticConstructor)(&Obj); Obj->_Index = INDEX_NONE; Obj->_HashNext = NULL; Obj->_Name = InName; Obj->AddObject(INDEX_NONE); } return Obj; }
static void ReplaceStructWithTempDuplicate( UUserDefinedStruct* StructureToReinstance, TSet<UBlueprint*>& BlueprintsToRecompile, TArray<UUserDefinedStruct*>& ChangedStructs) { if (StructureToReinstance) { UUserDefinedStruct* DuplicatedStruct = NULL; { const FString ReinstancedName = FString::Printf(TEXT("STRUCT_REINST_%s"), *StructureToReinstance->GetName()); const FName UniqueName = MakeUniqueObjectName(GetTransientPackage(), UUserDefinedStruct::StaticClass(), FName(*ReinstancedName)); TGuardValue<bool> IsDuplicatingClassForReinstancing(GIsDuplicatingClassForReinstancing, true); DuplicatedStruct = (UUserDefinedStruct*)StaticDuplicateObject(StructureToReinstance, GetTransientPackage(), *UniqueName.ToString(), ~RF_Transactional); } DuplicatedStruct->Guid = StructureToReinstance->Guid; DuplicatedStruct->Bind(); DuplicatedStruct->StaticLink(true); DuplicatedStruct->PrimaryStruct = StructureToReinstance; DuplicatedStruct->Status = EUserDefinedStructureStatus::UDSS_Duplicate; DuplicatedStruct->SetFlags(RF_Transient); DuplicatedStruct->AddToRoot(); CastChecked<UUserDefinedStructEditorData>(DuplicatedStruct->EditorData)->RecreateDefaultInstance(); for (auto StructProperty : TObjectRange<UStructProperty>(RF_ClassDefaultObject | RF_PendingKill)) { if (StructProperty && (StructureToReinstance == StructProperty->Struct)) { if (auto OwnerClass = Cast<UBlueprintGeneratedClass>(StructProperty->GetOwnerClass())) { if (UBlueprint* FoundBlueprint = Cast<UBlueprint>(OwnerClass->ClassGeneratedBy)) { BlueprintsToRecompile.Add(FoundBlueprint); StructProperty->Struct = DuplicatedStruct; } } else if (auto OwnerStruct = Cast<UUserDefinedStruct>(StructProperty->GetOwnerStruct())) { check(OwnerStruct != DuplicatedStruct); const bool bValidStruct = (OwnerStruct->GetOutermost() != GetTransientPackage()) && !OwnerStruct->HasAnyFlags(RF_PendingKill) && (EUserDefinedStructureStatus::UDSS_Duplicate != OwnerStruct->Status.GetValue()); if (bValidStruct) { ChangedStructs.AddUnique(OwnerStruct); StructProperty->Struct = DuplicatedStruct; } } else { UE_LOG(LogK2Compiler, Error, TEXT("ReplaceStructWithTempDuplicate unknown owner")); } } } DuplicatedStruct->RemoveFromRoot(); } }
USCS_Node* USimpleConstructionScript::CreateNodeImpl(UActorComponent* NewComponentTemplate, FName ComponentVariableName) { auto NewNode = NewObject<USCS_Node>(this, MakeUniqueObjectName(this, USCS_Node::StaticClass())); NewNode->SetFlags(RF_Transactional); NewNode->ComponentTemplate = NewComponentTemplate; NewNode->VariableName = ComponentVariableName; // Note: This should match up with UEdGraphSchema_K2::VR_DefaultCategory NewNode->CategoryName = NSLOCTEXT("SCS", "Default", "Default"); NewNode->VariableGuid = FGuid::NewGuid(); return NewNode; }
UObject* FEditorObjectTracker::GetEditorObjectForClass( UClass* EdClass ) { UObject *Obj = (EditorObjMap.Contains(EdClass) ? *EditorObjMap.Find(EdClass) : NULL); if(Obj == NULL) { FString ObjName = MakeUniqueObjectName(GetTransientPackage(), EdClass).ToString(); ObjName += "_EdObj"; Obj = StaticConstructObject(EdClass, GetTransientPackage(), FName(*ObjName), RF_Public|RF_Standalone|RF_Transient); EditorObjMap.Add(EdClass,Obj); } return Obj; }
/** * Helper method to unload loaded blueprints. Use with caution. * * @param BlueprintObj The blueprint to unload * @param bForceFlush If true, will force garbage collection on everything but native objects (defaults to false) */ static void UnloadBlueprint(UBlueprint* const BlueprintObj, bool bForceFlush = false) { // have to grab the blueprint's package before we move it to the transient package UPackage* const OldPackage = Cast<UPackage>(BlueprintObj->GetOutermost()); UPackage* const TransientPackage = GetTransientPackage(); if (OldPackage == TransientPackage) { UE_LOG(LogBlueprintAutomationTests, Log, TEXT("No need to unload '%s' from the transient package."), *BlueprintObj->GetName()); } else if (OldPackage->HasAnyFlags(RF_RootSet) || BlueprintObj->HasAnyFlags(RF_RootSet)) { UE_LOG(LogBlueprintAutomationTests, Error, TEXT("Cannot unload '%s' when its root is set (it will not be garbage collected, leaving it in an erroneous state)."), *OldPackage->GetName()); } else if (OldPackage->IsDirty()) { UE_LOG(LogBlueprintAutomationTests, Error, TEXT("Cannot unload '%s' when it has unsaved changes (save the asset and then try again)."), *OldPackage->GetName()); } else { // prevent users from modifying an open blueprint, after it has been unloaded CloseBlueprint(BlueprintObj); UPackage* NewPackage = TransientPackage; // move the blueprint to the transient package (to be picked up by garbage collection later) FName UnloadedName = MakeUniqueObjectName(NewPackage, UBlueprint::StaticClass(), BlueprintObj->GetFName()); BlueprintObj->Rename(*UnloadedName.ToString(), NewPackage, REN_DontCreateRedirectors|REN_DoNotDirty); // make sure the blueprint is properly trashed so we can rerun tests on it BlueprintObj->SetFlags(RF_Transient); BlueprintObj->ClearFlags(RF_Standalone | RF_RootSet | RF_Transactional); BlueprintObj->RemoveFromRoot(); BlueprintObj->MarkPendingKill(); InvalidatePackage(OldPackage); } // because we just emptied out an existing package, we may want to clean // up garbage so an attempted load doesn't stick us with an invalid asset if (bForceFlush) { #if WITH_EDITOR // clear undo history to ensure that the transaction buffer isn't // holding onto any references to the blueprints we want unloaded GEditor->Trans->Reset(NSLOCTEXT("BpAutomation", "BpAutomationTest", "Blueprint Automation Test")); #endif // #if WITH_EDITOR CollectGarbage(RF_Native); } }
bool UModel::Rename( const TCHAR* InName, UObject* NewOuter, ERenameFlags Flags ) { #if WITH_EDITOR // Also rename the UPolys. if (NewOuter && Polys && Polys->GetOuter() == GetOuter()) { if (Polys->Rename(*MakeUniqueObjectName(NewOuter, Polys->GetClass()).ToString(), NewOuter, Flags) == false) { return false; } } #endif // WITH_EDITOR return Super::Rename( InName, NewOuter, Flags ); }
UWidget* FWidgetTemplateClass::CreateNamed(class UWidgetTree* Tree, FName NameOverride) { if (NameOverride != NAME_None) { UObject* ExistingObject = StaticFindObject(UObject::StaticClass(), Tree, *NameOverride.ToString()); if (ExistingObject != nullptr) { NameOverride = MakeUniqueObjectName(Tree, WidgetClass.Get(), NameOverride); } } UWidget* NewWidget = Tree->ConstructWidget<UWidget>(WidgetClass.Get(), NameOverride); NewWidget->OnCreationFromPalette(); return NewWidget; }
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 UWidgetBlueprint::PostLoad() { Super::PostLoad(); WidgetTree->ForEachWidget([&] (UWidget* Widget) { Widget->ConnectEditorData(); }); if( GetLinkerUE4Version() < VER_UE4_FIXUP_WIDGET_ANIMATION_CLASS ) { // Fixup widget animiations. for( auto& OldAnim : AnimationData_DEPRECATED ) { FName AnimName = OldAnim.MovieScene->GetFName(); // Rename the old movie scene so we can reuse the name OldAnim.MovieScene->Rename( *MakeUniqueObjectName( this, UMovieScene::StaticClass(), "MovieScene").ToString(), nullptr, REN_ForceNoResetLoaders | REN_DontCreateRedirectors | REN_DoNotDirty | REN_NonTransactional); UWidgetAnimation* NewAnimation = NewObject<UWidgetAnimation>(this, AnimName, RF_Transactional); OldAnim.MovieScene->Rename(*AnimName.ToString(), NewAnimation, REN_ForceNoResetLoaders | REN_DontCreateRedirectors | REN_DoNotDirty | REN_NonTransactional ); NewAnimation->MovieScene = OldAnim.MovieScene; NewAnimation->AnimationBindings = OldAnim.AnimationBindings; Animations.Add( NewAnimation ); } AnimationData_DEPRECATED.Empty(); } if ( GetLinkerUE4Version() < VER_UE4_RENAME_WIDGET_VISIBILITY ) { static const FName Visiblity(TEXT("Visiblity")); static const FName Visibility(TEXT("Visibility")); for ( FDelegateEditorBinding& Binding : Bindings ) { if ( Binding.PropertyName == Visiblity ) { Binding.PropertyName = Visibility; } } } }
void UMovieSceneShotTrack::AddNewShot(FGuid CameraHandle, UMovieScene& ShotMovieScene, const TRange<float>& TimeRange, const FText& ShotName, int32 ShotNumber ) { Modify(); FName UniqueShotName = MakeUniqueObjectName( this, UMovieSceneShotSection::StaticClass(), *ShotName.ToString() ); UMovieSceneShotSection* NewSection = NewObject<UMovieSceneShotSection>( this, UniqueShotName, RF_Transactional ); NewSection->SetMovieScene( &ShotMovieScene ); NewSection->SetStartTime( TimeRange.GetLowerBoundValue() ); NewSection->SetEndTime( TimeRange.GetUpperBoundValue() ); NewSection->SetCameraGuid( CameraHandle ); NewSection->SetShotNameAndNumber( ShotName , ShotNumber ); SubMovieSceneSections.Add( NewSection ); // When a new shot is added, sort all shots to ensure they are in the correct order SortShots(); }
void ULevelSequence::PostLoad() { Super::PostLoad(); #if WITH_EDITOR TSet<FGuid> InvalidSpawnables; for (int32 Index = 0; Index < MovieScene->GetSpawnableCount(); ++Index) { FMovieSceneSpawnable& Spawnable = MovieScene->GetSpawnable(Index); if (!Spawnable.GetObjectTemplate()) { if (Spawnable.GeneratedClass_DEPRECATED && Spawnable.GeneratedClass_DEPRECATED->ClassGeneratedBy) { const FName TemplateName = MakeUniqueObjectName(MovieScene, UObject::StaticClass(), Spawnable.GeneratedClass_DEPRECATED->ClassGeneratedBy->GetFName()); UObject* NewTemplate = NewObject<UObject>(MovieScene, Spawnable.GeneratedClass_DEPRECATED, TemplateName); if (NewTemplate) { Spawnable.CopyObjectTemplate(*NewTemplate, *this); } } } if (!Spawnable.GetObjectTemplate()) { InvalidSpawnables.Add(Spawnable.GetGuid()); UE_LOG(LogLevelSequence, Warning, TEXT("Discarding spawnable with ID '%s' since its generated class could not produce to a template actor"), *Spawnable.GetGuid().ToString()); } } for (FGuid& ID : InvalidSpawnables) { MovieScene->RemoveSpawnable(ID); } #endif if ( MovieScene->GetFixedFrameInterval() == 0 ) { MovieScene->SetFixedFrameInterval( 1 / 30.0f ); } }
static void CleanAndSanitizeStruct(UBlueprintGeneratedStruct* StructToClean) { check(StructToClean); const FString TransientString = FString::Printf(TEXT("TRASHSTRUCT_%s"), *StructToClean->GetName()); const FName TransientName = MakeUniqueObjectName(GetTransientPackage(), UBlueprintGeneratedStruct::StaticClass(), FName(*TransientString)); UBlueprintGeneratedStruct* TransientStruct = NewNamedObject<UBlueprintGeneratedStruct>(GetTransientPackage(), TransientName, RF_Public|RF_Transient); const bool bRecompilingOnLoad = StructToClean->StructGeneratedBy ? StructToClean->StructGeneratedBy->bIsRegeneratingOnLoad : false; const ERenameFlags RenFlags = REN_DontCreateRedirectors | (bRecompilingOnLoad ? REN_ForceNoResetLoaders : 0); TArray<UObject*> SubObjects; GetObjectsWithOuter(StructToClean, SubObjects, true); for( auto SubObjIt = SubObjects.CreateIterator(); SubObjIt; ++SubObjIt ) { UObject* CurrSubObj = *SubObjIt; CurrSubObj->Rename(NULL, TransientStruct, RenFlags); if( UProperty* Prop = Cast<UProperty>(CurrSubObj) ) { FKismetCompilerUtilities::InvalidatePropertyExport(Prop); } else { ULinkerLoad::InvalidateExport(CurrSubObj); } } if(!bRecompilingOnLoad) { StructToClean->RemoveMetaData(TEXT("BlueprintType")); } StructToClean->SetSuperStruct(NULL); StructToClean->Children = NULL; StructToClean->Script.Empty(); StructToClean->MinAlignment = 0; StructToClean->RefLink = NULL; StructToClean->PropertyLink = NULL; StructToClean->DestructorLink = NULL; StructToClean->ScriptObjectReferences.Empty(); StructToClean->PropertyLink = NULL; }
static void CleanAndSanitizeStruct(UUserDefinedStruct* StructToClean) { check(StructToClean); if (auto EditorData = Cast<UUserDefinedStructEditorData>(StructToClean->EditorData)) { EditorData->CleanDefaultInstance(); } const FString TransientString = FString::Printf(TEXT("TRASHSTRUCT_%s"), *StructToClean->GetName()); const FName TransientName = MakeUniqueObjectName(GetTransientPackage(), UUserDefinedStruct::StaticClass(), FName(*TransientString)); UUserDefinedStruct* TransientStruct = NewObject<UUserDefinedStruct>(GetTransientPackage(), TransientName, RF_Public | RF_Transient); TArray<UObject*> SubObjects; GetObjectsWithOuter(StructToClean, SubObjects, true); SubObjects.Remove(StructToClean->EditorData); for( auto SubObjIt = SubObjects.CreateIterator(); SubObjIt; ++SubObjIt ) { UObject* CurrSubObj = *SubObjIt; CurrSubObj->Rename(NULL, TransientStruct, REN_DontCreateRedirectors); if( UProperty* Prop = Cast<UProperty>(CurrSubObj) ) { FKismetCompilerUtilities::InvalidatePropertyExport(Prop); } else { FLinkerLoad::InvalidateExport(CurrSubObj); } } StructToClean->SetSuperStruct(NULL); StructToClean->Children = NULL; StructToClean->Script.Empty(); StructToClean->MinAlignment = 0; StructToClean->RefLink = NULL; StructToClean->PropertyLink = NULL; StructToClean->DestructorLink = NULL; StructToClean->ScriptObjectReferences.Empty(); StructToClean->PropertyLink = NULL; StructToClean->ErrorMessage.Empty(); }
FString FMeshProxyTool::GetDefaultPackageName() const { FString PackageName; USelection* SelectedActors = GEditor->GetSelectedActors(); // Iterate through selected actors and find first static mesh asset // Use this static mesh path as destination package name for a merged mesh for (FSelectionIterator Iter(*SelectedActors); Iter; ++Iter) { AActor* Actor = Cast<AActor>(*Iter); if (Actor) { TInlineComponentArray<UStaticMeshComponent*> SMComponets; Actor->GetComponents<UStaticMeshComponent>(SMComponets); for (UStaticMeshComponent* Component : SMComponets) { if (Component->StaticMesh) { PackageName = FPackageName::GetLongPackagePath(Component->StaticMesh->GetOutermost()->GetName()); PackageName += FString(TEXT("/PROXY_")) + Component->StaticMesh->GetName(); break; } } } if (!PackageName.IsEmpty()) { break; } } if (PackageName.IsEmpty()) { PackageName = FPackageName::FilenameToLongPackageName(FPaths::GameContentDir() + TEXT("PROXY")); PackageName = MakeUniqueObjectName(NULL, UPackage::StaticClass(), *PackageName).ToString(); } return PackageName; }
void USceneCapturer::InitCaptureComponent( USceneCaptureComponent2D* CaptureComponent, float HFov, float VFov, EStereoscopicPass InStereoPass ) { CaptureComponent->SetVisibility( true ); CaptureComponent->SetHiddenInGame( false ); CaptureComponent->CaptureStereoPass = InStereoPass; CaptureComponent->FOVAngle = FMath::Max( HFov, VFov ); CaptureComponent->bCaptureEveryFrame = false; CaptureComponent->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR; const FName TargetName = MakeUniqueObjectName(this, UTextureRenderTarget2D::StaticClass(), TEXT("SceneCaptureTextureTarget")); CaptureComponent->TextureTarget = NewObject<UTextureRenderTarget2D>(this, TargetName); //TODO: ikrimae: Not sure why the render target needs to be float to avoid banding. Seems like captures to this RT and then applies PP // on top of it which causes degredation. CaptureComponent->TextureTarget->InitCustomFormat(CaptureWidth, CaptureHeight, PF_A16B16G16R16, false); CaptureComponent->TextureTarget->ClearColor = FLinearColor::Red; CaptureComponent->RegisterComponentWithWorld( GWorld ); // UE4 cannot serialize an array of subobject pointers, so add these objects to the root CaptureComponent->AddToRoot(); }
void UMovieSceneShotTrack::AddNewShot(FGuid CameraHandle, UMovieSceneSequence& ShotMovieSceneSequence, float StartTime, const FText& ShotName, int32 ShotNumber ) { Modify(); FName UniqueShotName = MakeUniqueObjectName( this, UMovieSceneShotSection::StaticClass(), *ShotName.ToString() ); UMovieSceneShotSection* NewSection = NewObject<UMovieSceneShotSection>( this, UniqueShotName, RF_Transactional ); NewSection->SetMovieSceneAnimation( &ShotMovieSceneSequence ); NewSection->SetStartTime( StartTime ); NewSection->SetEndTime( FindEndTimeForShot( StartTime ) ); NewSection->SetCameraGuid( CameraHandle ); NewSection->SetShotNameAndNumber( ShotName , ShotNumber ); SubMovieSceneSections.Add( NewSection ); // When a new shot is added, sort all shots to ensure they are in the correct order SortShots(); // Once shots are sorted fixup the surrounding shots to fix any gaps FixupSurroundingShots( *NewSection, false ); }
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; } }
//* Destroys the constructed components. void AActor::DestroyConstructedComponents() { // Remove all existing components TArray<UActorComponent*> PreviouslyAttachedComponents; GetComponents(PreviouslyAttachedComponents); for (int32 i = 0; i < PreviouslyAttachedComponents.Num(); i++) { UActorComponent*& Component = PreviouslyAttachedComponents[i]; if (Component && Component->bCreatedByConstructionScript) { if (Component == RootComponent) { RootComponent = NULL; } Component->DestroyComponent(); // Rename component to avoid naming conflicts in the case where we rerun the SCS and name the new components the same way. FName const NewBaseName( *(FString::Printf(TEXT("TRASH_%s"), *Component->GetClass()->GetName())) ); FName const NewObjectName = MakeUniqueObjectName(this, GetClass(), NewBaseName); Component->Rename(*NewObjectName.ToString(), this, REN_ForceNoResetLoaders); } } }
static void ReplaceStructWithTempDuplicate( UBlueprintGeneratedStruct* StructureToReinstance, TSet<UBlueprint*>& BlueprintsToRecompile, TArray<UBlueprintGeneratedStruct*>& ChangedStructs) { if (StructureToReinstance) { UBlueprintGeneratedStruct* DuplicatedStruct = NULL; { const FString ReinstancedName = FString::Printf(TEXT("STRUCT_REINST_%s"), *StructureToReinstance->GetName()); const FName UniqueName = MakeUniqueObjectName(GetTransientPackage(), UBlueprintGeneratedStruct::StaticClass(), FName(*ReinstancedName)); const bool OldIsDuplicatingClassForReinstancing = GIsDuplicatingClassForReinstancing; GIsDuplicatingClassForReinstancing = true; DuplicatedStruct = (UBlueprintGeneratedStruct*)StaticDuplicateObject(StructureToReinstance, GetTransientPackage(), *UniqueName.ToString(), ~RF_Transactional); GIsDuplicatingClassForReinstancing = OldIsDuplicatingClassForReinstancing; } DuplicatedStruct->Status = EBlueprintStructureStatus::BSS_Duplicate; DuplicatedStruct->SetFlags(RF_Transient); DuplicatedStruct->AddToRoot(); for (TObjectIterator<UStructProperty> PropertyIter(RF_ClassDefaultObject|RF_PendingKill); PropertyIter; ++PropertyIter) { UStructProperty* StructProperty = *PropertyIter; if (StructProperty && (StructureToReinstance == StructProperty->Struct)) { UBlueprint* FoundBlueprint = NULL; if (auto OwnerClass = Cast<UBlueprintGeneratedClass>(StructProperty->GetOwnerClass())) { FoundBlueprint = Cast<UBlueprint>(OwnerClass->ClassGeneratedBy); } else if (auto OwnerStruct = Cast<UBlueprintGeneratedStruct>(StructProperty->GetOwnerStruct())) { check(OwnerStruct != DuplicatedStruct); const bool bValidStruct = (OwnerStruct->GetOutermost() != GetTransientPackage()) && !OwnerStruct->HasAnyFlags(RF_PendingKill) && (EBlueprintStructureStatus::BSS_Duplicate != OwnerStruct->Status.GetValue()); if (bValidStruct) { FoundBlueprint = OwnerStruct->StructGeneratedBy; ChangedStructs.AddUnique(OwnerStruct); } } else { UE_LOG(LogK2Compiler, Warning, TEXT("ReplaceStructWithTempDuplicate unknown owner")); } if (NULL != FoundBlueprint) { StructProperty->Struct = DuplicatedStruct; BlueprintsToRecompile.Add(FoundBlueprint); } } } DuplicatedStruct->RemoveFromRoot(); } }
void AActor::SetActorLabelInternal( const FString& NewActorLabelDirty, bool bMakeGloballyUniqueFName, bool bMarkDirty ) { // Clean up the incoming string a bit FString NewActorLabel = NewActorLabelDirty; NewActorLabel.Trim(); NewActorLabel.TrimTrailing(); // First, update the actor label { // Has anything changed? if( FCString::Strcmp( *NewActorLabel, *GetActorLabel() ) != 0 ) { // Store new label Modify( bMarkDirty ); ActorLabel = NewActorLabel; } } // Next, update the actor's name { // Generate an object name for the actor's label const FName OldActorName = GetFName(); FName NewActorName = MakeObjectNameFromDisplayLabel( GetActorLabel(), OldActorName ); // Has anything changed? if( OldActorName != NewActorName ) { // Try to rename the object UObject* NewOuter = NULL; // Outer won't be changing ERenameFlags RenFlags = bMakeGloballyUniqueFName ? (REN_DontCreateRedirectors | REN_ForceGlobalUnique) : REN_DontCreateRedirectors; bool bCanRename = Rename( *NewActorName.ToString(), NewOuter, REN_Test | REN_DoNotDirty | REN_NonTransactional | RenFlags ); if( bCanRename ) { // NOTE: Will assert internally if rename fails const bool bWasRenamed = Rename( *NewActorName.ToString(), NewOuter, RenFlags ); } else { // Unable to rename the object. Use a unique object name variant. NewActorName = MakeUniqueObjectName( bMakeGloballyUniqueFName ? ANY_PACKAGE : GetOuter(), GetClass(), NewActorName ); bCanRename = Rename( *NewActorName.ToString(), NewOuter, REN_Test | REN_DoNotDirty | REN_NonTransactional | RenFlags ); if( bCanRename ) { // NOTE: Will assert internally if rename fails const bool bWasRenamed = Rename( *NewActorName.ToString(), NewOuter, RenFlags ); } else { // Unable to rename the object. Oh well, not a big deal. } } } } FPropertyChangedEvent PropertyEvent( FindField<UProperty>( AActor::StaticClass(), "ActorLabel" ) ); PostEditChangeProperty(PropertyEvent); FCoreDelegates::OnActorLabelChanged.Broadcast(this); }
void FHotReloadClassReinstancer::RecreateCDOAndSetupOldClassReinstancing(UClass* InOldClass) { // Set base class members to valid values ClassToReinstance = InOldClass; DuplicatedClass = InOldClass; OriginalCDO = InOldClass->GetDefaultObject(); bHasReinstanced = false; bSkipGarbageCollection = false; bNeedsReinstancing = false; NewClass = InOldClass; // The class doesn't change in this case // Collect the original property values SerializeCDOProperties(InOldClass->GetDefaultObject(), OriginalCDOProperties); // Remember all the basic info about the object before we rename it EObjectFlags CDOFlags = OriginalCDO->GetFlags(); UObject* CDOOuter = OriginalCDO->GetOuter(); FName CDOName = OriginalCDO->GetFName(); // Rename original CDO, so we can store this one as OverridenArchetypeForCDO // and create new one with the same name and outer. OriginalCDO->Rename( *MakeUniqueObjectName( GetTransientPackage(), OriginalCDO->GetClass(), *FString::Printf(TEXT("BPGC_ARCH_FOR_CDO_%s"), *InOldClass->GetName()) ).ToString(), GetTransientPackage(), REN_DoNotDirty | REN_DontCreateRedirectors | REN_NonTransactional | REN_SkipGeneratedClasses | REN_ForceNoResetLoaders); // Re-create the CDO, re-running its constructor ReconstructClassDefaultObject(InOldClass, CDOOuter, CDOName, CDOFlags); ReconstructedCDOsMap.Add(OriginalCDO, InOldClass->GetDefaultObject()); // Collect the property values after re-constructing the CDO SerializeCDOProperties(InOldClass->GetDefaultObject(), ReconstructedCDOProperties); // We only want to re-instance the old class if its CDO's values have changed or any of its DSOs' property values have changed if (DefaultPropertiesHaveChanged()) { bNeedsReinstancing = true; SaveClassFieldMapping(InOldClass); TArray<UClass*> ChildrenOfClass; GetDerivedClasses(InOldClass, ChildrenOfClass); for (auto ClassIt = ChildrenOfClass.CreateConstIterator(); ClassIt; ++ClassIt) { UClass* ChildClass = *ClassIt; UBlueprint* ChildBP = Cast<UBlueprint>(ChildClass->ClassGeneratedBy); if (ChildBP && !ChildBP->HasAnyFlags(RF_BeingRegenerated)) { if (!ChildBP->HasAnyFlags(RF_NeedLoad)) { Children.AddUnique(ChildBP); auto BPGC = Cast<UBlueprintGeneratedClass>(ChildBP->GeneratedClass); auto CurrentCDO = BPGC ? BPGC->GetDefaultObject(false) : nullptr; if (CurrentCDO && (OriginalCDO == CurrentCDO->GetArchetype())) { BPGC->OverridenArchetypeForCDO = OriginalCDO; } } } } } }
FGuid FSequencer::AddSpawnableForAssetOrClass( UObject* Object, UObject* CounterpartGamePreviewObject ) { FGuid NewSpawnableGuid; if( ObjectBindingManager->AllowsSpawnableObjects() ) { // Grab the MovieScene that is currently focused. We'll add our Blueprint as an inner of the // MovieScene asset. UMovieScene* OwnerMovieScene = GetFocusedMovieScene(); // @todo sequencer: Undo doesn't seem to be working at all const FScopedTransaction Transaction( LOCTEXT("UndoAddingObject", "Add Object to MovieScene") ); // Use the class as the spawnable's name if this is an actor class, otherwise just use the object name (asset) const bool bIsActorClass = Object->IsA( AActor::StaticClass() ) && !Object->HasAnyFlags( RF_ArchetypeObject ); const FName AssetName = bIsActorClass ? Object->GetClass()->GetFName() : Object->GetFName(); // Inner objects don't need a name (it will be auto-generated by the UObject system), but we want one in this case // because the class of any actors that are created from this Blueprint may end up being user-facing. const FName BlueprintName = MakeUniqueObjectName( OwnerMovieScene, UBlueprint::StaticClass(), AssetName ); // Use the asset name as the initial spawnable name const FString NewSpawnableName = AssetName.ToString(); // @todo sequencer: Need UI to allow user to rename these slots // Create our new blueprint! UBlueprint* NewBlueprint = NULL; { // @todo sequencer: Add support for forcing specific factories for an asset UActorFactory* FactoryToUse = NULL; if( bIsActorClass ) { // Placing an actor class directly:: FactoryToUse = GEditor->FindActorFactoryForActorClass( Object->GetClass() ); } else { // Placing an asset FactoryToUse = FActorFactoryAssetProxy::GetFactoryForAssetObject( Object ); } if( FactoryToUse != NULL ) { // Create the blueprint NewBlueprint = FactoryToUse->CreateBlueprint( Object, OwnerMovieScene, BlueprintName ); } else if( bIsActorClass ) { // We don't have a factory, but we can still try to create a blueprint for this actor class NewBlueprint = FKismetEditorUtilities::CreateBlueprint( Object->GetClass(), OwnerMovieScene, BlueprintName, EBlueprintType::BPTYPE_Normal, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass() ); } } if( ensure( NewBlueprint != NULL ) ) { if( NewBlueprint->GeneratedClass != NULL && FBlueprintEditorUtils::IsActorBased( NewBlueprint ) ) { AActor* ActorCDO = CastChecked< AActor >( NewBlueprint->GeneratedClass->ClassDefaultObject ); // If we have a counterpart object, then copy the properties from that object back into our blueprint's CDO // @todo sequencer livecapture: This isn't really good enough to handle complex actors. The dynamically-spawned actor could have components that // were created in its construction script or via straight-up C++ code. Instead what we should probably do is duplicate the PIE actor and generate // our CDO from that duplicate. It could get pretty complex though. if( CounterpartGamePreviewObject != NULL ) { AActor* CounterpartGamePreviewActor = CastChecked< AActor >( CounterpartGamePreviewObject ); CopyActorProperties( CounterpartGamePreviewActor, ActorCDO ); } else { // Place the new spawnable in front of the camera (unless we were automatically created from a PIE actor) PlaceActorInFrontOfCamera( ActorCDO ); } } NewSpawnableGuid = OwnerMovieScene->AddSpawnable( NewSpawnableName, NewBlueprint, CounterpartGamePreviewObject ); if (IsShotFilteringOn()) { AddUnfilterableObject(NewSpawnableGuid); } } } return NewSpawnableGuid; }
FBlueprintCompileReinstancer::FBlueprintCompileReinstancer(UClass* InClassToReinstance, bool bIsBytecodeOnly, bool bSkipGC) : ClassToReinstance(InClassToReinstance) , DuplicatedClass(NULL) , OriginalCDO(NULL) , bHasReinstanced(false) , bSkipGarbageCollection(bSkipGC) , ClassToReinstanceDefaultValuesCRC(0) { if( InClassToReinstance != NULL ) { bIsReinstancingSkeleton = FKismetEditorUtilities::IsClassABlueprintSkeleton(ClassToReinstance); SaveClassFieldMapping(InClassToReinstance); // Remember the initial CDO for the class being resinstanced OriginalCDO = ClassToReinstance->GetDefaultObject(); // Duplicate the class we're reinstancing into the transient package. We'll re-class all objects we find to point to this new class GIsDuplicatingClassForReinstancing = true; ClassToReinstance->ClassFlags |= CLASS_NewerVersionExists; const FName RenistanceName = MakeUniqueObjectName(GetTransientPackage(), ClassToReinstance->GetClass(), *FString::Printf(TEXT("REINST_%s"), *ClassToReinstance->GetName())); DuplicatedClass = (UClass*)StaticDuplicateObject(ClassToReinstance, GetTransientPackage(), *RenistanceName.ToString(), ~RF_Transactional); ClassToReinstance->ClassFlags &= ~CLASS_NewerVersionExists; GIsDuplicatingClassForReinstancing = false; auto BPGDuplicatedClass = Cast<UBlueprintGeneratedClass>(DuplicatedClass); auto DuplicatedClassUberGraphFunction = BPGDuplicatedClass ? BPGDuplicatedClass->UberGraphFunction : nullptr; if (DuplicatedClassUberGraphFunction) { DuplicatedClassUberGraphFunction->Bind(); DuplicatedClassUberGraphFunction->StaticLink(true); } // Bind and link the duplicate class, so that it has the proper duplicate property offsets DuplicatedClass->Bind(); DuplicatedClass->StaticLink(true); // Copy over the ComponentNametoDefaultObjectMap, which tells CopyPropertiesForUnrelatedObjects which components are instanced and which aren't GIsDuplicatingClassForReinstancing = true; UObject* OldCDO = ClassToReinstance->GetDefaultObject(); DuplicatedClass->ClassDefaultObject = (UObject*)StaticDuplicateObject(OldCDO, GetTransientPackage(), *DuplicatedClass->GetDefaultObjectName().ToString()); GIsDuplicatingClassForReinstancing = false; DuplicatedClass->ClassDefaultObject->SetFlags(RF_ClassDefaultObject); DuplicatedClass->ClassDefaultObject->SetClass(DuplicatedClass); OldCDO->SetClass(DuplicatedClass); ObjectsThatShouldUseOldStuff.Add(DuplicatedClass); //CDO of REINST_ class can be used as archetype if( !bIsBytecodeOnly ) { TArray<UObject*> ObjectsToChange; const bool bIncludeDerivedClasses = false; GetObjectsOfClass(ClassToReinstance, ObjectsToChange, bIncludeDerivedClasses); for (auto ObjIt = ObjectsToChange.CreateConstIterator(); ObjIt; ++ObjIt) { (*ObjIt)->SetClass(DuplicatedClass); } TArray<UClass*> ChildrenOfClass; GetDerivedClasses(ClassToReinstance, ChildrenOfClass); for ( auto ClassIt = ChildrenOfClass.CreateConstIterator(); ClassIt; ++ClassIt ) { UClass* ChildClass = *ClassIt; UBlueprint* ChildBP = Cast<UBlueprint>(ChildClass->ClassGeneratedBy); if (ChildBP) { const bool bClassIsDirectlyGeneratedByTheBlueprint = (ChildBP->GeneratedClass == ChildClass) || (ChildBP->SkeletonGeneratedClass == ChildClass); if (ChildBP->HasAnyFlags(RF_BeingRegenerated) || !bClassIsDirectlyGeneratedByTheBlueprint) { if (ChildClass->GetSuperClass() == ClassToReinstance) { ReparentChild(ChildClass); } //TODO: some stronger condition would be nice if (!bClassIsDirectlyGeneratedByTheBlueprint) { ObjectsThatShouldUseOldStuff.Add(ChildClass); } } // If this is a direct child, change the parent and relink so the property chain is valid for reinstancing else if( !ChildBP->HasAnyFlags(RF_NeedLoad) ) { if( ChildClass->GetSuperClass() == ClassToReinstance ) { ReparentChild(ChildBP); } Children.AddUnique(ChildBP); } else { // If this is a child that caused the load of their parent, relink to the REINST class so that we can still serialize in the CDO, but do not add to later processing ReparentChild(ChildClass); } } } } // Pull the blueprint that generated this reinstance target, and gather the blueprints that are dependent on it UBlueprint* GeneratingBP = Cast<UBlueprint>(ClassToReinstance->ClassGeneratedBy); check(GeneratingBP || GIsAutomationTesting); if(GeneratingBP) { ClassToReinstanceDefaultValuesCRC = GeneratingBP->CrcPreviousCompiledCDO; FBlueprintEditorUtils::GetDependentBlueprints(GeneratingBP, Dependencies); } } }
void FAmbientSoundDetails::CreateNewSoundCue( ESoundCueLayouts Layout ) { if( AmbientSound.IsValid() ) { OnStopSoundClicked(); AAmbientSound* AS = CastChecked<AAmbientSound>(AmbientSound.Get()); // First if the existing SoundCue is a child of the AmbientSound rename it off to oblivion so we can have a good name USoundCue* SoundCue = Cast<USoundCue>(AmbientSound->GetAudioComponent()->Sound); if (SoundCue && SoundCue->GetOuter() == AS) { SoundCue->Rename(*MakeUniqueObjectName( GetTransientPackage(), USoundCue::StaticClass() ).ToString(), GetTransientPackage(), REN_DontCreateRedirectors); } int32 NodeColumn = 0; USoundNode* PrevNode = NULL; SoundCue = NewObject<USoundCue>(AS, FName(*AS->GetInternalSoundCueName())); AS->GetAudioComponent()->Sound = SoundCue; AS->GetAudioComponent()->PostEditChange(); if (Layout == SOUNDCUE_LAYOUT_RANDOM_LOOP || Layout == SOUNDCUE_LAYOUT_RANDOM_LOOP_WITH_DELAY) { USoundNodeLooping* LoopingNode = SoundCue->ConstructSoundNode<USoundNodeLooping>(); LoopingNode->CreateStartingConnectors(); LoopingNode->PlaceNode(NodeColumn++, 0, 1); if (!PrevNode) { SoundCue->FirstNode = LoopingNode; } else { check(PrevNode->ChildNodes.Num() > 0); PrevNode->ChildNodes[0] = LoopingNode; } PrevNode = LoopingNode; if (Layout == SOUNDCUE_LAYOUT_RANDOM_LOOP_WITH_DELAY) { USoundNodeDelay* DelayNode = SoundCue->ConstructSoundNode<USoundNodeDelay>(); DelayNode->CreateStartingConnectors(); DelayNode->PlaceNode(NodeColumn++,0,1); if (!PrevNode) { SoundCue->FirstNode = DelayNode; } else { check(PrevNode->ChildNodes.Num() > 0); PrevNode->ChildNodes[0] = DelayNode; } PrevNode = DelayNode; } USoundNodeRandom* RandomNode = SoundCue->ConstructSoundNode<USoundNodeRandom>(); RandomNode->CreateStartingConnectors(); RandomNode->PlaceNode(NodeColumn++,0,1); if (!PrevNode) { SoundCue->FirstNode = RandomNode; } else { check(PrevNode->ChildNodes.Num() > 0); PrevNode->ChildNodes[0] = RandomNode; } PrevNode = RandomNode; } else if (Layout == SOUNDCUE_LAYOUT_MIXER) { USoundNodeMixer* MixerNode = SoundCue->ConstructSoundNode<USoundNodeMixer>(); MixerNode->CreateStartingConnectors(); MixerNode->PlaceNode(NodeColumn++,0,1); if (!PrevNode) { SoundCue->FirstNode = MixerNode; } else { check(PrevNode->ChildNodes.Num() > 0); PrevNode->ChildNodes[0] = MixerNode; } PrevNode = MixerNode; } if (PrevNode) { const int32 ChildCount = PrevNode->ChildNodes.Num(); for (int32 ChildIndex = 0; ChildIndex < ChildCount; ++ChildIndex) { USoundNodeWavePlayer* PlayerNode = SoundCue->ConstructSoundNode<USoundNodeWavePlayer>(); PlayerNode->PlaceNode(NodeColumn,ChildIndex,ChildCount); if (Layout == SOUNDCUE_LAYOUT_MIXER) { PlayerNode->bLooping = true; } PrevNode->ChildNodes[ChildIndex] = PlayerNode; } } SoundCue->LinkGraphNodesFromSoundNodes(); FAssetEditorManager::Get().OpenEditorForAsset(SoundCue); } }
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; } }
AActor* UWorld::SpawnActor( UClass* Class, FTransform const* Transform, const FActorSpawnParameters& SpawnParameters ) { SCOPE_CYCLE_COUNTER(STAT_SpawnActorTime); check( CurrentLevel ); check(GIsEditor || (CurrentLevel == PersistentLevel)); // Make sure this class is spawnable. if( !Class ) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because no class was specified") ); return NULL; } if( Class->HasAnyClassFlags(CLASS_Deprecated) ) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because class %s is deprecated"), *Class->GetName() ); return NULL; } if( Class->HasAnyClassFlags(CLASS_Abstract) ) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because class %s is abstract"), *Class->GetName() ); return NULL; } else if( !Class->IsChildOf(AActor::StaticClass()) ) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because %s is not an actor class"), *Class->GetName() ); return NULL; } else if (SpawnParameters.Template != NULL && SpawnParameters.Template->GetClass() != Class) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because template class (%s) does not match spawn class (%s)"), *SpawnParameters.Template->GetClass()->GetName(), *Class->GetName()); if (!SpawnParameters.bNoFail) { return NULL; } } else if (bIsRunningConstructionScript && !SpawnParameters.bAllowDuringConstructionScript) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because we are running a ConstructionScript (%s)"), *Class->GetName() ); return NULL; } else if (bIsTearingDown) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because we are in the process of tearing down the world")); return NULL; } else if (Transform && Transform->ContainsNaN()) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because the given transform (%s) is invalid"), *Transform->ToString()); return NULL; } ULevel* LevelToSpawnIn = SpawnParameters.OverrideLevel; if (LevelToSpawnIn == NULL) { // Spawn in the same level as the owner if we have one. @warning: this relies on the outer of an actor being the level. LevelToSpawnIn = (SpawnParameters.Owner != NULL) ? CastChecked<ULevel>(SpawnParameters.Owner->GetOuter()) : CurrentLevel; } FName NewActorName = SpawnParameters.Name; AActor* Template = SpawnParameters.Template; // Use class's default actor as a template. if( !Template ) { Template = Class->GetDefaultObject<AActor>(); } else if (NewActorName.IsNone() && !Template->HasAnyFlags(RF_ClassDefaultObject)) { NewActorName = MakeUniqueObjectName(LevelToSpawnIn, Template->GetClass(), *Template->GetFName().GetPlainNameString()); } check(Template!=NULL); // See if we can spawn on ded.server/client only etc (check NeedsLoadForClient & NeedsLoadForServer) if(!CanCreateInCurrentContext(Template)) { UE_LOG(LogSpawn, Warning, TEXT("Unable to spawn class '%s' due to client/server context."), *Class->GetName() ); return NULL; } FVector NewLocation = Transform ? Transform->GetLocation() : (Template->GetRootComponent() ? Template->GetRootComponent()->RelativeLocation : FVector::ZeroVector); FRotator NewRotation = Transform ? Transform->GetRotation().Rotator() : (Template->GetRootComponent() ? Template->GetRootComponent()->RelativeRotation : FRotator::ZeroRotator); FVector NewScale = Transform ? Transform->GetScale3D() : (Template->GetRootComponent() ? Template->GetRootComponent()->RelativeScale3D : FVector(1.f) ); PRAGMA_DISABLE_DEPRECATION_WARNINGS; // handle existing (but deprecated) uses of bNoCollisionFail where user set it to true ESpawnActorCollisionHandlingMethod CollisionHandlingOverride = SpawnParameters.SpawnCollisionHandlingOverride; if ((CollisionHandlingOverride == ESpawnActorCollisionHandlingMethod::Undefined) && SpawnParameters.bNoCollisionFail) { CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; } PRAGMA_ENABLE_DEPRECATION_WARNINGS; // "no fail" take preedence over collision handling settings that include fails if (SpawnParameters.bNoFail) { // maybe upgrade to disallow fail if (CollisionHandlingOverride == ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding) { CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; } else if (CollisionHandlingOverride == ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding) { CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; } } // use override if set, else fall back to actor's preference ESpawnActorCollisionHandlingMethod const CollisionHandlingMethod = (CollisionHandlingOverride == ESpawnActorCollisionHandlingMethod::Undefined) ? Template->SpawnCollisionHandlingMethod : CollisionHandlingOverride; // see if we can avoid spawning altogether by checking native components // note: we can't handle all cases here, since we don't know the full component hierarchy until after the actor is spawned if (CollisionHandlingMethod == ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding) { if (EncroachingBlockingGeometry(Template, NewLocation, NewRotation)) { // a native component is colliding, that's enough to reject spawning UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because of collision at the spawn location [%s] for [%s]"), *NewLocation.ToString(), *Class->GetName()); return nullptr; } } // actually make the actor object AActor* const Actor = NewObject<AActor>(LevelToSpawnIn, Class, NewActorName, SpawnParameters.ObjectFlags, Template); check(Actor); #if WITH_EDITOR Actor->ClearActorLabel(); // Clear label on newly spawned actors #endif // WITH_EDITOR if ( GUndo ) { ModifyLevel( LevelToSpawnIn ); } LevelToSpawnIn->Actors.Add( Actor ); // Add this newly spawned actor to the network actor list AddNetworkActor( Actor ); #if PERF_SHOW_MULTI_PAWN_SPAWN_FRAMES if( Cast<APawn>(Actor) ) { FString PawnName = FString::Printf(TEXT("%d: %s"), ThisFramePawnSpawns.Num(), *Actor->GetPathName()); ThisFramePawnSpawns.Add(PawnName); } #endif // tell the actor what method to use, in case it was overridden Actor->SpawnCollisionHandlingMethod = CollisionHandlingMethod; Actor->PostSpawnInitialize(FTransform(NewRotation, NewLocation, NewScale), SpawnParameters.Owner, SpawnParameters.Instigator, SpawnParameters.bRemoteOwned, SpawnParameters.bNoFail, SpawnParameters.bDeferConstruction); if (Actor->IsPendingKill() && !SpawnParameters.bNoFail) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because the spawned actor IsPendingKill")); return NULL; } // // // actor should have all of its components now, do any collision checking and handling that we need to do // switch (CollisionHandlingMethod) // { // case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn: // // Try to find a spawn position // { // FVector AdjustedLocation = NewLocation; // FRotator AdjustedRotation = NewRotation; // if (FindTeleportSpot(Actor, AdjustedLocation, AdjustedRotation)) // { // Actor->SetActorLocationAndRotation(AdjustedLocation, AdjustedRotation); // } // } // break; // case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding: // // Try to find a spawn position // { // FVector AdjustedLocation = NewLocation; // FRotator AdjustedRotation = NewRotation; // if (FindTeleportSpot(Actor, AdjustedLocation, AdjustedRotation)) // { // Actor->SetActorLocationAndRotation(AdjustedLocation, AdjustedRotation); // } // else // { // UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because of collision at the spawn location [%s] for [%s]"), *NewLocation.ToString(), *Class->GetName()); // DestroyActor(Actor); // return nullptr; // } // } // break; // case ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding: // // #todo: don't recheck components checked above? // if (EncroachingBlockingGeometry(Actor, NewLocation, NewRotation)) // { // UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because of collision at the spawn location [%s] for [%s]"), *NewLocation.ToString(), *Class->GetName()); // DestroyActor(Actor); // return nullptr; // } // break; // // note we use "always spawn" as default, so treat undefined as that // case ESpawnActorCollisionHandlingMethod::Undefined: // case ESpawnActorCollisionHandlingMethod::AlwaysSpawn: // default: // // nothing to do, just proceed as normal // break; // } Actor->CheckDefaultSubobjects(); // Broadcast notification of spawn OnActorSpawned.Broadcast(Actor); #if WITH_EDITOR if (GIsEditor) { GEngine->BroadcastLevelActorAdded(Actor); } #endif return Actor; }