bool UClassThumbnailRenderer::CanVisualizeAsset(UObject* Object) { if (ThumbnailScene == nullptr) { ThumbnailScene = new FClassThumbnailScene(); } UClass* Class = Cast<UClass>(Object); // Only visualize actor based classes if (Class && Class->IsChildOf(AActor::StaticClass())) { // Try to find any visible primitive components in the class' CDO AActor* CDO = Class->GetDefaultObject<AActor>(); TInlineComponentArray<UActorComponent*> Components; CDO->GetComponents(Components); for (auto CompIt = Components.CreateConstIterator(); CompIt; ++CompIt) { if (ThumbnailScene->IsValidComponentForVisualization(*CompIt)) { return true; } } } return false; }
void UActorRecording::StartRecordingNewComponents(ULevelSequence* CurrentSequence, float CurrentSequenceTime) { if (GetActorToRecord() != nullptr) { // find the new component(s) TInlineComponentArray<USceneComponent*> NewComponents; TArray<USceneComponent*> SceneComponents; GetSceneComponents(SceneComponents); for(USceneComponent* SceneComponent : SceneComponents) { if(ValidComponent(SceneComponent)) { TWeakObjectPtr<USceneComponent> WeakSceneComponent(SceneComponent); int32 FoundIndex = TrackedComponents.Find(WeakSceneComponent); if(FoundIndex == INDEX_NONE) { // new component! NewComponents.Add(SceneComponent); } } } ProcessNewComponentArray(NewComponents); UMovieScene* MovieScene = CurrentSequence->GetMovieScene(); check(MovieScene); FAnimationRecordingSettings ComponentAnimationSettings = AnimationSettings; ComponentAnimationSettings.bRemoveRootAnimation = false; ComponentAnimationSettings.bRecordInWorldSpace = false; const USequenceRecorderSettings* Settings = GetDefault<USequenceRecorderSettings>(); if (!bRecordToPossessable) { FMovieSceneSpawnable* Spawnable = MovieScene->FindSpawnable(Guid); check(Spawnable); AActor* ObjectTemplate = CastChecked<AActor>(Spawnable->GetObjectTemplate()); for (USceneComponent* SceneComponent : NewComponents) { // new component, so we need to add this to our BP if it didn't come from SCS FName NewName; if (SceneComponent->CreationMethod != EComponentCreationMethod::SimpleConstructionScript) { // Give this component a unique name within its parent NewName = *FString::Printf(TEXT("Dynamic%s"), *SceneComponent->GetFName().GetPlainNameString()); NewName.SetNumber(1); while (FindObjectFast<UObject>(ObjectTemplate, NewName)) { NewName.SetNumber(NewName.GetNumber() + 1); } USceneComponent* TemplateRoot = ObjectTemplate->GetRootComponent(); USceneComponent* AttachToComponent = nullptr; // look for a similar attach parent in the current structure USceneComponent* AttachParent = SceneComponent->GetAttachParent(); if(AttachParent != nullptr) { // First off, check if we're attached to a component that has already been duplicated into this object // If so, the name lookup will fail, so we use a direct reference if (TWeakObjectPtr<USceneComponent>* DuplicatedComponent = DuplicatedDynamicComponents.Find(AttachParent)) { AttachToComponent = DuplicatedComponent->Get(); } // If we don't have an attachment parent duplicated already, perform a name lookup if (!AttachToComponent) { FName AttachName = SceneComponent->GetAttachParent()->GetFName(); TInlineComponentArray<USceneComponent*> AllChildren; ObjectTemplate->GetComponents(AllChildren); for (USceneComponent* Child : AllChildren) { CA_SUPPRESS(28182); // Dereferencing NULL pointer. 'Child' contains the same NULL value as 'AttachToComponent' did. if (Child->GetFName() == AttachName) { AttachToComponent = Child; break; } } } } if (!AttachToComponent) { AttachToComponent = ObjectTemplate->GetRootComponent(); } USceneComponent* NewTemplateComponent = Cast<USceneComponent>(StaticDuplicateObject(SceneComponent, ObjectTemplate, NewName, RF_AllFlags & ~RF_Transient)); NewTemplateComponent->AttachToComponent(AttachToComponent, FAttachmentTransformRules::KeepRelativeTransform, SceneComponent->GetAttachSocketName()); ObjectTemplate->AddInstanceComponent(NewTemplateComponent); DuplicatedDynamicComponents.Add(SceneComponent, NewTemplateComponent); } else { NewName = SceneComponent->GetFName(); } StartRecordingComponentProperties(NewName, SceneComponent, GetActorToRecord(), CurrentSequence, CurrentSequenceTime, ComponentAnimationSettings); bNewComponentAddedWhileRecording = true; } SyncTrackedComponents(); } else { for (USceneComponent* SceneComponent : NewComponents) { // new component, start recording StartRecordingComponentProperties(SceneComponent->GetFName(), SceneComponent, GetActorToRecord(), CurrentSequence, CurrentSequenceTime, ComponentAnimationSettings); } SyncTrackedComponents(); } } }
void UUnrealEdEngine::DrawComponentVisualizersHUD(const FViewport* Viewport, const FSceneView* View, FCanvas* Canvas) { // Iterate over all selected actors for (FSelectionIterator It(GetSelectedActorIterator()); It; ++It) { AActor* Actor = Cast<AActor>(*It); if (Actor != NULL) { // Then iterate over components of that actor TInlineComponentArray<UActorComponent*> Components; Actor->GetComponents(Components); for (int32 CompIdx = 0; CompIdx<Components.Num(); CompIdx++) { UActorComponent* Comp = Components[CompIdx]; if (Comp->IsRegistered()) { // Try and find a visualizer TSharedPtr<FComponentVisualizer> Visualizer = FindComponentVisualizer(Comp->GetClass()); if (Visualizer.IsValid()) { Visualizer->DrawVisualizationHUD(Comp, Viewport, View, Canvas); } } } } } }
USkeleton* FAnimationTrackEditor::AcquireSkeletonFromObjectGuid(const FGuid& Guid) { TArray<UObject*> OutObjects; GetSequencer()->GetRuntimeObjects(GetSequencer()->GetFocusedMovieSceneInstance(), Guid, OutObjects); USkeleton* Skeleton = NULL; for (int32 i = 0; i < OutObjects.Num(); ++i) { AActor* Actor = Cast<AActor>(OutObjects[i]); if (Actor != NULL) { TInlineComponentArray<USkeletalMeshComponent*> SkeletalMeshComponents; Actor->GetComponents(SkeletalMeshComponents); for (int32 j = 0; j <SkeletalMeshComponents.Num(); ++j) { USkeletalMeshComponent* SkeletalMeshComp = SkeletalMeshComponents[j]; if (SkeletalMeshComp->SkeletalMesh && SkeletalMeshComp->SkeletalMesh->Skeleton) { // @todo Multiple actors, multiple components check(!Skeleton); Skeleton = SkeletalMeshComp->SkeletalMesh->Skeleton; } } } } return Skeleton; }
//* Destroys the constructed components. void AActor::DestroyConstructedComponents() { // Remove all existing components TInlineComponentArray<UActorComponent*> PreviouslyAttachedComponents; GetComponents(PreviouslyAttachedComponents); // We need the hierarchy to be torn down in attachment order, so do a quick sort PreviouslyAttachedComponents.Remove(nullptr); PreviouslyAttachedComponents.Sort([](UActorComponent& A, UActorComponent& B) { if (USceneComponent* BSC = Cast<USceneComponent>(&B)) { if (BSC->AttachParent == &A) { return false; } } return true; }); for (UActorComponent* Component : PreviouslyAttachedComponents) { if (Component) { bool bDestroyComponent = false; if (Component->IsCreatedByConstructionScript()) { bDestroyComponent = true; } else { UActorComponent* OuterComponent = Component->GetTypedOuter<UActorComponent>(); while (OuterComponent) { if (OuterComponent->IsCreatedByConstructionScript()) { bDestroyComponent = true; break; } OuterComponent = OuterComponent->GetTypedOuter<UActorComponent>(); } } if (bDestroyComponent) { if (Component == RootComponent) { RootComponent = NULL; } Component->DestroyComponent(); // Rename component to avoid naming conflicts in the case where we rerun the SCS and name the new components the same way. FName const NewBaseName( *(FString::Printf(TEXT("TRASH_%s"), *Component->GetClass()->GetName())) ); FName const NewObjectName = MakeUniqueObjectName(this, GetClass(), NewBaseName); Component->Rename(*NewObjectName.ToString(), this, REN_ForceNoResetLoaders|REN_DontCreateRedirectors|REN_NonTransactional); } } } }
void UUnrealEdEngine::SetActorSelectionFlags (AActor* InActor) { TInlineComponentArray<UActorComponent*> Components; InActor->GetComponents(Components); //for every component in the actor for(int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++) { UActorComponent* Component = Components[ComponentIndex]; if (Component->IsRegistered()) { // If we have a 'child actor' component, want to update its visible selection state UChildActorComponent* ChildActorComponent = Cast<UChildActorComponent>(Component); if(ChildActorComponent != NULL && ChildActorComponent->ChildActor != NULL) { SetActorSelectionFlags(ChildActorComponent->ChildActor); } UPrimitiveComponent* PrimComponent = Cast<UPrimitiveComponent>(Component); if(PrimComponent != NULL && PrimComponent->IsRegistered()) { PrimComponent->PushSelectionToProxy(); } UDecalComponent* DecalComponent = Cast<UDecalComponent>(Component); if(DecalComponent != NULL)// && DecalComponent->IsRegistered()) { DecalComponent->PushSelectionToProxy(); } } } }
void AActor::CheckForErrors() { if ( GetClass()->HasAnyClassFlags(CLASS_Deprecated) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); FMessageLog("MapCheck").Warning() ->AddToken(FUObjectToken::Create(this)) ->AddToken(FTextToken::Create(FText::Format(LOCTEXT( "MapCheck_Message_ActorIsObselete_Deprecated", "{ActorName} : Obsolete and must be removed! (Class is deprecated)" ), Arguments) )) ->AddToken(FMapErrorToken::Create(FMapErrors::ActorIsObselete)); return; } if ( GetClass()->HasAnyClassFlags(CLASS_Abstract) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); FMessageLog("MapCheck").Warning() ->AddToken(FUObjectToken::Create(this)) ->AddToken(FTextToken::Create(FText::Format(LOCTEXT( "MapCheck_Message_ActorIsObselete_Abstract", "{ActorName} : Obsolete and must be removed! (Class is abstract)" ), Arguments) )) ->AddToken(FMapErrorToken::Create(FMapErrors::ActorIsObselete)); return; } UPrimitiveComponent* PrimComp = Cast<UPrimitiveComponent>(RootComponent); if( PrimComp && (PrimComp->Mobility != EComponentMobility::Movable) && PrimComp->BodyInstance.bSimulatePhysics) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); FMessageLog("MapCheck").Warning() ->AddToken(FUObjectToken::Create(this)) ->AddToken(FTextToken::Create(FText::Format(LOCTEXT( "MapCheck_Message_StaticPhysNone", "{ActorName} : Static object with bSimulatePhysics set to true" ), Arguments) )) ->AddToken(FMapErrorToken::Create(FMapErrors::StaticPhysNone)); } if( RootComponent && FMath::IsNearlyZero( GetRootComponent()->RelativeScale3D.X * GetRootComponent()->RelativeScale3D.Y * GetRootComponent()->RelativeScale3D.Z ) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); FMessageLog("MapCheck").Error() ->AddToken(FUObjectToken::Create(this)) ->AddToken(FTextToken::Create(FText::Format(LOCTEXT( "MapCheck_Message_InvalidDrawscale", "{ActorName} : Invalid DrawScale/DrawScale3D" ), Arguments) )) ->AddToken(FMapErrorToken::Create(FMapErrors::InvalidDrawscale)); } // Route error checking to components. TInlineComponentArray<UActorComponent*> Components; GetComponents(Components); for ( int32 ComponentIndex = 0 ; ComponentIndex < Components.Num() ; ++ComponentIndex ) { UActorComponent* ActorComponent = Components[ ComponentIndex ]; if (ActorComponent->IsRegistered()) { ActorComponent->CheckForErrors(); } } }
void FLayers::RemoveViewFromActorViewVisibility( FLevelEditorViewportClient* ViewportClient ) { const int32 ViewIndex = ViewportClient->ViewIndex; // get the bit for the view index uint64 ViewBit = ((uint64)1 << ViewIndex); // get all bits under that that we want to keep uint64 KeepBits = ViewBit - 1; // Iterate over all actors, looking for actors in the specified layers. for( FActorIterator It(ViewportClient->GetWorld()) ; It ; ++It ) { const TWeakObjectPtr< AActor > Actor = *It; if( !IsActorValidForLayer( Actor ) ) { continue; } // remember original bits uint64 OriginalHiddenViews = Actor->HiddenEditorViews; uint64 Was = Actor->HiddenEditorViews; // slide all bits higher than ViewIndex down one since the view is being removed from Editor uint64 LowBits = Actor->HiddenEditorViews & KeepBits; // now slide the top bits down by ViewIndex + 1 (chopping off ViewBit) uint64 HighBits = Actor->HiddenEditorViews >> (ViewIndex + 1); // then slide back up by ViewIndex, which will now have erased ViewBit, as well as leaving 0 in the low bits HighBits = HighBits << ViewIndex; // put it all back together Actor->HiddenEditorViews = LowBits | HighBits; // reregister if we changed the visibility bits, as the rendering thread needs them if (OriginalHiddenViews == Actor->HiddenEditorViews) { continue; } // Find all registered primitive components and update the scene proxy with the actors updated visibility map TInlineComponentArray<UPrimitiveComponent*> Components; Actor->GetComponents(Components); for( int32 ComponentIdx = 0; ComponentIdx < Components.Num(); ++ComponentIdx ) { UPrimitiveComponent* PrimitiveComponent = Components[ComponentIdx]; if (PrimitiveComponent->IsRegistered()) { // Push visibility to the render thread PrimitiveComponent->PushEditorVisibilityToProxy( Actor->HiddenEditorViews ); } } } }
void FSCSEditorViewportClient::Tick(float DeltaSeconds) { FEditorViewportClient::Tick(DeltaSeconds); // Register the selection override delegate for the preview actor's components TSharedPtr<SSCSEditor> SCSEditor = BlueprintEditorPtr.Pin()->GetSCSEditor(); AActor* PreviewActor = GetPreviewActor(); if (PreviewActor != nullptr) { TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; PreviewActor->GetComponents(PrimitiveComponents); for (int32 CompIdx = 0; CompIdx < PrimitiveComponents.Num(); ++CompIdx) { UPrimitiveComponent* PrimComponent = PrimitiveComponents[CompIdx]; if (!PrimComponent->SelectionOverrideDelegate.IsBound()) { SCSEditor->SetSelectionOverride(PrimComponent); } } } else { InvalidatePreview(false); } if ( PreviewActor != LastPreviewActor.Get() || PreviewActor == nullptr || IsRealtime() ) { LastPreviewActor = PreviewActor; Invalidate(); RefreshPreviewBounds(); } // Tick the preview scene world. if (!GIntraFrameDebuggingGameThread) { // Ensure that the preview actor instance is up-to-date for component editing (e.g. after compiling the Blueprint, the actor may be reinstanced outside of this class) if(PreviewActor != BlueprintEditorPtr.Pin()->GetBlueprintObj()->SimpleConstructionScript->GetComponentEditorActorInstance()) { BlueprintEditorPtr.Pin()->GetBlueprintObj()->SimpleConstructionScript->SetComponentEditorActorInstance(PreviewActor); } // Allow full tick only if preview simulation is enabled and we're not currently in an active SIE or PIE session if(bIsSimulateEnabled && GEditor->PlayWorld == NULL && !GEditor->bIsSimulatingInEditor) { PreviewScene->GetWorld()->Tick(IsRealtime() ? LEVELTICK_All : LEVELTICK_TimeOnly, DeltaSeconds); } else { PreviewScene->GetWorld()->Tick(IsRealtime() ? LEVELTICK_ViewportsOnly : LEVELTICK_TimeOnly, DeltaSeconds); } } }
void USceneCaptureComponent::HideActorComponents(AActor* InActor) { if (InActor) { TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; InActor->GetComponents(PrimitiveComponents); for (int32 ComponentIndex = 0, NumComponents = PrimitiveComponents.Num(); ComponentIndex < NumComponents; ++ComponentIndex) { HiddenComponents.AddUnique(PrimitiveComponents[ComponentIndex]); } } }
void FSCSEditorViewportClient::ProcessClick(class FSceneView& View, class HHitProxy* HitProxy, FKey Key, EInputEvent Event, uint32 HitX, uint32 HitY) { if(HitProxy) { if(HitProxy->IsA(HInstancedStaticMeshInstance::StaticGetType())) { HInstancedStaticMeshInstance* InstancedStaticMeshInstanceProxy = ( ( HInstancedStaticMeshInstance* )HitProxy ); TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditorPtr.Pin()->CustomizeSCSEditor(InstancedStaticMeshInstanceProxy->Component); if(Customization.IsValid() && Customization->HandleViewportClick(AsShared(), View, HitProxy, Key, Event, HitX, HitY)) { Invalidate(); } } else if(HitProxy->IsA(HActor::StaticGetType())) { HActor* ActorProxy = (HActor*)HitProxy; AActor* PreviewActor = GetPreviewActor(); if(ActorProxy && ActorProxy->Actor && ActorProxy->Actor == PreviewActor && ActorProxy->PrimComponent != NULL) { TInlineComponentArray<USceneComponent*> SceneComponents; ActorProxy->Actor->GetComponents(SceneComponents); for(auto CompIt = SceneComponents.CreateConstIterator(); CompIt; ++CompIt) { USceneComponent* CompInstance = *CompIt; TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditorPtr.Pin()->CustomizeSCSEditor(CompInstance); if (Customization.IsValid() && Customization->HandleViewportClick(AsShared(), View, HitProxy, Key, Event, HitX, HitY)) { break; } if (CompInstance == ActorProxy->PrimComponent) { const bool bIsCtrlKeyDown = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl); if (BlueprintEditorPtr.IsValid()) { // Note: This will find and select any node associated with the component instance that's attached to the proxy (including visualizers) BlueprintEditorPtr.Pin()->FindAndSelectSCSEditorTreeNode(CompInstance, bIsCtrlKeyDown); } break; } } } Invalidate(); } // Pass to component vis manager //GUnrealEd->ComponentVisManager.HandleProxyForComponentVis(HitProxy); } }
static UProperty *GetPropertyByName( UClass *InClass, const FName &Name ) { if ( InClass == NULL ) return NULL; UProperty *Property = GetPropertyByNameRecurse( InClass, Name.ToString() ); if ( Property != NULL ) { return Property; } AActor *AsActor = Cast<AActor>(InClass->ClassDefaultObject); if ( AsActor != NULL ) { FString ComponentPropertyName = Name.ToString(); int32 SplitIndex = 0; if ( ComponentPropertyName.FindChar( '.', SplitIndex ) ) { //FString ComponentName = ComponentPropertyName.LeftChop(SplitIndex); ComponentPropertyName = ComponentPropertyName.RightChop(SplitIndex+1); TInlineComponentArray<UActorComponent*> ActorComponents; AsActor->GetComponents(ActorComponents); for ( auto ComponentIt = ActorComponents.CreateIterator(); ComponentIt; ++ComponentIt ) { UActorComponent *Component = *ComponentIt; check( Component != NULL ); /* if ( Component->GetName() != ComponentName ) { continue; } */ Property = GetPropertyByNameRecurse( Component->GetClass(), ComponentPropertyName ); if ( Property != NULL ) { return Property; } } } } return NULL; }
/** * Determines if the provided actor is capable of having a material applied to it. * * @param TargetActor Actor to check for the validity of material application * * @return true if the actor is valid for material application; false otherwise */ bool FActorFactoryAssetProxy::IsActorValidForMaterialApplication( AActor* TargetActor ) { bool bIsValid = false; //@TODO: PAPER2D: Extend this to support non mesh components (or make sprites a mesh component) // Check if the actor has a mesh or fog volume density. If so, it can likely have // a material applied to it. Otherwise, it cannot. if ( TargetActor ) { TInlineComponentArray<UMeshComponent*> MeshComponents; TargetActor->GetComponents(MeshComponents); bIsValid = (MeshComponents.Num() > 0); } return bIsValid; }
void UUnrealEdEngine::SelectComponent(UActorComponent* Component, bool bInSelected, bool bNotify, bool bSelectEvenIfHidden) { // Don't do any work if the component's selection state matches the target selection state const bool bComponentSelected = GetSelectedComponents()->IsSelected(Component); if (( bComponentSelected && !bInSelected ) || ( !bComponentSelected && bInSelected )) { if (bInSelected) { UE_LOG(LogEditorSelectUtils, Verbose, TEXT("Selected Component: %s"), *Component->GetClass()->GetName()); } else { UE_LOG(LogEditorSelectUtils, Verbose, TEXT("Deselected Component: %s"), *Component->GetClass()->GetName()); } GetSelectedComponents()->Select(Component, bInSelected); // Make sure the override delegate is bound properly auto SceneComponent = Cast<USceneComponent>(Component); if (SceneComponent) { FComponentEditorUtils::BindComponentSelectionOverride(SceneComponent, true); } // Update the selection visualization AActor* ComponentOwner = Component->GetOwner(); if (ComponentOwner != nullptr) { TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; ComponentOwner->GetComponents(PrimitiveComponents); for (int32 Idx = 0; Idx < PrimitiveComponents.Num(); ++Idx) { PrimitiveComponents[Idx]->PushSelectionToProxy(); } } if (bNotify) { NoteSelectionChange(); } } }
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 FSCSEditorViewportClient::RefreshPreviewBounds() { AActor* PreviewActor = GetPreviewActor(); if(PreviewActor) { // Compute actor bounds as the sum of its visible parts TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; PreviewActor->GetComponents(PrimitiveComponents); PreviewActorBounds = FBoxSphereBounds(ForceInitToZero); for(auto CompIt = PrimitiveComponents.CreateConstIterator(); CompIt; ++CompIt) { // Aggregate primitive components that either have collision enabled or are otherwise visible components in-game UPrimitiveComponent* PrimComp = *CompIt; if(PrimComp->IsRegistered() && (!PrimComp->bHiddenInGame || PrimComp->IsCollisionEnabled()) && PrimComp->Bounds.SphereRadius < HALF_WORLD_MAX) { PreviewActorBounds = PreviewActorBounds + PrimComp->Bounds; } } } }
static void DrawSnapVertices( AActor* Actor, float PointSize, FPrimitiveDrawInterface* PDI ) { TInlineComponentArray<UActorComponent*> Components; Actor->GetComponents(Components); // Get the closest vertex on each component for( int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ++ComponentIndex ) { TSharedPtr<FVertexIterator> VertexGetter = MakeVertexIterator( Cast<UPrimitiveComponent>( Components[ComponentIndex] ) ); if( VertexGetter.IsValid() ) { FVertexIterator& VertexGetterRef = *VertexGetter; for( ; VertexGetterRef; ++VertexGetterRef ) { PDI->DrawPoint( VertexGetterRef.Position(), VertexSnappingConstants::VertexHelperColor, PointSize, SDPG_World ); } } else { PDI->DrawPoint( Actor->GetActorLocation(), VertexSnappingConstants::VertexHelperColor, PointSize, SDPG_World ); } } }
static UProperty *GetPropertyByName( UObject *Target, UStruct *InStruct, const FString &PropertyName, void ** hContainerPtr, int32 &OutArrayIndex ) { UProperty *Prop = GetPropertyByNameRecurse( Target->GetClass(), PropertyName, hContainerPtr, OutArrayIndex ); if ( Prop == NULL ) { AActor *AsActor = Cast<AActor>(Target); if ( AsActor != NULL ) { FString ComponentPropertyName = PropertyName; int32 SplitIndex = 0; if ( ComponentPropertyName.FindChar( '.', SplitIndex ) ) { //FString ComponentName = ComponentPropertyName.LeftChop(SplitIndex); ComponentPropertyName = ComponentPropertyName.RightChop(SplitIndex+1); TInlineComponentArray<UActorComponent*> ActorComponents; AsActor->GetComponents(ActorComponents); for ( auto ComponentIt = ActorComponents.CreateIterator(); ComponentIt && !Prop; ++ComponentIt ) { UActorComponent *Component = *ComponentIt; check( Component != NULL ); /* if ( Component->GetName() != ComponentName ) { continue; } */ *hContainerPtr = Component; Prop = GetPropertyByNameRecurse( Component->GetClass(), ComponentPropertyName, hContainerPtr, OutArrayIndex ); } } } } return Prop; }
bool UMatineeTrackAnimControlHelper::PreCreateKeyframe( UInterpTrack *Track, float fTime ) const { KeyframeAddAnimSequence = NULL; UInterpTrackAnimControl *AnimTrack = CastChecked<UInterpTrackAnimControl>(Track); UInterpGroup* Group = CastChecked<UInterpGroup>(Track->GetOuter()); AActor* Actor = GetGroupActor(Track); if (!Actor) { // error message UE_LOG(LogSlateMatinee, Warning, TEXT("No Actor is selected. Select actor first.")); return false; } USkeletalMeshComponent * SkelMeshComp = NULL; TInlineComponentArray<USkeletalMeshComponent*> SkeletalMeshComponents; Actor->GetComponents(SkeletalMeshComponents); for (int32 I=0; I<SkeletalMeshComponents.Num(); ++I) { USkeletalMeshComponent * CurSkelMeshComp = SkeletalMeshComponents[I]; // if qualified to play animation, break if (CurSkelMeshComp->SkeletalMesh && CurSkelMeshComp->SkeletalMesh->Skeleton) { SkelMeshComp = CurSkelMeshComp; break; } } if (!SkelMeshComp) { UE_LOG(LogSlateMatinee, Warning, TEXT("SkeletalMeshComponent isn't found in the selected actor or it does not have Mesh/Skeleton set up in order to play animation")); return false; } USkeleton* Skeleton = SkelMeshComp->SkeletalMesh->Skeleton; if ( Skeleton ) { // Show the dialog. FEdModeInterpEdit* Mode = (FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_InterpEdit ); check(Mode != NULL); check(Mode->InterpEd != NULL); TSharedPtr< SWindow > Parent = FSlateApplication::Get().GetActiveTopLevelWindow(); if ( Parent.IsValid() ) { FAssetPickerConfig AssetPickerConfig; AssetPickerConfig.OnAssetSelected = FOnAssetSelected::CreateUObject( this, &UMatineeTrackAnimControlHelper::OnAddKeyTextEntry, Mode->InterpEd, Track ); AssetPickerConfig.bAllowNullSelection = false; AssetPickerConfig.InitialAssetViewType = EAssetViewType::List; // Filter config AssetPickerConfig.Filter.ClassNames.Add(UAnimSequence::StaticClass()->GetFName()); AssetPickerConfig.Filter.TagsAndValues.Add(TEXT("Skeleton"), FAssetData(Skeleton).GetExportTextName()); FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser")); FMenuBuilder MenuBuilder(true, NULL); MenuBuilder.BeginSection(NAME_None, LOCTEXT("MatineeAnimPicker", "Browse")); { TSharedPtr<SBox> MenuEntry = SNew(SBox) .WidthOverride(300.0f) .HeightOverride(300.f) [ ContentBrowserModule.Get().CreateAssetPicker(AssetPickerConfig) ]; MenuBuilder.AddWidget(MenuEntry.ToSharedRef(), FText::GetEmpty(), true); } MenuBuilder.EndSection(); EntryMenu = FSlateApplication::Get().PushMenu( Parent.ToSharedRef(), FWidgetPath(), MenuBuilder.MakeWidget(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect(FPopupTransitionEffect::TypeInPopup) ); } } else { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "NoAnimSeqsFound", "No AnimSequences Found. Make sure to load AnimSequences.") ); } return false; }
void UUnrealEdEngine::UpdateVolumeActorVisibility( UClass* InVolumeActorClass, FLevelEditorViewportClient* InViewport ) { TSubclassOf<AActor> VolumeClassToCheck = InVolumeActorClass ? InVolumeActorClass : AVolume::StaticClass(); // Build a list of actors that need to be updated. Only take actors of the passed in volume class. UWorld* World = InViewport ? InViewport->GetWorld() : GWorld; TArray< AActor *> ActorsToUpdate; for( TActorIterator<AActor> It( World, VolumeClassToCheck ); It; ++It) { ActorsToUpdate.Add(*It); } if( ActorsToUpdate.Num() > 0 ) { TArray< AActor* > ActorsThatChanged; if( !InViewport ) { // Update the visibility state of each actor for each viewport for( int32 ViewportIdx = 0; ViewportIdx < LevelViewportClients.Num(); ++ViewportIdx ) { FLevelEditorViewportClient& ViewClient = *LevelViewportClients[ViewportIdx]; { // Only update the editor frame clients as those are the only viewports right now that show volumes. InternalUpdateVolumeActorVisibility( ActorsToUpdate, ViewClient, ActorsThatChanged ); if( ActorsThatChanged.Num() ) { // If actor visibility changed in the viewport, it needs to be redrawn ViewClient.Invalidate(); } } } } else { // Only update the editor frame clients as those are the only viewports right now that show volumes. InternalUpdateVolumeActorVisibility( ActorsToUpdate, *InViewport, ActorsThatChanged ); if( ActorsThatChanged.Num() ) { // If actor visibility changed in the viewport, it needs to be redrawn InViewport->Invalidate(); } } // Push all changes in the actors to the scene proxy so the render thread correctly updates visibility for( int32 ActorIdx = 0; ActorIdx < ActorsThatChanged.Num(); ++ActorIdx ) { AActor* ActorToUpdate = ActorsThatChanged[ ActorIdx ]; // Find all registered primitive components and update the scene proxy with the actors updated visibility map TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; ActorToUpdate->GetComponents(PrimitiveComponents); for( int32 ComponentIdx = 0; ComponentIdx < PrimitiveComponents.Num(); ++ComponentIdx ) { UPrimitiveComponent* PrimitiveComponent = PrimitiveComponents[ComponentIdx]; if (PrimitiveComponent->IsRegistered()) { // Push visibility to the render thread PrimitiveComponent->PushEditorVisibilityToProxy( ActorToUpdate->HiddenEditorViews ); } } } } }
FSnappingVertex FVertexSnappingImpl::GetClosestVertex( const TArray<FSnapActor>& Actors, const FVertexSnappingArgs& InArgs ) { // The current closest distance float ClosestDistance = FLT_MAX; const FPlane& ActorPlane = InArgs.ActorPlane; EAxisList::Type CurrentAxis = InArgs.CurrentAxis; const FSceneView* View = InArgs.SceneView; const FVector& CurrentLocation = InArgs.CurrentLocation; const FVector2D& MousePosition = InArgs.MousePosition; FSnappingVertex ClosestLocation( CurrentLocation ); AActor* ClosestActor = NULL; // Find the closest vertex on each actor and then from that list find the closest vertex for( int32 ActorIndex = 0; ActorIndex < Actors.Num(); ++ActorIndex ) { const FSnapActor& SnapActor = Actors[ActorIndex]; AActor* Actor = SnapActor.Actor; // Get the closest vertex on each component TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; Actor->GetComponents(PrimitiveComponents); for( int32 ComponentIndex = 0; ComponentIndex < PrimitiveComponents.Num(); ++ComponentIndex ) { FSnappingVertex ClosestLocationOnComponent( CurrentLocation ); if( !GetClosestVertexOnComponent( SnapActor, PrimitiveComponents[ComponentIndex], InArgs, ClosestLocationOnComponent ) ) { ClosestLocationOnComponent.Position = Actor->GetActorLocation(); ClosestLocationOnComponent.Normal = FVector::ZeroVector; } float Distance = 0; if( CurrentAxis != EAxisList::Screen ) { // Compute the distance from the point being snapped. When not in screen space we snap to the plane created by the current closest vertex Distance = ActorPlane.PlaneDot( ClosestLocationOnComponent.Position ); } else { // Favor the vertex closest to the mouse in screen space FVector2D ComponentLocPixel; if( View->WorldToPixel( ClosestLocationOnComponent.Position, ComponentLocPixel ) ) { Distance = FVector::DistSquared( FVector( MousePosition, 0 ), FVector( ComponentLocPixel, 0 ) ); } } if( // A close vertex must have been found ClosestLocationOnComponent.Position != CurrentLocation // we must have made some movement && !FMath::IsNearlyZero(Distance) // If not in screen space the vertex cannot be behind the point being snapped && ( CurrentAxis == EAxisList::Screen || !FMath::IsNegativeFloat( Distance ) ) // The vertex must be closer than the current closest vertex && Distance < ClosestDistance ) { ClosestActor = Actor; ClosestDistance = Distance; ClosestLocation = ClosestLocationOnComponent; } } } if( InArgs.bDrawVertexHelpers ) { if(ActorVertsToDraw.IsValid()) { ActorVertsToFade.Add(ActorVertsToDraw, FApp::GetCurrentTime()); } ActorVertsToFade.Remove(ClosestActor); ActorVertsToDraw = ClosestActor; } else { ActorVertsToDraw = nullptr; ActorVertsToFade.Empty(); } return ClosestLocation; }
USceneComponent* USimpleConstructionScript::GetSceneRootComponentTemplate(USCS_Node** OutSCSNode) const { UBlueprint* Blueprint = GetBlueprint(); UClass* GeneratedClass = GetOwnerClass(); if(OutSCSNode) { *OutSCSNode = nullptr; } // Get the Blueprint class default object AActor* CDO = nullptr; if(GeneratedClass != nullptr) { CDO = Cast<AActor>(GeneratedClass->GetDefaultObject(false)); } // If the generated class does not yet have a CDO, defer to the parent class if(CDO == nullptr && Blueprint->ParentClass != nullptr) { CDO = Cast<AActor>(Blueprint->ParentClass->GetDefaultObject(false)); } // Check to see if we already have a native root component template USceneComponent* RootComponentTemplate = nullptr; if(CDO != nullptr) { // If the root component property is not set, the first available scene component will be used as the root. This matches what's done in the SCS editor. RootComponentTemplate = CDO->GetRootComponent(); if(!RootComponentTemplate) { TInlineComponentArray<USceneComponent*> SceneComponents; CDO->GetComponents(SceneComponents); if(SceneComponents.Num() > 0) { RootComponentTemplate = SceneComponents[0]; } } } // Don't add the default scene root if we already have a native scene root component if(!RootComponentTemplate) { // Get the Blueprint hierarchy TArray<UBlueprint*> BPStack; if(Blueprint->GeneratedClass != nullptr) { UBlueprint::GetBlueprintHierarchyFromClass(Blueprint->GeneratedClass, BPStack); } else if(Blueprint->ParentClass != nullptr) { UBlueprint::GetBlueprintHierarchyFromClass(Blueprint->ParentClass, BPStack); } // Note: Normally if the Blueprint has a parent, we can assume that the parent already has a scene root component set, // ...but we'll run through the hierarchy just in case there are legacy BPs out there that might not adhere to this assumption. TArray<const USimpleConstructionScript*> SCSStack; SCSStack.Add(this); for(int32 StackIndex = 0; StackIndex < BPStack.Num(); ++StackIndex) { if(BPStack[StackIndex] && BPStack[StackIndex]->SimpleConstructionScript && !SCSStack.Contains(BPStack[StackIndex]->SimpleConstructionScript)) { // UBlueprint::GetBlueprintHierarchyFromClass returns first children then parents. So we need to revert the order. SCSStack.Insert(BPStack[StackIndex]->SimpleConstructionScript, 0); } } for(int32 StackIndex = 0; StackIndex < SCSStack.Num() && !RootComponentTemplate; ++StackIndex) { // Check for any scene component nodes in the root set that are not the default scene root const TArray<USCS_Node*>& SCSRootNodes = SCSStack[StackIndex]->GetRootNodes(); for(int32 RootNodeIndex = 0; RootNodeIndex < SCSRootNodes.Num() && RootComponentTemplate == nullptr; ++RootNodeIndex) { USCS_Node* RootNode = SCSRootNodes[RootNodeIndex]; if(RootNode != nullptr && RootNode != DefaultSceneRootNode && RootNode->ComponentTemplate != nullptr && RootNode->ComponentTemplate->IsA<USceneComponent>()) { if(OutSCSNode) { *OutSCSNode = RootNode; } RootComponentTemplate = Cast<USceneComponent>(RootNode->ComponentTemplate); } } } } return RootComponentTemplate; }
void ADebugCameraHUD::PostRender() { Super::PostRender(); if (bShowHUD) { ADebugCameraController* DCC = Cast<ADebugCameraController>( PlayerOwner ); UFont* RenderFont = GEngine->GetSmallFont(); if( DCC != NULL ) { FFontRenderInfo FontRenderInfo = Canvas->CreateFontRenderInfo(false, true); Canvas->SetDrawColor(64, 64, 255, 255); FString MyText = TEXT("Debug Camera"); float xl, yl; Canvas->StrLen(RenderFont, MyText, xl, yl); float X = Canvas->SizeX * 0.05f; float Y = yl;//*1.67; yl += 2*Y; Canvas->DrawText(RenderFont, MyText, X, yl, 1.f, 1.f, FontRenderInfo); Canvas->SetDrawColor(200, 200, 128, 255); FVector const CamLoc = DCC->PlayerCameraManager->GetCameraLocation(); FRotator const CamRot = DCC->PlayerCameraManager->GetCameraRotation(); float const CamFOV = DCC->PlayerCameraManager->GetFOVAngle(); yl += Y; FString const LocRotString = FString::Printf(TEXT("Loc=(%.1f, %.1f, %.1f) Rot=(%.1f, %.1f, %.1f)"), CamLoc.X, CamLoc.Y, CamLoc.Z, CamRot.Pitch, CamRot.Yaw, CamRot.Roll); Canvas->DrawText(RenderFont, LocRotString, X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; FString const FOVString = FString::Printf(TEXT("HFOV=%.1f"), CamFOV); Canvas->DrawText(RenderFont, FOVString, X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; FString const SpeedScaleString = FString::Printf(TEXT("SpeedScale=%.2fx"), DCC->SpeedScale); Canvas->DrawText(RenderFont, SpeedScaleString, X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; FString const SpeedString = FString::Printf(TEXT("MaxSpeed=%.1f"), DCC->GetSpectatorPawn() && DCC->GetSpectatorPawn()->GetMovementComponent() ? DCC->GetSpectatorPawn()->GetMovementComponent()->GetMaxSpeed() : 0.f); Canvas->DrawText(RenderFont, SpeedString, X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; //Canvas->DrawText(FString::Printf(TEXT("CamLoc:%s CamRot:%s"), *CamLoc.ToString(), *CamRot.ToString() )); const TCHAR* CVarComplexName = TEXT("g.DebugCameraTraceComplex"); bool bTraceComplex = true; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) bTraceComplex = CVarDebugCameraTraceComplex.GetValueOnGameThread() != 0; #endif FCollisionQueryParams TraceParams(NAME_None, bTraceComplex, this); FHitResult Hit; bool bHit = GetWorld()->LineTraceSingleByChannel(Hit, CamLoc, CamRot.Vector() * 100000.f + CamLoc, ECC_Pawn, TraceParams); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("Trace info (%s = %d):"), CVarComplexName, bTraceComplex ? 1 : 0), X, yl, 1.f, 1.f, FontRenderInfo); if( bHit ) { AActor* HitActor = Hit.GetActor(); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitLoc:%s HitNorm:%s"), *Hit.Location.ToString(), *Hit.Normal.ToString() ), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitDist: %f"), Hit.Distance), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitActor: '%s'"), HitActor ? *HitActor->GetFName().ToString() : TEXT("<NULL>")), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitComponent: '%s'"), Hit.Component.Get() ? *Hit.Component.Get()->GetFName().ToString() : TEXT("<NULL>")), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitActor Class: '%s'"), HitActor && HitActor->GetClass() ? *HitActor->GetClass()->GetName() : TEXT("<Not Found>") ), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitActorPath: '%s'"), HitActor ? *HitActor->GetPathName() : TEXT("<Not Found>")), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; bool bFoundMaterial = false; if ( Hit.Component != NULL ) { bFoundMaterial = DisplayMaterials( X, yl, Y, Cast<UMeshComponent>(Hit.Component.Get()) ); } else { TInlineComponentArray<UMeshComponent*> Components; GetComponents(Components); for ( int32 i=0; i<Components.Num(); i++ ) { UMeshComponent* MeshComp = Components[i]; if ( MeshComp->IsRegistered() ) { bFoundMaterial = bFoundMaterial || DisplayMaterials( X, yl, Y, MeshComp ); } } } if ( bFoundMaterial == false ) { yl += Y; Canvas->DrawText(RenderFont, "Material: NULL", X + Y, yl, 1.f, 1.f, FontRenderInfo ); } DrawDebugLine( GetWorld(), Hit.Location, Hit.Location+Hit.Normal*30.f, FColor::White ); } else { yl += Y; Canvas->DrawText( RenderFont, TEXT("No trace Hit"), X, yl, 1.f, 1.f, FontRenderInfo); } if ( DCC->bShowSelectedInfo && DCC->SelectedActor != NULL ) { yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("Selected actor: '%s'"), *DCC->SelectedActor->GetFName().ToString()), X, yl, 1.f, 1.f, FontRenderInfo); DisplayMaterials( X, yl, Y, Cast<UMeshComponent>(DCC->SelectedComponent) ); } // controls display yl += Y*15; Canvas->SetDrawColor(64, 64, 255, 255); Canvas->DrawText(RenderFont, TEXT("Controls"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->SetDrawColor(200, 200, 128, 255); Canvas->DrawText(RenderFont, TEXT("FOV +/-: ,/. or DPad Up/Down"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, TEXT("Speed +/-: MouseWheel or +/- or LB/RB"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, TEXT("Freeze Rendering: F or YButton"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, TEXT("Toggle Display: BackSpace or XButton"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; } } }
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; }
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); }
int32 FComponentEditorUtils::DeleteComponents(const TArray<UActorComponent*>& ComponentsToDelete, UActorComponent*& OutComponentToSelect) { int32 NumDeletedComponents = 0; TArray<AActor*> ActorsToReconstruct; for (auto ComponentToDelete : ComponentsToDelete) { if (ComponentToDelete->CreationMethod != EComponentCreationMethod::Instance) { // We can only delete instance components, so retain selection on the un-deletable component OutComponentToSelect = ComponentToDelete; continue; } AActor* Owner = ComponentToDelete->GetOwner(); check(Owner != nullptr); // If necessary, determine the component that should be selected following the deletion of the indicated component if (!OutComponentToSelect || ComponentToDelete == OutComponentToSelect) { USceneComponent* RootComponent = Owner->GetRootComponent(); if (RootComponent != ComponentToDelete) { // Worst-case, the root can be selected OutComponentToSelect = RootComponent; if (auto ComponentToDeleteAsSceneComp = Cast<USceneComponent>(ComponentToDelete)) { if (USceneComponent* ParentComponent = ComponentToDeleteAsSceneComp->GetAttachParent()) { // The component to delete has a parent, so we select that in the absence of an appropriate sibling OutComponentToSelect = ParentComponent; // Try to select the sibling that immediately precedes the component to delete TArray<USceneComponent*> Siblings; ParentComponent->GetChildrenComponents(false, Siblings); for (int32 i = 0; i < Siblings.Num() && ComponentToDelete != Siblings[i]; ++i) { if (!Siblings[i]->IsPendingKill()) { OutComponentToSelect = Siblings[i]; } } } } else { // For a non-scene component, try to select the preceding non-scene component TInlineComponentArray<UActorComponent*> ActorComponents; Owner->GetComponents(ActorComponents); for (int32 i = 0; i < ActorComponents.Num() && ComponentToDelete != ActorComponents[i]; ++i) { if (!ActorComponents[i]->IsA(USceneComponent::StaticClass())) { OutComponentToSelect = ActorComponents[i]; } } } } else { OutComponentToSelect = nullptr; } } // Defer reconstruction ActorsToReconstruct.AddUnique(Owner); // Actually delete the component ComponentToDelete->Modify(); ComponentToDelete->DestroyComponent(true); NumDeletedComponents++; } // Reconstruct owner instance(s) after deletion for(auto ActorToReconstruct : ActorsToReconstruct) { ActorToReconstruct->RerunConstructionScripts(); } return NumDeletedComponents; }
/** * Attempts to apply the material to the specified actor. * * @param TargetActor the actor to apply the material to * @param MaterialToApply the material to apply to the actor * @param OptionalMaterialSlot the material slot to apply to. * * @return true if the material was successfully applied to the actor */ bool FActorFactoryAssetProxy::ApplyMaterialToActor( AActor* TargetActor, UMaterialInterface* MaterialToApply, int32 OptionalMaterialSlot ) { bool bResult = false; if ( TargetActor != NULL && MaterialToApply != NULL ) { ALandscapeProxy* Landscape = Cast<ALandscapeProxy>(TargetActor); if (Landscape != NULL) { UProperty* MaterialProperty = FindField<UProperty>(ALandscapeProxy::StaticClass(), "LandscapeMaterial"); Landscape->PreEditChange(MaterialProperty); Landscape->LandscapeMaterial = MaterialToApply; FPropertyChangedEvent PropertyChangedEvent(MaterialProperty); Landscape->PostEditChangeProperty(PropertyChangedEvent); bResult = true; } else { TArray<UActorComponent*> EditableComponents; FActorEditorUtils::GetEditableComponents( TargetActor, EditableComponents ); // Some actors could potentially have multiple mesh components, so we need to store all of the potentially valid ones // (or else perform special cases with IsA checks on the target actor) TArray<USceneComponent*> FoundMeshComponents; // Find which mesh the user clicked on first. TInlineComponentArray<USceneComponent*> SceneComponents; TargetActor->GetComponents(SceneComponents); for ( int32 ComponentIdx=0; ComponentIdx < SceneComponents.Num(); ComponentIdx++ ) { USceneComponent* SceneComp = SceneComponents[ComponentIdx]; // Only apply the material to editable components. Components which are not exposed are not intended to be changed. if( EditableComponents.Contains( SceneComp ) ) { UMeshComponent* MeshComponent = Cast<UMeshComponent>(SceneComp); if((MeshComponent && MeshComponent->IsRegistered()) || SceneComp->IsA<UDecalComponent>()) { // Intentionally do not break the loop here, as there could be potentially multiple mesh components FoundMeshComponents.AddUnique( SceneComp ); } } } if ( FoundMeshComponents.Num() > 0 ) { // Check each component that was found for ( TArray<USceneComponent*>::TConstIterator MeshCompIter( FoundMeshComponents ); MeshCompIter; ++MeshCompIter ) { USceneComponent* SceneComp = *MeshCompIter; bResult = FComponentEditorUtils::AttemptApplyMaterialToComponent(SceneComp, MaterialToApply, OptionalMaterialSlot); } } } } return bResult; }
/** * Removes the actor from its level's actor list and generally cleans up the engine's internal state. * What this function does not do, but is handled via garbage collection instead, is remove references * to this actor from all other actors, and kill the actor's resources. This function is set up so that * no problems occur even if the actor is being destroyed inside its recursion stack. * * @param ThisActor Actor to remove. * @param bNetForce [opt] Ignored unless called during play. Default is false. * @param bShouldModifyLevel [opt] If true, Modify() the level before removing the actor. Default is true. * @return true if destroy, false if actor couldn't be destroyed. */ bool UWorld::DestroyActor( AActor* ThisActor, bool bNetForce, bool bShouldModifyLevel ) { check(ThisActor); check(ThisActor->IsValidLowLevel()); //UE_LOG(LogSpawn, Log, "Destroy %s", *ThisActor->GetClass()->GetName() ); if (ThisActor->GetWorld() == NULL) { UE_LOG(LogSpawn, Warning, TEXT("Destroying %s, which doesn't have a valid world pointer"), *ThisActor->GetPathName()); } // If already on list to be deleted, pretend the call was successful. // We don't want recursive calls to trigger destruction notifications multiple times. if (ThisActor->IsPendingKillPending()) { return true; } // In-game deletion rules. if( IsGameWorld() ) { // Never destroy the world settings actor. This used to be enforced by bNoDelete and is actually needed for // seamless travel and network games. if (GetWorldSettings() == ThisActor) { return false; } // Can't kill if wrong role. if( ThisActor->Role!=ROLE_Authority && !bNetForce && !ThisActor->bNetTemporary ) { return false; } // Don't destroy player actors. APlayerController* PC = Cast<APlayerController>(ThisActor); if ( PC ) { UNetConnection* C = Cast<UNetConnection>(PC->Player); if( C ) { if( C->Channels[0] && C->State!=USOCK_Closed ) { C->bPendingDestroy = true; C->Channels[0]->Close(); } return false; } } } else { ThisActor->Modify(); } // Prevent recursion //FMarkActorIsBeingDestroyed MarkActorIsBeingDestroyed(ThisActor); // Notify the texture streaming manager about the destruction of this actor. IStreamingManager::Get().NotifyActorDestroyed( ThisActor ); // Tell this actor it's about to be destroyed. ThisActor->Destroyed(); // Detach this actor's children TArray<AActor*> AttachedActors; ThisActor->GetAttachedActors(AttachedActors); if (AttachedActors.Num() > 0) { TInlineComponentArray<USceneComponent*> SceneComponents; ThisActor->GetComponents(SceneComponents); for (TArray< AActor* >::TConstIterator AttachedActorIt(AttachedActors); AttachedActorIt; ++AttachedActorIt) { AActor* ChildActor = *AttachedActorIt; if (ChildActor != NULL) { for (auto SceneCompIter = SceneComponents.CreateIterator(); SceneCompIter; ++SceneCompIter) { ChildActor->DetachSceneComponentsFromParent(*SceneCompIter, true); } #if WITH_EDITOR if( GIsEditor ) { GEngine->BroadcastLevelActorDetached(ChildActor, ThisActor); } #endif } } } // Detach from anything we were attached to USceneComponent* RootComp = ThisActor->GetRootComponent(); if( RootComp != NULL && RootComp->AttachParent != NULL) { AActor* OldParentActor = RootComp->AttachParent->GetOwner(); if (OldParentActor) { OldParentActor->Modify(); } ThisActor->DetachRootComponentFromParent(); #if WITH_EDITOR if( GIsEditor ) { GEngine->BroadcastLevelActorDetached(ThisActor, OldParentActor); } #endif } ThisActor->ClearComponentOverlaps(); // If this actor has an owner, notify it that it has lost a child. if( ThisActor->GetOwner() ) { ThisActor->SetOwner(NULL); } // Notify net players that this guy has been destroyed. UNetDriver* ActorNetDriver = GEngine->FindNamedNetDriver(this, ThisActor->NetDriverName); if (ActorNetDriver) { ActorNetDriver->NotifyActorDestroyed(ThisActor); } if ( DemoNetDriver ) { DemoNetDriver->NotifyActorDestroyed( ThisActor ); } // Remove the actor from the actor list. RemoveActor( ThisActor, bShouldModifyLevel ); // Invalidate the lighting cache in the Editor. We need to check for GIsEditor as play has not begun in network game and objects get destroyed on switching levels if ( GIsEditor ) { ThisActor->InvalidateLightingCache(); #if WITH_EDITOR GEngine->BroadcastLevelActorDeleted(ThisActor); #endif } // Clean up the actor's components. ThisActor->UnregisterAllComponents(); // Mark the actor and its direct components as pending kill. ThisActor->MarkPendingKill(); ThisActor->MarkPackageDirty(); ThisActor->MarkComponentsAsPendingKill(); // Unregister the actor's tick function const bool bRegisterTickFunctions = false; const bool bIncludeComponents = true; ThisActor->RegisterAllActorTickFunctions(bRegisterTickFunctions, bIncludeComponents); // Return success. return true; }
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(); }