void USimpleConstructionScript::RemoveNode(USCS_Node* Node) { // If it's a root node we are removing, clear it from the list if(RootNodes.Contains(Node)) { Modify(); RootNodes.Remove(Node); AllNodes.Remove(Node); Node->Modify(); Node->bIsParentComponentNative = false; Node->ParentComponentOrVariableName = NAME_None; Node->ParentComponentOwnerClassName = NAME_None; ValidateSceneRootNodes(); } // Not the root, so iterate over all nodes looking for the one with us in its ChildNodes array else { USCS_Node* ParentNode = FindParentNode(Node); if(ParentNode != NULL) { ParentNode->RemoveChildNode(Node); } } }
void USimpleConstructionScript::RemoveNodeAndPromoteChildren(USCS_Node* Node) { Node->Modify(); if (RootNodes.Contains(Node)) { USCS_Node* ChildToPromote = nullptr; int32 PromoteIndex = FindPromotableChildNodeIndex(Node); if(PromoteIndex != INDEX_NONE) { ChildToPromote = Node->ChildNodes[PromoteIndex]; Node->ChildNodes.RemoveAt(PromoteIndex); } Modify(); if(ChildToPromote != NULL) { ChildToPromote->Modify(); RootNodes.Add(ChildToPromote); ChildToPromote->ChildNodes.Append(Node->ChildNodes); ChildToPromote->bIsParentComponentNative = Node->bIsParentComponentNative; ChildToPromote->ParentComponentOrVariableName = Node->ParentComponentOrVariableName; ChildToPromote->ParentComponentOwnerClassName = Node->ParentComponentOwnerClassName; } RootNodes.Remove(Node); Node->bIsParentComponentNative = false; Node->ParentComponentOrVariableName = NAME_None; Node->ParentComponentOwnerClassName = NAME_None; ValidateSceneRootNodes(); } // Not the root so need to promote in place of node. else { USCS_Node* ParentNode = FindParentNode(Node); checkSlow(ParentNode); ParentNode->Modify(); // remove node and move children onto parent int32 Location = ParentNode->ChildNodes.Find(Node); ParentNode->ChildNodes.Remove(Node); ParentNode->ChildNodes.Insert(Node->ChildNodes, Location); } // Clear out references to previous children Node->ChildNodes.Empty(); }
bool FComponentKey::RefreshVariableName() { if (IsValid() && IsSCSKey()) { USCS_Node* SCSNode = FindSCSNode(); const FName UpdatedName = SCSNode ? SCSNode->GetVariableName() : NAME_None; if (UpdatedName != SCSVariableName) { SCSVariableName = UpdatedName; return true; } } return false; }
TArray<USCS_Node*> USCS_Node::GetAllNodes() { TArray<USCS_Node*> AllNodes; // first add ourself AllNodes.Add(this); // then add each child (including all their children) for(int32 ChildIdx=0; ChildIdx<ChildNodes.Num(); ChildIdx++) { USCS_Node* ChildNode = ChildNodes[ChildIdx]; check(ChildNode != NULL); AllNodes.Append( ChildNode->GetAllNodes() ); } return AllNodes; }
TArray<USCS_Node*> USimpleConstructionScript::GetAllNodes() const { TArray<USCS_Node*> AllNodes; if(RootNodes.Num() > 0) { for(auto NodeIt = RootNodes.CreateConstIterator(); NodeIt; ++NodeIt) { USCS_Node* RootNode = *NodeIt; if(RootNode != NULL) { AllNodes.Append(RootNode->GetAllNodes()); } } } return AllNodes; }
void USCS_Node::PreloadChain() { if( HasAnyFlags(RF_NeedLoad) ) { GetLinker()->Preload(this); } if (ComponentTemplate && ComponentTemplate->HasAnyFlags(RF_NeedLoad)) { ComponentTemplate->GetLinker()->Preload(ComponentTemplate); } for( TArray<USCS_Node*>::TIterator ChildIt(ChildNodes); ChildIt; ++ChildIt ) { USCS_Node* CurrentChild = *ChildIt; if( CurrentChild ) { CurrentChild->PreloadChain(); } } }
void USimpleConstructionScript::ValidateSceneRootNodes() { #if WITH_EDITOR UBlueprint* Blueprint = GetBlueprint(); if(DefaultSceneRootNode == nullptr) { // If applicable, create a default scene component node if(Blueprint != nullptr && FBlueprintEditorUtils::IsActorBased(Blueprint) && Blueprint->BlueprintType != BPTYPE_MacroLibrary) { DefaultSceneRootNode = CreateNode(USceneComponent::StaticClass(), USceneComponent::GetDefaultSceneRootVariableName()); CastChecked<USceneComponent>(DefaultSceneRootNode->ComponentTemplate)->bVisualizeComponent = true; } } if(DefaultSceneRootNode != nullptr) { // Get the current root component template const USceneComponent* RootComponentTemplate = GetSceneRootComponentTemplate(); // Add the default scene root back in if there are no other scene component nodes that can be used as root; otherwise, remove it if(RootComponentTemplate == nullptr && !RootNodes.Contains(DefaultSceneRootNode)) { RootNodes.Add(DefaultSceneRootNode); AllNodes.Add(DefaultSceneRootNode); } else if(RootComponentTemplate != nullptr && RootNodes.Contains(DefaultSceneRootNode)) { // If the default scene root has any child nodes, determine what they should parent to. USCS_Node* RootNode = nullptr; bool bIsParentComponentNative = false; FName ParentComponentOrVariableName = NAME_None; FName ParentComponentOwnerClassName = NAME_None; if(UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(RootComponentTemplate->GetOuter())) { // The root scene component is an SCS node. if(BPClass->SimpleConstructionScript != nullptr) { const TArray<USCS_Node*> SCSRootNodes = BPClass->SimpleConstructionScript->GetRootNodes(); for(USCS_Node* SCSNode : SCSRootNodes) { if(SCSNode != nullptr && SCSNode->ComponentTemplate == RootComponentTemplate) { if(BPClass->SimpleConstructionScript != this) { // The root node is inherited from a parent BP class. ParentComponentOwnerClassName = BPClass->GetFName(); ParentComponentOrVariableName = SCSNode->VariableName; } else { // The root node belongs to the current BP class. RootNode = SCSNode; } break; } } } } else { // The root scene component is a native component. bIsParentComponentNative = true; ParentComponentOrVariableName = RootComponentTemplate->GetFName(); } // Reparent any child nodes within the current hierarchy. for(USCS_Node* ChildNode : DefaultSceneRootNode->ChildNodes) { if(RootNode != nullptr) { // We have an existing root node within the current BP class. RootNode->AddChildNode(ChildNode, false); } else { // The current root node is inherited from a parent class (may be BP or native). RootNodes.Add(ChildNode); ChildNode->bIsParentComponentNative = bIsParentComponentNative; ChildNode->ParentComponentOrVariableName = ParentComponentOrVariableName; ChildNode->ParentComponentOwnerClassName = ParentComponentOwnerClassName; } } // Remove the default scene root node from the current hierarchy. RootNodes.Remove(DefaultSceneRootNode); AllNodes.Remove(DefaultSceneRootNode); DefaultSceneRootNode->ChildNodes.Empty(); // These shouldn't be set, but just in case... DefaultSceneRootNode->bIsParentComponentNative = false; DefaultSceneRootNode->ParentComponentOrVariableName = NAME_None; DefaultSceneRootNode->ParentComponentOwnerClassName = NAME_None; } } #endif // WITH_EDITOR }
void USimpleConstructionScript::RemoveNodeAndPromoteChildren(USCS_Node* Node) { Node->Modify(); if (RootNodes.Contains(Node)) { USCS_Node* ChildToPromote = nullptr; int32 PromoteIndex = FindPromotableChildNodeIndex(Node); if(PromoteIndex != INDEX_NONE) { ChildToPromote = Node->GetChildNodes()[PromoteIndex]; Node->RemoveChildNodeAt(PromoteIndex, false); } Modify(); if(ChildToPromote != NULL) { ChildToPromote->Modify(); RootNodes.Add(ChildToPromote); ChildToPromote->MoveChildNodes(Node); ChildToPromote->bIsParentComponentNative = Node->bIsParentComponentNative; ChildToPromote->ParentComponentOrVariableName = Node->ParentComponentOrVariableName; ChildToPromote->ParentComponentOwnerClassName = Node->ParentComponentOwnerClassName; } RootNodes.Remove(Node); AllNodes.Remove(Node); Node->bIsParentComponentNative = false; Node->ParentComponentOrVariableName = NAME_None; Node->ParentComponentOwnerClassName = NAME_None; ValidateSceneRootNodes(); } // Not the root so need to promote in place of node. else { USCS_Node* ParentNode = FindParentNode(Node); if (!ensure(ParentNode)) { #if WITH_EDITOR UE_LOG(LogBlueprint, Error, TEXT("RemoveNodeAndPromoteChildren(%s) failed to find a parent node in Blueprint %s, attaching children to the root"), *Node->GetName(), *GetBlueprint()->GetPathName()); #endif ParentNode = GetDefaultSceneRootNode(); } check(ParentNode); if (ParentNode != nullptr) { ParentNode->Modify(); // remove node and move children onto parent const int32 Location = ParentNode->GetChildNodes().Find(Node); ParentNode->RemoveChildNode(Node); ParentNode->MoveChildNodes(Node, Location); } } }
void USimpleConstructionScript::ExecuteScriptOnActor(AActor* Actor, const FTransform& RootTransform, bool bIsDefaultTransform) { if(RootNodes.Num() > 0) { TSet<UActorComponent*> AllComponentsCreatedBySCS; TInlineComponentArray<UActorComponent*> InstancedComponents; for(auto NodeIt = RootNodes.CreateIterator(); NodeIt; ++NodeIt) { USCS_Node* RootNode = *NodeIt; if(RootNode != nullptr) { // Get all native scene components TInlineComponentArray<USceneComponent*> Components; Actor->GetComponents(Components); for (int32 Index = Components.Num()-1; Index >= 0; --Index) { USceneComponent* SceneComponent = Components[Index]; if (SceneComponent->CreationMethod == EComponentCreationMethod::Instance) { Components.RemoveAt(Index); } else { // Handle the native sub-component of an instance component case USceneComponent* ParentSceneComponent = SceneComponent->GetTypedOuter<USceneComponent>(); if (ParentSceneComponent && ParentSceneComponent->CreationMethod == EComponentCreationMethod::Instance) { Components.RemoveAt(Index); } } } // Get the native root component; if it's not set, the first native scene component will be used as root. This matches what's done in the SCS editor. USceneComponent* RootComponent = Actor->GetRootComponent(); if(RootComponent == nullptr && Components.Num() > 0) { RootComponent = Components[0]; } // If the root node specifies that it has a parent USceneComponent* ParentComponent = nullptr; if(RootNode->ParentComponentOrVariableName != NAME_None) { // Get the Actor class object UClass* ActorClass = Actor->GetClass(); check(ActorClass != nullptr); // If the root node is parented to a "native" component (i.e. in the 'Components' array) if(RootNode->bIsParentComponentNative) { for(int32 CompIndex = 0; CompIndex < Components.Num(); ++CompIndex) { // If we found a match, remember the index if(Components[CompIndex]->GetFName() == RootNode->ParentComponentOrVariableName) { ParentComponent = Components[CompIndex]; break; } } } else { // In the non-native case, the SCS node's variable name property is used as the parent identifier UObjectPropertyBase* Property = FindField<UObjectPropertyBase>(ActorClass, RootNode->ParentComponentOrVariableName); if(Property != nullptr) { // If we found a matching property, grab its value and use that as the parent for this node ParentComponent = Cast<USceneComponent>(Property->GetObjectPropertyValue_InContainer(Actor)); } } } // Create the new component instance and any child components it may have UActorComponent* InstancedComponent = RootNode->ExecuteNodeOnActor(Actor, ParentComponent != nullptr ? ParentComponent : RootComponent, &RootTransform, bIsDefaultTransform); if(InstancedComponent != nullptr) { InstancedComponents.Add(InstancedComponent); } // get list of every component SCS created, in case some of them aren't in the attachment hierarchy any more (e.g. rigid bodies) TInlineComponentArray<USceneComponent*> ComponentsAfterSCS; Actor->GetComponents(ComponentsAfterSCS); for (USceneComponent* C : ComponentsAfterSCS) { if (Components.Contains(C) == false) { AllComponentsCreatedBySCS.Add(C); } } } } // Register all instanced SCS components once SCS execution has finished; sorted in order to register the scene component hierarchy first, followed by the remaining actor components (in case they happen to depend on something in the scene hierarchy) InstancedComponents.Sort([](const UActorComponent& A, const UActorComponent& B) { return A.IsA<USceneComponent>(); }); for(auto InstancedComponent : InstancedComponents) { RegisterInstancedComponent(InstancedComponent); } // now that the instanced components in the attachment hierarchy are registered, register any other components that SCS made but aren't in the attachment hierarchy for whatever reason. for (auto C : AllComponentsCreatedBySCS) { if (C->IsRegistered() == false) { C->RegisterComponent(); } } } else if(Actor->GetRootComponent() == NULL) // Must have a root component at the end of SCS, so if we don't have one already (from base class), create a SceneComponent now { USceneComponent* SceneComp = NewObject<USceneComponent>(Actor); SceneComp->SetFlags(RF_Transactional); SceneComp->CreationMethod = EComponentCreationMethod::SimpleConstructionScript; SceneComp->SetWorldTransform(RootTransform); Actor->SetRootComponent(SceneComp); SceneComp->RegisterComponent(); } }
void USimpleConstructionScript::FixupRootNodeParentReferences() { // Get the BlueprintGeneratedClass that owns the SCS UClass* BPGeneratedClass = GetOwnerClass(); if(BPGeneratedClass == NULL) { UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::FixupRootNodeParentReferences() - owner class is NULL; skipping.")); // cannot do the rest of fixup without a BPGC return; } for (int32 NodeIndex=0; NodeIndex < RootNodes.Num(); ++NodeIndex) { // If this root node is parented to a native/inherited component template USCS_Node* RootNode = RootNodes[NodeIndex]; if(RootNode->ParentComponentOrVariableName != NAME_None) { bool bWasFound = false; // If the node is parented to a native component if(RootNode->bIsParentComponentNative) { // Get the Blueprint class default object AActor* CDO = Cast<AActor>(BPGeneratedClass->GetDefaultObject(false)); if(CDO != NULL) { // Look for the parent component in the CDO's components array TInlineComponentArray<UActorComponent*> Components; CDO->GetComponents(Components); for (auto CompIter = Components.CreateConstIterator(); CompIter && !bWasFound; ++CompIter) { UActorComponent* ComponentTemplate = *CompIter; bWasFound = ComponentTemplate->GetFName() == RootNode->ParentComponentOrVariableName; } } else { // SCS and BGClass depends on each other (while their construction). // Class is not ready, so one have to break the dependency circle. continue; } } // Otherwise the node is parented to an inherited SCS node from a parent Blueprint else { // Get the Blueprint hierarchy TArray<const UBlueprintGeneratedClass*> ParentBPClassStack; const bool bErrorFree = UBlueprintGeneratedClass::GetGeneratedClassesHierarchy(BPGeneratedClass, ParentBPClassStack); // Find the parent Blueprint in the hierarchy for(int32 StackIndex = ParentBPClassStack.Num() - 1; StackIndex > 0; --StackIndex) { const UBlueprintGeneratedClass* ParentClass = ParentBPClassStack[StackIndex]; if( ParentClass != NULL && ParentClass->SimpleConstructionScript != NULL && ParentClass->GetFName() == RootNode->ParentComponentOwnerClassName) { // Attempt to locate a match by searching all the nodes that belong to the parent Blueprint's SCS for (USCS_Node* ParentNode : ParentClass->SimpleConstructionScript->GetAllNodes()) { if (ParentNode != nullptr && ParentNode->VariableName == RootNode->ParentComponentOrVariableName) { bWasFound = true; break; } } // We found a match; no need to continue searching the hierarchy break; } } } // Clear parent info if we couldn't find the parent component instance if(!bWasFound) { UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::FixupRootNodeParentReferences() - Couldn't find %s parent component '%s' for '%s' in BlueprintGeneratedClass '%s' (it may have been removed)"), RootNode->bIsParentComponentNative ? TEXT("native") : TEXT("inherited"), *RootNode->ParentComponentOrVariableName.ToString(), *RootNode->GetVariableName().ToString(), *BPGeneratedClass->GetName()); RootNode->bIsParentComponentNative = false; RootNode->ParentComponentOrVariableName = NAME_None; RootNode->ParentComponentOwnerClassName = NAME_None; } } } // call this after we do the above ParentComponentOrVariableName fixup, // because this operates differently for root nodes that have their // ParentComponentOrVariableName field cleared // // repairs invalid scene hierarchies (like when this Blueprint has been // reparented and there is no longer an inherited scene root... meaning one // of the scene component nodes here needs to be promoted) FixupSceneNodeHierarchy(); }
void USimpleConstructionScript::FixupSceneNodeHierarchy() { #if WITH_EDITOR // determine the scene's root component, this isn't necessarily a node owned // by this SCS; it could be from a super SCS, or (if SceneRootNode and // SceneRootComponentTemplate is not) it could be a native component USCS_Node* SceneRootNode = nullptr; USceneComponent* SceneRootComponentTemplate = GetSceneRootComponentTemplate(&SceneRootNode); // if there is no scene root (then there shouldn't be anything but the // default placeholder root). if (SceneRootComponentTemplate == nullptr) { return; } bool const bIsSceneRootNative = (SceneRootNode == nullptr); bool const bThisOwnsSceneRoot = !bIsSceneRootNative && RootNodes.Contains(SceneRootNode); // iterate backwards so that we can remove nodes from the array as we go for (int32 NodeIndex = RootNodes.Num() - 1; NodeIndex >= 0; --NodeIndex) { USCS_Node* Node = RootNodes[NodeIndex]; // we only care about the scene component hierarchy (non-scene components // can share root placement) if ((Node->ComponentTemplate == nullptr) || !Node->ComponentTemplate->IsA<USceneComponent>()) { continue; } // if this is the scene's root, then we shouldn't fix it up (instead we // need to be nesting others under this one) if (SceneRootComponentTemplate == Node->ComponentTemplate) { continue; } // if this node has a clear parent already defined, then ignore it (I // imagine that its attachment will be handled elsewhere) if (Node->ParentComponentOrVariableName != NAME_None) { continue; } if (bIsSceneRootNative) { // Parent to the native component template if not already attached Node->SetParent(SceneRootComponentTemplate); } else if (bThisOwnsSceneRoot) { // Reparent to this BP's root node if it's still in the root set RootNodes.Remove(Node); SceneRootNode->AddChildNode(Node, false); } else { // Parent to an inherited parent BP's node if not already attached Node->SetParent(SceneRootNode); } } #endif // #if WITH_EDITOR }
void USimpleConstructionScript::PostLoad() { Super::PostLoad(); #if WITH_EDITOR // Get the Blueprint that owns the SCS UBlueprint* Blueprint = GetBlueprint(); if (!Blueprint) { // sometimes the PostLoad can be called, after the object was trashed, we dont want this UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::PostLoad() '%s' cannot find its owner blueprint"), *GetPathName()); return; } for (USCS_Node* Node : GetAllNodes()) { // Fix up any uninitialized category names if(Node->CategoryName.IsEmpty()) { Node->CategoryName = NSLOCTEXT("SCS", "Default", "Default"); } // Fix up components that may have switched from scene to non-scene type and vice-versa if(Node->ComponentTemplate != nullptr) { // Fix up any component template objects whose name doesn't match the current variable name; this ensures that there is always one unique template per node. FString VariableName = Node->GetVariableName().ToString(); FString ComponentTemplateName = Node->ComponentTemplate->GetName(); if(ComponentTemplateName.EndsWith(UActorComponent::ComponentTemplateNameSuffix) && !ComponentTemplateName.StartsWith(VariableName) && !GIsDuplicatingClassForReinstancing) { Node->ComponentTemplate->ConditionalPostLoad(); Node->ComponentTemplate = static_cast<UActorComponent*>(StaticDuplicateObject(Node->ComponentTemplate, Node->ComponentTemplate->GetOuter(), *(VariableName + UActorComponent::ComponentTemplateNameSuffix))); } // Check to see if switched from scene to a non-scene component type if (!Node->ComponentTemplate->IsA<USceneComponent>()) { // Otherwise, check to see if switched from scene to non-scene component type int32 RootNodeIndex = INDEX_NONE; if(!RootNodes.Find(Node, RootNodeIndex)) { // Move the node into the root set if it's currently in the scene hierarchy USCS_Node* ParentNode = FindParentNode(Node); if(ParentNode != nullptr) { ParentNode->RemoveChildNode(Node); } RootNodes.Add(Node); } else { // Otherwise, if it's a root node, promote one of its children (if any) to take its place int32 PromoteIndex = FindPromotableChildNodeIndex(Node); if(PromoteIndex != INDEX_NONE) { // Remove it as a child node USCS_Node* ChildToPromote = Node->GetChildNodes()[PromoteIndex]; Node->RemoveChildNodeAt(PromoteIndex, false); // Insert it as a root node just before its prior parent node; this way if it switches back to a scene type it won't supplant the new root we've just created RootNodes.Insert(ChildToPromote, RootNodeIndex); // Append previous root node's children to the new root ChildToPromote->MoveChildNodes(Node); // Copy any previous external attachment info from the previous root node ChildToPromote->bIsParentComponentNative = Node->bIsParentComponentNative; ChildToPromote->ParentComponentOrVariableName = Node->ParentComponentOrVariableName; ChildToPromote->ParentComponentOwnerClassName = Node->ParentComponentOwnerClassName; } // Clear info for any previous external attachment if set if(Node->ParentComponentOrVariableName != NAME_None) { Node->bIsParentComponentNative = false; Node->ParentComponentOrVariableName = NAME_None; Node->ParentComponentOwnerClassName = NAME_None; } } } } } #endif // WITH_EDITOR // Fix up native/inherited parent attachments, in case anything has changed FixupRootNodeParentReferences(); // Ensure that we have a valid scene root ValidateSceneRootNodes(); // Reset non-native "root" scene component scale values, prior to the change in which // we began applying custom scale values to root components at construction time. This // way older, existing Blueprint actor instances won't start unexpectedly getting scaled. if(GetLinkerUE4Version() < VER_UE4_BLUEPRINT_USE_SCS_ROOTCOMPONENT_SCALE) { // Get the BlueprintGeneratedClass that owns the SCS UClass* BPGeneratedClass = GetOwnerClass(); if(BPGeneratedClass != nullptr) { // Get the Blueprint class default object AActor* CDO = Cast<AActor>(BPGeneratedClass->GetDefaultObject(false)); if(CDO != NULL) { // Check for a native root component USceneComponent* NativeRootComponent = CDO->GetRootComponent(); if(NativeRootComponent == nullptr) { // If no native root component exists, find the first non-native, non-parented SCS node with a // scene component template. This will be designated as the root component at construction time. for (USCS_Node* Node : RootNodes) { if(Node->ParentComponentOrVariableName == NAME_None) { // Note that we have to check for nullptr here, because it may be an ActorComponent type USceneComponent* SceneComponentTemplate = Cast<USceneComponent>(Node->ComponentTemplate); if(SceneComponentTemplate != nullptr && SceneComponentTemplate->RelativeScale3D != FVector(1.0f, 1.0f, 1.0f)) { UE_LOG(LogBlueprint, Warning, TEXT("%s: Found non-native root component custom scale for %s (%s) saved prior to being usable; reverting to default scale."), *BPGeneratedClass->GetName(), *Node->GetVariableName().ToString(), *SceneComponentTemplate->RelativeScale3D.ToString()); SceneComponentTemplate->RelativeScale3D = FVector(1.0f, 1.0f, 1.0f); } // Done - no need to fix up any other nodes. break; } } } } } } if (GetLinkerUE4Version() < VER_UE4_SCS_STORES_ALLNODES_ARRAY) { // Fill out AllNodes if this is an older object if (RootNodes.Num() > 0) { AllNodes.Reset(); for (USCS_Node* RootNode : RootNodes) { if (RootNode != nullptr) { AllNodes.Append(RootNode->GetAllNodes()); } } } } }
UActorComponent* USCS_Node::ExecuteNodeOnActor(AActor* Actor, USceneComponent* ParentComponent, const FTransform* RootTransform, bool bIsDefaultTransform) { check(Actor != nullptr); check((ParentComponent != nullptr && !ParentComponent->IsPendingKill()) || (RootTransform != nullptr)); // must specify either a parent component or a world transform auto ActualBPGC = Cast<UBlueprintGeneratedClass>(Actor->GetClass()); UActorComponent* ActualComponentTemplate = GetActualComponentTemplate(ActualBPGC); // Create a new component instance based on the template UActorComponent* NewActorComp = Actor->CreateComponentFromTemplate(ActualComponentTemplate, VariableName.ToString()); if(NewActorComp != nullptr) { NewActorComp->CreationMethod = EComponentCreationMethod::SimpleConstructionScript; // SCS created components are net addressable NewActorComp->SetNetAddressable(); // Special handling for scene components USceneComponent* NewSceneComp = Cast<USceneComponent>(NewActorComp); if (NewSceneComp != nullptr) { // If NULL is passed in, we are the root, so set transform and assign as RootComponent on Actor if (ParentComponent == nullptr || (ParentComponent && ParentComponent->IsPendingKill())) { FTransform WorldTransform = *RootTransform; if(bIsDefaultTransform) { // Note: We use the scale vector from the component template when spawning (to match what happens with a native root) WorldTransform.SetScale3D(NewSceneComp->RelativeScale3D); } NewSceneComp->SetWorldTransform(WorldTransform); Actor->SetRootComponent(NewSceneComp); } // Otherwise, attach to parent component passed in else { NewSceneComp->AttachTo(ParentComponent, AttachToName); } } // Call function to notify component it has been created NewActorComp->OnComponentCreated(); if (NewActorComp->GetIsReplicated()) { // Make sure this component is added to owning actor's replicated list. NewActorComp->SetIsReplicated(true); } // If we want to save this to a property, do it here FName VarName = GetVariableName(); if (VarName != NAME_None) { UClass* ActorClass = Actor->GetClass(); if (UObjectPropertyBase* Prop = FindField<UObjectPropertyBase>(ActorClass, VarName)) { Prop->SetObjectPropertyValue_InContainer(Actor, NewActorComp); } else { UE_LOG(LogBlueprint, Log, TEXT("ExecuteNodeOnActor: Couldn't find property '%s' on '%s"), *VarName.ToString(), *Actor->GetName()); #if WITH_EDITOR // If we're constructing editable components in the SCS editor, set the component instance corresponding to this node for editing purposes USimpleConstructionScript* SCS = GetSCS(); if(SCS != nullptr && (SCS->IsConstructingEditorComponents() || SCS->GetComponentEditorActorInstance() == Actor)) { EditorComponentInstance = NewSceneComp; } #endif } } // Determine the parent component for our children (it's still our parent if we're a non-scene component) USceneComponent* ParentSceneComponentOfChildren = (NewSceneComp != nullptr) ? NewSceneComp : ParentComponent; // If we made a component, go ahead and process our children for (int32 NodeIdx = 0; NodeIdx < ChildNodes.Num(); NodeIdx++) { USCS_Node* Node = ChildNodes[NodeIdx]; check(Node != nullptr); Node->ExecuteNodeOnActor(Actor, ParentSceneComponentOfChildren, nullptr, false); } } return NewActorComp; }
void USimpleConstructionScript::Serialize(FArchive& Ar) { Super::Serialize(Ar); if(Ar.IsLoading()) { int32 NodeIndex; if(Ar.UE4Ver() < VER_UE4_REMOVE_NATIVE_COMPONENTS_FROM_BLUEPRINT_SCS) { // If we previously had a root node, we need to move it into the new RootNodes array. This is done in Serialize() in order to support SCS preloading (which relies on a valid RootNodes array). if(RootNode_DEPRECATED != NULL) { // Ensure it's been loaded so that its properties are valid if(RootNode_DEPRECATED->HasAnyFlags(RF_NeedLoad)) { RootNode_DEPRECATED->GetLinker()->Preload(RootNode_DEPRECATED); } // If the root node was not native if(!RootNode_DEPRECATED->bIsNative_DEPRECATED) { // Add the node to the root set RootNodes.Add(RootNode_DEPRECATED); } else { // For each child of the previously-native root node for (NodeIndex=0; NodeIndex < RootNode_DEPRECATED->ChildNodes.Num(); ++NodeIndex) { USCS_Node* Node = RootNode_DEPRECATED->ChildNodes[NodeIndex]; if(Node != NULL) { // Ensure it's been loaded (may not have been yet if we're preloading the SCS) if(Node->HasAnyFlags(RF_NeedLoad)) { Node->GetLinker()->Preload(Node); } // We only care about non-native child nodes (non-native nodes could only be attached to the root node in the previous version, so we don't need to examine native child nodes) if(!Node->bIsNative_DEPRECATED) { // Add the node to the root set RootNodes.Add(Node); // Set the previously-native root node as its parent component Node->bIsParentComponentNative = true; Node->ParentComponentOrVariableName = RootNode_DEPRECATED->NativeComponentName_DEPRECATED; } } } } // Clear the deprecated reference RootNode_DEPRECATED = NULL; } // Add any user-defined actor components to the root set for(NodeIndex = 0; NodeIndex < ActorComponentNodes_DEPRECATED.Num(); ++NodeIndex) { USCS_Node* Node = ActorComponentNodes_DEPRECATED[NodeIndex]; if(Node != NULL) { // Ensure it's been loaded (may not have been yet if we're preloading the SCS) if(Node->HasAnyFlags(RF_NeedLoad)) { Node->GetLinker()->Preload(Node); } if(!Node->bIsNative_DEPRECATED) { RootNodes.Add(Node); } } } // Clear the deprecated ActorComponent list ActorComponentNodes_DEPRECATED.Empty(); } } }