void UChildActorComponent::OnRegister() { Super::OnRegister(); if (ChildActor) { if (ChildActor->GetClass() != ChildActorClass) { DestroyChildActor(); CreateChildActor(); } else { ChildActorName = ChildActor->GetFName(); USceneComponent* ChildRoot = ChildActor->GetRootComponent(); if (ChildRoot && ChildRoot->GetAttachParent() != this) { // attach new actor to this component // we can't attach in CreateChildActor since it has intermediate Mobility set up // causing spam with inconsistent mobility set up // so moving Attach to happen in Register ChildRoot->AttachTo(this, NAME_None, EAttachLocation::SnapToTarget); } } } else if (ChildActorClass) { CreateChildActor(); } }
void UChildActorComponent::OnRegister() { Super::OnRegister(); if (ChildActor) { if (ChildActor->GetClass() != ChildActorClass) { DestroyChildActor(); CreateChildActor(); } else { ChildActorName = ChildActor->GetFName(); USceneComponent* ChildRoot = ChildActor->GetRootComponent(); if (ChildRoot && ChildRoot->GetAttachParent() != this) { // attach new actor to this component // we can't attach in CreateChildActor since it has intermediate Mobility set up // causing spam with inconsistent mobility set up // so moving Attach to happen in Register ChildRoot->AttachToComponent(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale); } // Ensure the components replication is correctly initialized SetIsReplicated(ChildActor->GetIsReplicated()); } } else if (ChildActorClass) { CreateChildActor(); } }
USceneComponent* FComponentEditorUtils::FindClosestParentInList(UActorComponent* ChildComponent, const TArray<UActorComponent*>& ComponentList) { USceneComponent* ClosestParentComponent = nullptr; for (auto Component : ComponentList) { auto ChildAsScene = Cast<USceneComponent>(ChildComponent); auto SceneComponent = Cast<USceneComponent>(Component); if (ChildAsScene && SceneComponent) { // Check to see if any parent is also in the list USceneComponent* Parent = ChildAsScene->GetAttachParent(); while (Parent != nullptr) { if (ComponentList.Contains(Parent)) { ClosestParentComponent = SceneComponent; break; } Parent = Parent->GetAttachParent(); } } } return ClosestParentComponent; }
FTransform FMovieScene3DTransformSectionRecorder::GetTransformToRecord() { if(USceneComponent* SceneComponent = Cast<USceneComponent>(ObjectToRecord.Get())) { return SceneComponent->GetRelativeTransform(); } else if(AActor* Actor = Cast<AActor>(ObjectToRecord.Get())) { bool bCaptureWorldSpaceTransform = false; USceneComponent* RootComponent = Actor->GetRootComponent(); USceneComponent* AttachParent = RootComponent ? RootComponent->GetAttachParent() : nullptr; bWasAttached = AttachParent != nullptr; if (AttachParent) { // We capture world space transforms for actors if they're attached, but we're not recording the attachment parent bCaptureWorldSpaceTransform = !FSequenceRecorder::Get().FindRecording(AttachParent->GetOwner()); } return (bCaptureWorldSpaceTransform || !RootComponent) ? Actor->ActorToWorld() : RootComponent->GetRelativeTransform(); } return FTransform::Identity; }
UActorComponent* FComponentEditorUtils::DuplicateComponent(UActorComponent* TemplateComponent) { check(TemplateComponent); UActorComponent* NewCloneComponent = nullptr; AActor* Actor = TemplateComponent->GetOwner(); if (!TemplateComponent->IsEditorOnly() && Actor) { Actor->Modify(); UClass* ComponentClass = TemplateComponent->GetClass(); FName NewComponentName = *FComponentEditorUtils::GenerateValidVariableName(ComponentClass, Actor); bool bKeepWorldLocationOnAttach = false; const bool bTemplateTransactional = TemplateComponent->HasAllFlags(RF_Transactional); TemplateComponent->SetFlags(RF_Transactional); NewCloneComponent = DuplicateObject<UActorComponent>(TemplateComponent, Actor, NewComponentName ); if (!bTemplateTransactional) { TemplateComponent->ClearFlags(RF_Transactional); } USceneComponent* NewSceneComponent = Cast<USceneComponent>(NewCloneComponent); if (NewSceneComponent) { // Ensure the clone doesn't think it has children NewSceneComponent->AttachChildren.Empty(); // If the clone is a scene component without an attach parent, attach it to the root (can happen when duplicating the root component) if (!NewSceneComponent->GetAttachParent()) { USceneComponent* RootComponent = Actor->GetRootComponent(); check(RootComponent); // ComponentToWorld is not a UPROPERTY, so make sure the clone has calculated it properly before attachment NewSceneComponent->UpdateComponentToWorld(); NewSceneComponent->AttachTo(RootComponent, NAME_None, EAttachLocation::KeepWorldPosition); } } NewCloneComponent->OnComponentCreated(); // Add to SerializedComponents array so it gets saved Actor->AddInstanceComponent(NewCloneComponent); // Register the new component NewCloneComponent->RegisterComponent(); // Rerun construction scripts Actor->RerunConstructionScripts(); } return NewCloneComponent; }
int32 GetAttachmentDepth(USceneComponent* Component) { int32 Depth = 0; USceneComponent* Parent = Component->GetAttachParent(); while (Parent) { ++Depth; Parent = Parent->GetAttachParent(); } return Depth; }
AActor::FActorTransactionAnnotation::FActorTransactionAnnotation(const AActor* Actor, const bool bCacheRootComponentData) : ComponentInstanceData(Actor) { USceneComponent* ActorRootComponent = Actor->GetRootComponent(); if (bCacheRootComponentData && ActorRootComponent && ActorRootComponent->IsCreatedByConstructionScript()) { bRootComponentDataCached = true; RootComponentData.Transform = ActorRootComponent->ComponentToWorld; RootComponentData.Transform.SetTranslation(ActorRootComponent->GetComponentLocation()); // take into account any custom location if (ActorRootComponent->GetAttachParent()) { RootComponentData.AttachedParentInfo.Actor = ActorRootComponent->GetAttachParent()->GetOwner(); RootComponentData.AttachedParentInfo.AttachParent = ActorRootComponent->GetAttachParent(); RootComponentData.AttachedParentInfo.AttachParentName = ActorRootComponent->GetAttachParent()->GetFName(); RootComponentData.AttachedParentInfo.SocketName = ActorRootComponent->GetAttachSocketName(); RootComponentData.AttachedParentInfo.RelativeTransform = ActorRootComponent->GetRelativeTransform(); } for (USceneComponent* AttachChild : ActorRootComponent->GetAttachChildren()) { AActor* ChildOwner = (AttachChild ? AttachChild->GetOwner() : NULL); if (ChildOwner && ChildOwner != Actor) { // Save info about actor to reattach FActorRootComponentReconstructionData::FAttachedActorInfo Info; Info.Actor = ChildOwner; Info.SocketName = AttachChild->GetAttachSocketName(); Info.RelativeTransform = AttachChild->GetRelativeTransform(); RootComponentData.AttachedToInfo.Add(Info); } } } else { bRootComponentDataCached = false; } }
void UActorRecording::ProcessNewComponentArray(TInlineComponentArray<USceneComponent*>& ProspectiveComponents) const { // Only iterate as far as the current size of the array (it may grow inside the loop) int32 LastIndex = ProspectiveComponents.Num(); for(int32 Index = 0; Index < LastIndex; ++Index) { USceneComponent* NewComponent = ProspectiveComponents[Index]; USceneComponent* Parent = ProspectiveComponents[Index]->GetAttachParent(); while (Parent) { TWeakObjectPtr<USceneComponent> WeakParent(Parent); if (TrackedComponents.Contains(WeakParent) || ProspectiveComponents.Contains(Parent) || Parent->GetOwner() != NewComponent->GetOwner()) { break; } else { ProspectiveComponents.Add(Parent); } Parent = Parent->GetAttachParent(); } } // Sort parent first, to ensure that attachments get added properly TMap<USceneComponent*, int32> AttachmentDepths; for (USceneComponent* Component : ProspectiveComponents) { AttachmentDepths.Add(Component, GetAttachmentDepth(Component)); } ProspectiveComponents.Sort( [&](USceneComponent& A, USceneComponent& B) { return *AttachmentDepths.Find(&A) < *AttachmentDepths.Find(&B); } ); }
void FPreviewScene::AddComponent(UActorComponent* Component,const FTransform& LocalToWorld) { Components.AddUnique(Component); USceneComponent* SceneComp = Cast<USceneComponent>(Component); if(SceneComp && SceneComp->GetAttachParent() == NULL) { SceneComp->SetRelativeTransform(LocalToWorld); } Component->RegisterComponentWithWorld(GetWorld()); if (bForceAllUsedMipsResident) { // Add a mip streaming override to the new mesh UMeshComponent* pMesh = Cast<UMeshComponent>(Component); if (pMesh != NULL) { pMesh->SetTextureForceResidentFlag(true); } } GetScene()->UpdateSpeedTreeWind(0.0); }
void FEmitDefaultValueHelper::GenerateConstructor(FEmitterLocalContext& Context) { GenerateCustomDynamicClassInitialization(Context); auto BPGC = CastChecked<UBlueprintGeneratedClass>(Context.GetCurrentlyGeneratedClass()); const FString CppClassName = FEmitHelper::GetCppName(BPGC); UClass* SuperClass = BPGC->GetSuperClass(); const bool bSuperHasOnlyDefaultConstructor = SuperClass && SuperClass->HasMetaData(TEXT("OnlyDefaultConstructorDeclared")); Context.CurrentCodeType = FEmitterLocalContext::EGeneratedCodeType::CommonConstructor; Context.ResetPropertiesForInaccessibleStructs(); Context.AddLine(FString::Printf(TEXT("%s::%s(const FObjectInitializer& ObjectInitializer) : Super(%s)") , *CppClassName , *CppClassName , bSuperHasOnlyDefaultConstructor ? TEXT("") : TEXT("ObjectInitializer"))); Context.AddLine(TEXT("{")); Context.IncreaseIndent(); // Call CustomDynamicClassInitialization Context.AddLine(FString::Printf(TEXT("if(HasAnyFlags(RF_ClassDefaultObject) && (%s::StaticClass() == GetClass()))"), *CppClassName)); Context.AddLine(TEXT("{")); Context.IncreaseIndent(); Context.AddLine(FString::Printf(TEXT("%s::__CustomDynamicClassInitialization(CastChecked<UDynamicClass>(GetClass()));"), *CppClassName)); Context.DecreaseIndent(); Context.AddLine(TEXT("}")); // Components that must be fixed after serialization TArray<FString> NativeCreatedComponentProperties; { UObject* CDO = BPGC->GetDefaultObject(false); UObject* ParentCDO = BPGC->GetSuperClass()->GetDefaultObject(false); check(CDO && ParentCDO); Context.AddLine(TEXT("")); FString NativeRootComponentFallback; TSet<const UProperty*> HandledProperties; // Generate ctor init code for native class default subobjects that are always instanced (e.g. components). // @TODO (pkavan) - We can probably make this faster by generating code to index through the DSO array instead (i.e. in place of HandleInstancedSubobject which will generate a lookup call per DSO). TArray<UObject*> NativeDefaultObjectSubobjects; BPGC->GetDefaultObjectSubobjects(NativeDefaultObjectSubobjects); for (auto DSO : NativeDefaultObjectSubobjects) { if (DSO && DSO->GetClass()->HasAnyClassFlags(CLASS_DefaultToInstanced)) { // Determine if this is an editor-only subobject. bool bIsEditorOnlySubobject = false; if (const UActorComponent* ActorComponent = Cast<UActorComponent>(DSO)) { bIsEditorOnlySubobject = ActorComponent->IsEditorOnly(); } // Skip ctor code gen for editor-only subobjects, since they won't be used by the runtime. Any dependencies on editor-only subobjects will be handled later (see HandleInstancedSubobject). if (!bIsEditorOnlySubobject) { const FString VariableName = HandleInstancedSubobject(Context, DSO, false, true); // Keep track of which component can be used as a root, in case it's not explicitly set. if (NativeRootComponentFallback.IsEmpty()) { USceneComponent* SceneComponent = Cast<USceneComponent>(DSO); if (SceneComponent && !SceneComponent->GetAttachParent() && SceneComponent->CreationMethod == EComponentCreationMethod::Native) { NativeRootComponentFallback = VariableName; } } } } } // Check for a valid RootComponent property value; mark it as handled if already set in the defaults. bool bNeedsRootComponentAssignment = false; static const FName RootComponentPropertyName(TEXT("RootComponent")); const UObjectProperty* RootComponentProperty = FindField<UObjectProperty>(BPGC, RootComponentPropertyName); if (RootComponentProperty) { if (RootComponentProperty->GetObjectPropertyValue_InContainer(CDO)) { HandledProperties.Add(RootComponentProperty); } else if (!NativeRootComponentFallback.IsEmpty()) { Context.AddLine(FString::Printf(TEXT("RootComponent = %s;"), *NativeRootComponentFallback)); HandledProperties.Add(RootComponentProperty); } else { bNeedsRootComponentAssignment = true; } } // Generate ctor init code for the SCS node hierarchy (i.e. non-native components). SCS nodes may have dependencies on native DSOs, but not vice-versa. TArray<const UBlueprintGeneratedClass*> BPGCStack; const bool bErrorFree = UBlueprintGeneratedClass::GetGeneratedClassesHierarchy(BPGC, BPGCStack); if (bErrorFree) { TArray<FNonativeComponentData> ComponentsToInit; // Start at the base of the hierarchy so that dependencies are handled first. for (int32 i = BPGCStack.Num() - 1; i >= 0; --i) { if (BPGCStack[i]->SimpleConstructionScript) { for (auto Node : BPGCStack[i]->SimpleConstructionScript->GetRootNodes()) { if (Node) { const FString NativeVariablePropertyName = HandleNonNativeComponent(Context, Node, HandledProperties, NativeCreatedComponentProperties, nullptr, ComponentsToInit); if (bNeedsRootComponentAssignment && Node->ComponentTemplate && Node->ComponentTemplate->IsA<USceneComponent>() && !NativeVariablePropertyName.IsEmpty()) { // Only emit the explicit root component assignment statement if we're looking at the child BPGC that we're generating ctor code // for. In all other cases, the root component will already be set up by a chained parent ctor call, so we avoid stomping it here. if (i == 0) { Context.AddLine(FString::Printf(TEXT("RootComponent = %s;"), *NativeVariablePropertyName)); HandledProperties.Add(RootComponentProperty); } bNeedsRootComponentAssignment = false; } } } } } for (auto& ComponentToInit : ComponentsToInit) { ComponentToInit.EmitProperties(Context); } } // Generate ctor init code for generated Blueprint class property values that may differ from parent class defaults (or that otherwise belong to the generated Blueprint class). for (auto Property : TFieldRange<const UProperty>(BPGC)) { const bool bNewProperty = Property->GetOwnerStruct() == BPGC; const bool bIsAccessible = bNewProperty || !Property->HasAnyPropertyFlags(CPF_NativeAccessSpecifierPrivate); if (bIsAccessible && !HandledProperties.Contains(Property)) { OuterGenerate(Context, Property, TEXT(""), reinterpret_cast<const uint8*>(CDO), bNewProperty ? nullptr : reinterpret_cast<const uint8*>(ParentCDO), EPropertyAccessOperator::None, true); } } } Context.DecreaseIndent(); Context.AddLine(TEXT("}")); Context.CurrentCodeType = FEmitterLocalContext::EGeneratedCodeType::Regular; Context.ResetPropertiesForInaccessibleStructs(); Context.AddLine(FString::Printf(TEXT("void %s::PostLoadSubobjects(FObjectInstancingGraph* OuterInstanceGraph)"), *CppClassName)); Context.AddLine(TEXT("{")); Context.IncreaseIndent(); Context.AddLine(TEXT("Super::PostLoadSubobjects(OuterInstanceGraph);")); for (auto& ComponentToFix : NativeCreatedComponentProperties) { Context.AddLine(FString::Printf(TEXT("if(ensure(%s))"), *ComponentToFix)); Context.AddLine(TEXT("{")); Context.IncreaseIndent(); Context.AddLine(FString::Printf(TEXT("%s->CreationMethod = EComponentCreationMethod::Native;"), *ComponentToFix)); Context.DecreaseIndent(); Context.AddLine(TEXT("}")); } Context.DecreaseIndent(); Context.AddLine(TEXT("}")); FDependenciesHelper::AddStaticFunctionsForDependencies(Context); FBackendHelperUMG::EmitWidgetInitializationFunctions(Context); }
void AActor::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { UProperty* PropertyThatChanged = PropertyChangedEvent.Property; FName PropertyName = PropertyThatChanged != NULL ? PropertyThatChanged->GetFName() : NAME_None; const bool bTransformationChanged = (PropertyName == Name_RelativeLocation || PropertyName == Name_RelativeRotation || PropertyName == Name_RelativeScale3D); // During SIE, allow components to reregistered and reconstructed in PostEditChangeProperty. // This is essential as construction is deferred during spawning / duplication when in SIE. if ((GEditor && GEditor->bIsSimulatingInEditor) || ReregisterComponentsWhenModified()) { // In the Undo case we have an annotation storing information about constructed components and we do not want // to improperly apply out of date changes so we need to skip registration of all blueprint created components // and defer instance components attached to them until after rerun if (CurrentTransactionAnnotation.IsValid()) { UnregisterAllComponents(); TInlineComponentArray<UActorComponent*> Components; GetComponents(Components); Components.Sort([](UActorComponent& A, UActorComponent& B) { if (&B == B.GetOwner()->GetRootComponent()) { return false; } if (USceneComponent* ASC = Cast<USceneComponent>(&A)) { if (ASC->GetAttachParent() == &B) { return false; } } return true; }); bool bRequiresReregister = false; for (UActorComponent* Component : Components) { if (Component->CreationMethod == EComponentCreationMethod::Native) { Component->RegisterComponent(); } else if (Component->CreationMethod == EComponentCreationMethod::Instance) { USceneComponent* SC = Cast<USceneComponent>(Component); if (SC == nullptr || SC == RootComponent || (SC->GetAttachParent() && SC->GetAttachParent()->IsRegistered())) { Component->RegisterComponent(); } else { bRequiresReregister = true; } } else { bRequiresReregister = true; } } RerunConstructionScripts(); if (bRequiresReregister) { ReregisterAllComponents(); } } else { UnregisterAllComponents(); RerunConstructionScripts(); ReregisterAllComponents(); } } // Let other systems know that an actor was moved if (bTransformationChanged) { GEngine->BroadcastOnActorMoved( this ); } if (GetWorld()) { GetWorld()->bDoDelayedUpdateCullDistanceVolumes = true; } FEditorSupportDelegates::UpdateUI.Broadcast(); Super::PostEditChangeProperty(PropertyChangedEvent); }
FSelectedActorInfo BuildSelectedActorInfo( const TArray<AActor*>& SelectedActors) { FSelectedActorInfo ActorInfo; if( SelectedActors.Num() > 0 ) { // Get the class type of the first actor. AActor* FirstActor = SelectedActors[0]; if( FirstActor && !FirstActor->HasAnyFlags( RF_ClassDefaultObject ) ) { UClass* FirstClass = FirstActor->GetClass(); UObject* FirstArchetype = FirstActor->GetArchetype(); ActorInfo.bAllSelectedAreBrushes = Cast< ABrush >( FirstActor ) != NULL; ActorInfo.SelectionClass = FirstClass; // Compare all actor types with the baseline. for ( int32 ActorIndex = 0; ActorIndex < SelectedActors.Num(); ++ActorIndex ) { AActor* CurrentActor = SelectedActors[ ActorIndex ]; if( CurrentActor->HasAnyFlags( RF_ClassDefaultObject ) ) { continue; } ABrush* Brush = Cast< ABrush >( CurrentActor ); if( !Brush) { ActorInfo.bAllSelectedAreBrushes = false; } else { if( !ActorInfo.bHaveBuilderBrush ) { ActorInfo.bHaveBuilderBrush = FActorEditorUtils::IsABuilderBrush(Brush); } ActorInfo.bHaveBrush |= true; ActorInfo.bHaveBSPBrush |= (!Brush->IsVolumeBrush()); ActorInfo.bHaveVolume |= Brush->IsVolumeBrush(); } UClass* CurrentClass = CurrentActor->GetClass(); if( FirstClass != CurrentClass ) { ActorInfo.bAllSelectedActorsOfSameType = false; ActorInfo.SelectionClass = NULL; FirstClass = NULL; } else { ActorInfo.SelectionClass = CurrentActor->GetClass(); } ++ActorInfo.NumSelected; if( ActorInfo.bAllSelectedActorsBelongToCurrentLevel ) { if( !CurrentActor->GetOuter()->IsA(ULevel::StaticClass()) || !CurrentActor->GetLevel()->IsCurrentLevel() ) { ActorInfo.bAllSelectedActorsBelongToCurrentLevel = false; } } if( ActorInfo.bAllSelectedActorsBelongToSameWorld ) { if ( !ActorInfo.SharedWorld ) { ActorInfo.SharedWorld = CurrentActor->GetWorld(); check(ActorInfo.SharedWorld); } else { if( ActorInfo.SharedWorld != CurrentActor->GetWorld() ) { ActorInfo.bAllSelectedActorsBelongToCurrentLevel = false; ActorInfo.SharedWorld = NULL; } } } // To prevent move to other level for Landscape if its components are distributed in streaming levels if (CurrentActor->IsA(ALandscape::StaticClass())) { ALandscape* Landscape = CastChecked<ALandscape>(CurrentActor); if (!Landscape || !Landscape->HasAllComponent()) { if( !ActorInfo.bAllSelectedActorsBelongToCurrentLevel ) { ActorInfo.bAllSelectedActorsBelongToCurrentLevel = true; } } } if ( ActorInfo.bSelectedActorsBelongToSameLevel ) { ULevel* ActorLevel = CurrentActor->GetOuter()->IsA(ULevel::StaticClass()) ? CurrentActor->GetLevel() : NULL; if ( !ActorInfo.SharedLevel ) { // This is the first selected actor we've encountered. ActorInfo.SharedLevel = ActorLevel; } else { // Does this actor's level match the others? if ( ActorInfo.SharedLevel != ActorLevel ) { ActorInfo.bSelectedActorsBelongToSameLevel = false; ActorInfo.SharedLevel = NULL; } } } AGroupActor* FoundGroup = Cast<AGroupActor>(CurrentActor); if(!FoundGroup) { FoundGroup = AGroupActor::GetParentForActor(CurrentActor); } if( FoundGroup ) { if( !ActorInfo.bHaveSelectedSubGroup ) { ActorInfo.bHaveSelectedSubGroup = AGroupActor::GetParentForActor(FoundGroup) != NULL; } if( !ActorInfo.bHaveSelectedLockedGroup ) { ActorInfo.bHaveSelectedLockedGroup = FoundGroup->IsLocked(); } if( !ActorInfo.bHaveSelectedUnlockedGroup ) { AGroupActor* FoundRoot = AGroupActor::GetRootForActor(CurrentActor); ActorInfo.bHaveSelectedUnlockedGroup = !FoundGroup->IsLocked() || ( FoundRoot && !FoundRoot->IsLocked() ); } } else { ++ActorInfo.NumSelectedUngroupedActors; } USceneComponent* RootComp = CurrentActor->GetRootComponent(); if(RootComp != nullptr && RootComp->GetAttachParent() != nullptr) { ActorInfo.bHaveAttachedActor = true; } TInlineComponentArray<UActorComponent*> ActorComponents; CurrentActor->GetComponents(ActorComponents); for( UActorComponent* Component : ActorComponents ) { if( UStaticMeshComponent* SMComp = Cast<UStaticMeshComponent>(Component) ) { if( SMComp->IsRegistered() ) { ActorInfo.bHaveStaticMeshComponent = true; } } // Check for experimental/early-access classes in the component hierarchy bool bIsExperimental, bIsEarlyAccess; FObjectEditorUtils::GetClassDevelopmentStatus(Component->GetClass(), bIsExperimental, bIsEarlyAccess); ActorInfo.bHaveExperimentalClass |= bIsExperimental; ActorInfo.bHaveEarlyAccessClass |= bIsEarlyAccess; } // Check for experimental/early-access classes in the actor hierarchy { bool bIsExperimental, bIsEarlyAccess; FObjectEditorUtils::GetClassDevelopmentStatus(CurrentClass, bIsExperimental, bIsEarlyAccess); ActorInfo.bHaveExperimentalClass |= bIsExperimental; ActorInfo.bHaveEarlyAccessClass |= bIsEarlyAccess; } if( CurrentActor->IsA( ALight::StaticClass() ) ) { ActorInfo.bHaveLight = true; } if( CurrentActor->IsA( AStaticMeshActor::StaticClass() ) ) { ActorInfo.bHaveStaticMesh = true; AStaticMeshActor* StaticMeshActor = CastChecked<AStaticMeshActor>( CurrentActor ); if ( StaticMeshActor->GetStaticMeshComponent() ) { UStaticMesh* StaticMesh = StaticMeshActor->GetStaticMeshComponent()->StaticMesh; ActorInfo.bAllSelectedStaticMeshesHaveCollisionModels &= ( (StaticMesh && StaticMesh->BodySetup) ? true : false ); } } if( CurrentActor->IsA( ASkeletalMeshActor::StaticClass() ) ) { ActorInfo.bHaveSkeletalMesh = true; } if( CurrentActor->IsA( APawn::StaticClass() ) ) { ActorInfo.bHavePawn = true; } if( CurrentActor->IsA( AEmitter::StaticClass() ) ) { ActorInfo.bHaveEmitter = true; } if ( CurrentActor->IsA( AMatineeActor::StaticClass() ) ) { ActorInfo.bHaveMatinee = true; } if ( CurrentActor->IsTemporarilyHiddenInEditor() ) { ActorInfo.bHaveHidden = true; } if ( CurrentActor->IsA( ALandscapeProxy::StaticClass() ) ) { ActorInfo.bHaveLandscape = true; } // Find our counterpart actor AActor* EditorWorldActor = EditorUtilities::GetEditorWorldCounterpartActor( CurrentActor ); if( EditorWorldActor != NULL ) { // Just count the total number of actors with counterparts ++ActorInfo.NumSimulationChanges; } } if( ActorInfo.SelectionClass != NULL ) { ActorInfo.SelectionStr = ActorInfo.SelectionClass->GetName(); } else { ActorInfo.SelectionStr = TEXT("Actor"); } } } // hack when only BSP is selected if( ActorInfo.SharedWorld == nullptr ) { ActorInfo.SharedWorld = GWorld; } return ActorInfo; }
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(); if(PreviewActor) { TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditorPtr.Pin()->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->IsRoot() && !SelectedNodePtr->IsInherited() && !IsMovableParentNodeSelected(SelectedNodePtr, SelectedNodes); if(bCanEdit) { USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodePtr->FindComponentInstanceInActor(PreviewActor, true)); USceneComponent* SelectedTemplate = Cast<USceneComponent>(SelectedNodePtr->GetComponentTemplate()); if(SceneComp != NULL && SelectedTemplate != NULL) { // Cache the current default values for propagation FVector OldRelativeLocation = SelectedTemplate->RelativeLocation; FRotator OldRelativeRotation = SelectedTemplate->RelativeRotation; FVector OldRelativeScale3D = SelectedTemplate->RelativeScale3D; USceneComponent* ParentSceneComp = SceneComp->GetAttachParent(); if( ParentSceneComp ) { const FTransform ParentToWorldSpace = ParentSceneComp->GetSocketTransform(SceneComp->AttachSocketName); if(!SceneComp->bAbsoluteLocation) { Drag = ParentToWorldSpace.Inverse().TransformVector(Drag); } if(!SceneComp->bAbsoluteRotation) { Rot = (ParentToWorldSpace.Inverse().GetRotation() * Rot.Quaternion() * ParentToWorldSpace.GetRotation()).Rotator(); } } FComponentEditorUtils::FTransformData OldDefaultTransform(*SelectedTemplate); TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditorPtr.Pin()->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); } FComponentEditorUtils::FTransformData NewDefaultTransform(*SelectedTemplate); if (SelectedNodePtr->IsNative()) { if (ensure(SelectedTemplate->HasAnyFlags(RF_DefaultSubObject))) { FComponentEditorUtils::PropagateTransformPropertyChange(SelectedTemplate, OldDefaultTransform, NewDefaultTransform, UpdatedComponents); } } 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); } // Get the Blueprint class default object AActor* CDO = NULL; if(PreviewBlueprint->GeneratedClass) { CDO = Cast<AActor>(PreviewBlueprint->GeneratedClass->ClassDefaultObject); } else if(PreviewBlueprint->ParentClass) { CDO = Cast<AActor>(PreviewBlueprint->ParentClass->ClassDefaultObject); } if(CDO != NULL) { // Iterate over all the active archetype instances and propagate the change(s) to the matching component instance TArray<UObject*> ArchetypeInstances; CDO->GetArchetypeInstances(ArchetypeInstances); for(int32 InstanceIndex = 0; InstanceIndex < ArchetypeInstances.Num(); ++InstanceIndex) { AActor* ArchetypeInstance = Cast<AActor>(ArchetypeInstances[InstanceIndex]); if(ArchetypeInstance != NULL) { const bool bIsProcessingPreviewActor = (ArchetypeInstance == PreviewActor); SceneComp = Cast<USceneComponent>(SelectedNodePtr->FindComponentInstanceInActor(ArchetypeInstance, bIsProcessingPreviewActor)); if(!bIsProcessingPreviewActor && SceneComp != nullptr && !UpdatedComponents.Contains(SceneComp)) { FComponentEditorUtils::PropagateTransformPropertyChange(SceneComp, SceneComp->RelativeLocation, OldRelativeLocation, SelectedTemplate->RelativeLocation, UpdatedComponents); FComponentEditorUtils::PropagateTransformPropertyChange(SceneComp, SceneComp->RelativeRotation, OldRelativeRotation, SelectedTemplate->RelativeRotation, UpdatedComponents); FComponentEditorUtils::PropagateTransformPropertyChange(SceneComp, SceneComp->RelativeScale3D, OldRelativeScale3D, SelectedTemplate->RelativeScale3D, UpdatedComponents); } } } } } } } } GUnrealEd->RedrawLevelEditingViewports(); } } Invalidate(); } return bHandled; }