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::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()); } } } } }