void AActor::ExecuteConstruction(const FTransform& Transform, const FComponentInstanceDataCache* InstanceDataCache, bool bIsDefaultTransform) { check(!IsPendingKill()); check(!HasAnyFlags(RF_BeginDestroyed|RF_FinishDestroyed)); // ensure that any existing native root component gets this new transform // we can skip this in the default case as the given transform will be the root component's transform if (RootComponent && !bIsDefaultTransform) { RootComponent->SetWorldTransform(Transform); } // Generate the parent blueprint hierarchy for this actor, so we can run all the construction scripts sequentially TArray<const UBlueprintGeneratedClass*> ParentBPClassStack; const bool bErrorFree = UBlueprintGeneratedClass::GetGeneratedClassesHierarchy(GetClass(), ParentBPClassStack); // If this actor has a blueprint lineage, go ahead and run the construction scripts from least derived to most if( (ParentBPClassStack.Num() > 0) ) { if( bErrorFree ) { // Prevent user from spawning actors in User Construction Script TGuardValue<bool> AutoRestoreISCS(GetWorld()->bIsRunningConstructionScript, true); for( int32 i = ParentBPClassStack.Num() - 1; i >= 0; i-- ) { const UBlueprintGeneratedClass* CurrentBPGClass = ParentBPClassStack[i]; check(CurrentBPGClass); if(CurrentBPGClass->SimpleConstructionScript) { CurrentBPGClass->SimpleConstructionScript->ExecuteScriptOnActor(this, Transform, bIsDefaultTransform); } // Now that the construction scripts have been run, we can create timelines and hook them up CurrentBPGClass->CreateComponentsForActor(this); } // If we passed in cached data, we apply it now, so that the UserConstructionScript can use the updated values if(InstanceDataCache) { InstanceDataCache->ApplyToActor(this, ECacheApplyPhase::PostSimpleConstructionScript); } #if WITH_EDITOR bool bDoUserConstructionScript; GConfig->GetBool(TEXT("Kismet"), TEXT("bTurnOffEditorConstructionScript"), bDoUserConstructionScript, GEngineIni); if (!GIsEditor || !bDoUserConstructionScript) #endif { // Then run the user script, which is responsible for calling its own super, if desired ProcessUserConstructionScript(); } // Since re-run construction scripts will never be run and we want to keep dynamic spawning fast, don't spend time // determining the UCS modified properties in game worlds if (!GetWorld()->IsGameWorld()) { for (UActorComponent* Component : GetComponents()) { if (Component) { Component->DetermineUCSModifiedProperties(); } } } // Bind any delegates on components ((UBlueprintGeneratedClass*)GetClass())->BindDynamicDelegates(this); // We have a BP stack, we must have a UBlueprintGeneratedClass... // Apply any cached data procedural components // @TODO Don't re-apply to components we already applied to above if (InstanceDataCache) { InstanceDataCache->ApplyToActor(this, ECacheApplyPhase::PostUserConstructionScript); } } else { // Disaster recovery mode; create a dummy billboard component to retain the actor location // until the compile error can be fixed if (RootComponent == NULL) { UBillboardComponent* BillboardComponent = NewObject<UBillboardComponent>(this); BillboardComponent->SetFlags(RF_Transactional); BillboardComponent->CreationMethod = EComponentCreationMethod::SimpleConstructionScript; #if WITH_EDITOR BillboardComponent->Sprite = (UTexture2D*)(StaticLoadObject(UTexture2D::StaticClass(), NULL, TEXT("/Engine/EditorResources/BadBlueprintSprite.BadBlueprintSprite"), NULL, LOAD_None, NULL)); #endif BillboardComponent->SetRelativeTransform(Transform); SetRootComponent(BillboardComponent); FinishAndRegisterComponent(BillboardComponent); } } } GetWorld()->UpdateCullDistanceVolumes(this); // Now run virtual notification OnConstruction(Transform); }
void AActor::OnConstruction(const FTransform& Transform) { check(!IsPendingKill()); check(!HasAnyFlags(RF_BeginDestroyed|RF_FinishDestroyed)); // Generate the parent blueprint hierarchy for this actor, so we can run all the construction scripts sequentially TArray<const UBlueprintGeneratedClass*> ParentBPClassStack; const bool bErrorFree = UBlueprintGeneratedClass::GetGeneratedClassesHierarchy(GetClass(), ParentBPClassStack); // If this actor has a blueprint lineage, go ahead and run the construction scripts from least derived to most if( (ParentBPClassStack.Num() > 0) ) { if( bErrorFree ) { FEditorScriptExecutionGuard ScriptGuard; // Prevent user from spawning actors in User Construction Script TGuardValue<bool> AutoRestoreISCS(GetWorld()->bIsRunningConstructionScript, true); for( int32 i = ParentBPClassStack.Num() - 1; i >= 0; i-- ) { const UBlueprintGeneratedClass* CurrentBPGClass = ParentBPClassStack[i]; check(CurrentBPGClass); if(CurrentBPGClass->SimpleConstructionScript) { CurrentBPGClass->SimpleConstructionScript->ExecuteScriptOnActor(this, Transform); } // Now that the construction scripts have been run, we can create timelines and hook them up CurrentBPGClass->CreateTimelinesForActor(this); } #if WITH_EDITOR bool bDoUserConstructionScript; GConfig->GetBool(TEXT("Kismet"), TEXT("bTurnOffEditorConstructionScript"), bDoUserConstructionScript, GEngineIni); if (!GIsEditor || !bDoUserConstructionScript) #endif { // Then run the user script, which is responsible for calling its own super, if desired ProcessUserConstructionScript(); } // Bind any delegates on components ((UBlueprintGeneratedClass*)GetClass())->BindDynamicDelegates(this); // We have a BP stack, we must have a UBlueprintGeneratedClass... } else { // Disaster recovery mode; create a dummy billboard component to retain the actor location // until the compile error can be fixed if (RootComponent == NULL) { UBillboardComponent* BillboardComponent = NewObject<UBillboardComponent>(this); BillboardComponent->SetFlags(RF_Transactional); BillboardComponent->bCreatedByConstructionScript = true; #if WITH_EDITOR BillboardComponent->Sprite = (UTexture2D*)(StaticLoadObject(UTexture2D::StaticClass(), NULL, TEXT("/Engine/EditorResources/BadBlueprintSprite.BadBlueprintSprite"), NULL, LOAD_None, NULL)); #endif BillboardComponent->SetRelativeTransform(Transform); SetRootComponent(BillboardComponent); FinishAndRegisterComponent(BillboardComponent); } } } }