// Determine whether or not scene components in the new object set can be attached to the given scene root component bool CanAttachComponentsTo(USceneComponent* InRootComponent) { check(InRootComponent); // For each component in the set, check against the given root component and break if we fail to validate bool bCanAttachToRoot = true; for (auto NewComponentIt = NewObjectMap.CreateConstIterator(); NewComponentIt && bCanAttachToRoot; ++NewComponentIt) { // If this is a scene component, and it does not already have a parent within the set USceneComponent* SceneComponent = Cast<USceneComponent>(NewComponentIt->Value); if (SceneComponent != NULL && !ParentMap.Contains(SceneComponent->GetFName())) { // Determine if we are allowed to attach the scene component to the given root component bCanAttachToRoot = InRootComponent->CanAttachAsChild(SceneComponent, NAME_None) && SceneComponent->Mobility >= InRootComponent->Mobility && ( !InRootComponent->IsEditorOnly() || SceneComponent->IsEditorOnly() ); } } return bCanAttachToRoot; }
bool FSCSEditorViewportClient::InputWidgetDelta( FViewport* Viewport, EAxisList::Type CurrentAxis, FVector& Drag, FRotator& Rot, FVector& Scale ) { bool bHandled = false; if(bIsManipulating && CurrentAxis != EAxisList::None) { bHandled = true; AActor* PreviewActor = GetPreviewActor(); auto BlueprintEditor = BlueprintEditorPtr.Pin(); if (PreviewActor && BlueprintEditor.IsValid()) { TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditor->GetSelectedSCSEditorTreeNodes(); if(SelectedNodes.Num() > 0) { FVector ModifiedScale = Scale; if( GEditor->UsePercentageBasedScaling() ) { ModifiedScale = Scale * ((GEditor->GetScaleGridSize() / 100.0f) / GEditor->GetGridSize()); } TSet<USceneComponent*> UpdatedComponents; for(auto It(SelectedNodes.CreateIterator());It;++It) { FSCSEditorTreeNodePtrType SelectedNodePtr = *It; // Don't allow editing of a root node, inherited SCS node or child node that also has a movable (non-root) parent node selected const bool bCanEdit = !SelectedNodePtr->IsRootComponent() && !SelectedNodePtr->IsInherited() && !IsMovableParentNodeSelected(SelectedNodePtr, SelectedNodes); if(bCanEdit) { USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodePtr->FindComponentInstanceInActor(PreviewActor)); USceneComponent* SelectedTemplate = Cast<USceneComponent>(SelectedNodePtr->GetEditableComponentTemplate(BlueprintEditor->GetBlueprintObj())); if(SceneComp != NULL && SelectedTemplate != NULL) { // Cache the current default values for propagation FVector OldRelativeLocation = SelectedTemplate->RelativeLocation; FRotator OldRelativeRotation = SelectedTemplate->RelativeRotation; FVector OldRelativeScale3D = SelectedTemplate->RelativeScale3D; // Adjust the deltas as necessary FComponentEditorUtils::AdjustComponentDelta(SceneComp, Drag, Rot); TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditor->CustomizeSCSEditor(SceneComp); if(Customization.IsValid() && Customization->HandleViewportDrag(SceneComp, SelectedTemplate, Drag, Rot, ModifiedScale, GetWidgetLocation())) { UpdatedComponents.Add(SceneComp); UpdatedComponents.Add(SelectedTemplate); } else { // Apply delta to the preview actor's scene component GEditor->ApplyDeltaToComponent( SceneComp, true, &Drag, &Rot, &ModifiedScale, SceneComp->RelativeLocation ); UpdatedComponents.Add(SceneComp); // Apply delta to the template component object GEditor->ApplyDeltaToComponent( SelectedTemplate, true, &Drag, &Rot, &ModifiedScale, SelectedTemplate->RelativeLocation ); UpdatedComponents.Add(SelectedTemplate); } UBlueprint* PreviewBlueprint = UBlueprint::GetBlueprintFromClass(PreviewActor->GetClass()); if(PreviewBlueprint != NULL) { // Like PostEditMove(), but we only need to re-run construction scripts if(PreviewBlueprint && PreviewBlueprint->bRunConstructionScriptOnDrag) { PreviewActor->RerunConstructionScripts(); } SceneComp->PostEditComponentMove(true); // @TODO HACK passing 'finished' every frame... // If a constraint, copy back updated constraint frames to template UPhysicsConstraintComponent* ConstraintComp = Cast<UPhysicsConstraintComponent>(SceneComp); UPhysicsConstraintComponent* TemplateComp = Cast<UPhysicsConstraintComponent>(SelectedTemplate); if(ConstraintComp && TemplateComp) { TemplateComp->ConstraintInstance.CopyConstraintGeometryFrom(&ConstraintComp->ConstraintInstance); } // Iterate over all the active archetype instances and propagate the change(s) to the matching component instance TArray<UObject*> ArchetypeInstances; if(SelectedTemplate->HasAnyFlags(RF_ArchetypeObject)) { SelectedTemplate->GetArchetypeInstances(ArchetypeInstances); for(int32 InstanceIndex = 0; InstanceIndex < ArchetypeInstances.Num(); ++InstanceIndex) { SceneComp = Cast<USceneComponent>(ArchetypeInstances[InstanceIndex]); if(SceneComp && SceneComp->GetOwner() != PreviewActor) { FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeLocation, OldRelativeLocation, SelectedTemplate->RelativeLocation); FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeRotation, OldRelativeRotation, SelectedTemplate->RelativeRotation); FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeScale3D, OldRelativeScale3D, SelectedTemplate->RelativeScale3D); } } } else if(UObject* Outer = SelectedTemplate->GetOuter()) { Outer->GetArchetypeInstances(ArchetypeInstances); for(int32 InstanceIndex = 0; InstanceIndex < ArchetypeInstances.Num(); ++InstanceIndex) { if(ArchetypeInstances[InstanceIndex] != PreviewActor) { SceneComp = static_cast<USceneComponent*>(FindObjectWithOuter(ArchetypeInstances[InstanceIndex], SelectedTemplate->GetClass(), SelectedTemplate->GetFName())); if(SceneComp) { FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeLocation, OldRelativeLocation, SelectedTemplate->RelativeLocation); FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeRotation, OldRelativeRotation, SelectedTemplate->RelativeRotation); FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeScale3D, OldRelativeScale3D, SelectedTemplate->RelativeScale3D); } } } } } } } } GUnrealEd->RedrawLevelEditingViewports(); } } Invalidate(); } return bHandled; }
void FComponentEditorUtils::CopyComponents(const TArray<UActorComponent*>& ComponentsToCopy) { FStringOutputDevice Archive; const FExportObjectInnerContext Context; // Clear the mark state for saving. UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp)); // Duplicate the selected component templates into temporary objects that we can modify TMap<FName, FName> ParentMap; TMap<FName, UActorComponent*> ObjectMap; for (UActorComponent* Component : ComponentsToCopy) { // Duplicate the component into a temporary object UObject* DuplicatedComponent = StaticDuplicateObject(Component, GetTransientPackage(), Component->GetFName(), RF_AllFlags & ~RF_ArchetypeObject); if (DuplicatedComponent) { // If the duplicated component is a scene component, wipe its attach parent (to prevent log warnings for referencing a private object in an external package) if (auto DuplicatedCompAsSceneComp = Cast<USceneComponent>(DuplicatedComponent)) { DuplicatedCompAsSceneComp->AttachParent = nullptr; } // Find the closest parent component of the current component within the list of components to copy USceneComponent* ClosestSelectedParent = FindClosestParentInList(Component, ComponentsToCopy); if (ClosestSelectedParent) { // If the parent is included in the list, record it into the node->parent map ParentMap.Add(Component->GetFName(), ClosestSelectedParent->GetFName()); } // Record the temporary object into the name->object map ObjectMap.Add(Component->GetFName(), CastChecked<UActorComponent>(DuplicatedComponent)); } } // Export the component object(s) to text for copying for (auto ObjectIt = ObjectMap.CreateIterator(); ObjectIt; ++ObjectIt) { // Get the component object to be copied UActorComponent* ComponentToCopy = ObjectIt->Value; check(ComponentToCopy); // If this component object had a parent within the selected set if (ParentMap.Contains(ComponentToCopy->GetFName())) { // Get the name of the parent component FName ParentName = ParentMap[ComponentToCopy->GetFName()]; if (ObjectMap.Contains(ParentName)) { // Ensure that this component is a scene component USceneComponent* SceneComponent = Cast<USceneComponent>(ComponentToCopy); if (SceneComponent) { // Set the attach parent to the matching parent object in the temporary set. This allows us to preserve hierarchy in the copied set. SceneComponent->AttachParent = Cast<USceneComponent>(ObjectMap[ParentName]); } } } // Export the component object to the given string UExporter::ExportToOutputDevice(&Context, ComponentToCopy, NULL, Archive, TEXT("copy"), 0, PPF_ExportsNotFullyQualified | PPF_Copy | PPF_Delimited, false, ComponentToCopy->GetOuter()); } // Copy text to clipboard FString ExportedText = Archive; FPlatformMisc::ClipboardCopy(*ExportedText); }
USceneComponent* USCS_Node::GetParentComponentTemplate(UBlueprint* InBlueprint) const { USceneComponent* ParentComponentTemplate = NULL; if(ParentComponentOrVariableName != NAME_None) { check(InBlueprint != NULL && InBlueprint->GeneratedClass != NULL); // If the parent component template is found in the 'Components' array of the CDO (i.e. native) if(bIsParentComponentNative) { // Access the Blueprint CDO AActor* CDO = InBlueprint->GeneratedClass->GetDefaultObject<AActor>(); if(CDO != NULL) { // Find the component template in the CDO that matches the specified name TInlineComponentArray<USceneComponent*> Components; CDO->GetComponents(Components); for(auto CompIt = Components.CreateIterator(); CompIt; ++CompIt) { USceneComponent* CompTemplate = *CompIt; if(CompTemplate->GetFName() == ParentComponentOrVariableName) { // Found a match; this is our parent, we're done ParentComponentTemplate = CompTemplate; break; } } } } // Otherwise the parent component template is found in a parent Blueprint's SCS tree (i.e. non-native) else { // Get the Blueprint hierarchy TArray<UBlueprint*> ParentBPStack; UBlueprint::GetBlueprintHierarchyFromClass(InBlueprint->GeneratedClass, ParentBPStack); // Find the parent Blueprint in the hierarchy for(int32 StackIndex = ParentBPStack.Num() - 1; StackIndex > 0; --StackIndex) { UBlueprint* ParentBlueprint = ParentBPStack[StackIndex]; if(ParentBlueprint != NULL && ParentBlueprint->SimpleConstructionScript != NULL && ParentBlueprint->GeneratedClass->GetFName() == ParentComponentOwnerClassName) { // Find the SCS node with a variable name that matches the specified name TArray<USCS_Node*> ParentSCSNodes = ParentBlueprint->SimpleConstructionScript->GetAllNodes(); for(int32 ParentNodeIndex = 0; ParentNodeIndex < ParentSCSNodes.Num(); ++ParentNodeIndex) { USceneComponent* CompTemplate = Cast<USceneComponent>(ParentSCSNodes[ParentNodeIndex]->ComponentTemplate); if(CompTemplate != NULL && ParentSCSNodes[ParentNodeIndex]->VariableName == ParentComponentOrVariableName) { // Found a match; this is our parent, we're done ParentComponentTemplate = CompTemplate; break; } } } } } } return ParentComponentTemplate; }