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);
		}
	}
}
Esempio n. 2
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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());
				}
			}
		}
	}
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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();
		}
	}
}