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(); } } }
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; }
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); } } } } } }
PyObject *py_ue_get_actor_component(ue_PyUObject * self, PyObject * args) { ue_py_check(self); AActor *actor = ue_get_actor(self); if (!actor) return PyErr_Format(PyExc_Exception, "cannot retrieve Actor from uobject"); char *name; if (!PyArg_ParseTuple(args, "s:get_actor_component", &name)) { return NULL; } for (UActorComponent *component : actor->GetComponents()) { if (component->GetName().Equals(UTF8_TO_TCHAR(name))) { Py_RETURN_UOBJECT(component); } } Py_RETURN_NONE; }
void SGraphPinLiveEditVar::GenerateComboBoxIndexes( TArray< TSharedPtr<int32> >& OutComboBoxIndexes ) { if ( !NodeClass.IsValid() ) return; UClass *InClass = Cast<UClass>(NodeClass.Get()); if ( InClass == NULL ) return; GenerateComboBoxIndexesRecurse( InClass, FString(TEXT("")), OutComboBoxIndexes ); AActor *AsActor = Cast<AActor>(InClass->ClassDefaultObject); if ( AsActor != NULL ) { TArray<UActorComponent*> ActorComponents; AsActor->GetComponents(ActorComponents); for ( TArray<UActorComponent*>::TIterator ComponentIt(ActorComponents); ComponentIt; ++ComponentIt ) { UActorComponent *Component = *ComponentIt; check( Component != NULL ); FString ComponentName = Component->GetName() + FString(TEXT(".")); GenerateComboBoxIndexesRecurse( Component->GetClass(), ComponentName, OutComboBoxIndexes ); } } for (int32 i = 0; i < VariableNameList.Num(); ++i) { TSharedPtr<int32> EnumIdxPtr(new int32(i)); OutComboBoxIndexes.Add(EnumIdxPtr); } }
void AddTickDependency(FTickFunction& BasedObjectTick, UPrimitiveComponent* NewBase) { if (NewBase && MovementBaseUtility::UseRelativeLocation(NewBase)) { if (NewBase->PrimaryComponentTick.bCanEverTick) { BasedObjectTick.AddPrerequisite(NewBase, NewBase->PrimaryComponentTick); } AActor* NewBaseOwner = NewBase->GetOwner(); if (NewBaseOwner) { if (NewBaseOwner->PrimaryActorTick.bCanEverTick) { BasedObjectTick.AddPrerequisite(NewBaseOwner, NewBaseOwner->PrimaryActorTick); } // @TODO: We need to find a more efficient way of finding all ticking components in an actor. for (UActorComponent* Component : NewBaseOwner->GetComponents()) { if (Component && Component->PrimaryComponentTick.bCanEverTick) { BasedObjectTick.AddPrerequisite(Component, Component->PrimaryComponentTick); } } } } }
PyObject *py_ue_get_actor_component(ue_PyUObject * self, PyObject * args) { ue_py_check(self); AActor *actor = ue_get_actor(self); if (!actor) return PyErr_Format(PyExc_Exception, "cannot retrieve Actor from uobject"); char *name; if (!PyArg_ParseTuple(args, "s:get_actor_component", &name)) { return NULL; } for (UActorComponent *component : actor->GetComponents()) { if (component->GetName().Equals(UTF8_TO_TCHAR(name))) { ue_PyUObject *py_obj = ue_get_python_wrapper(component); if (!py_obj) return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state"); Py_INCREF(py_obj); return (PyObject *)py_obj; } } Py_INCREF(Py_None); return Py_None; }
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 UActorRecording::GetSceneComponents(TArray<USceneComponent*>& OutArray, bool bIncludeNonCDO/*=true*/) { // it is not enough to just go through the owned components array here // we need to traverse the scene component hierarchy as well, as some components may be // owned by other actors (e.g. for pooling) and some may not be part of the hierarchy if(GetActorToRecord() != nullptr) { USceneComponent* RootComponent = GetActorToRecord()->GetRootComponent(); if(RootComponent) { // note: GetChildrenComponents clears array! RootComponent->GetChildrenComponents(true, OutArray); OutArray.Add(RootComponent); } // add owned components that are *not* part of the hierarchy TInlineComponentArray<USceneComponent*> OwnedComponents(GetActorToRecord()); for(USceneComponent* OwnedComponent : OwnedComponents) { check(OwnedComponent); if(OwnedComponent->GetAttachParent() == nullptr && OwnedComponent != RootComponent) { OutArray.Add(OwnedComponent); } } if(!bIncludeNonCDO) { AActor* CDO = Cast<AActor>(GetActorToRecord()->GetClass()->GetDefaultObject()); auto ShouldRemovePredicate = [&](UActorComponent* PossiblyRemovedComponent) { // try to find a component with this name in the CDO for (UActorComponent* SearchComponent : CDO->GetComponents()) { if (SearchComponent->GetClass() == PossiblyRemovedComponent->GetClass() && SearchComponent->GetFName() == PossiblyRemovedComponent->GetFName()) { return false; } } // remove if its not found return true; }; OutArray.RemoveAllSwap(ShouldRemovePredicate); } } }
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; }
UObject* FSequencerPossessedObject::GetObject() const { // get component-less object if (ComponentName.IsEmpty()) { return ObjectOrOwner.Get(); } // get cached component if ((CachedComponent != nullptr) && (CachedComponent->GetName() == ComponentName)) { return CachedComponent; } CachedComponent = nullptr; // find & cache component UObject* Object = ObjectOrOwner.Get(); if (Object == nullptr) { return nullptr; } AActor* Owner = Cast<AActor>(Object); if (Owner == nullptr) { return Object; } for (UActorComponent* ActorComponent : Owner->GetComponents()) { if (ActorComponent->GetName() == ComponentName) { CachedComponent = ActorComponent; return ActorComponent; } } // component not found return nullptr; }
PyObject *py_ue_actor_components(ue_PyUObject * self, PyObject * args) { ue_py_check(self); AActor *actor = ue_get_actor(self); if (!actor) return PyErr_Format(PyExc_Exception, "cannot retrieve Actor from uobject"); PyObject *ret = PyList_New(0); for (UActorComponent *component : actor->GetComponents()) { ue_PyUObject *py_obj = ue_get_python_wrapper(component); if (!py_obj) continue; PyList_Append(ret, (PyObject *)py_obj); } return ret; }
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 FSequencerAssetEditor::ExtendSequencerAddTrackMenu( FMenuBuilder& AddTrackMenuBuilder, TArray<UObject*> ContextObjects ) { if ( ContextObjects.Num() == 1 ) { AActor* Actor = Cast<AActor>( ContextObjects[0] ); if ( Actor != nullptr ) { AddTrackMenuBuilder.BeginSection( "Components", LOCTEXT( "ComponentsSection", "Components" ) ); { for ( UActorComponent* Component : Actor->GetComponents() ) { FUIAction AddComponentAction( FExecuteAction::CreateSP( this, &FSequencerAssetEditor::AddComponentTrack, Component ) ); FText AddComponentLabel = FText::FromString(Component->GetName()); FText AddComponentToolTip = FText::Format( LOCTEXT( "ComponentToolTipFormat", "Add {0} component" ), FText::FromString( Component->GetName() ) ); AddTrackMenuBuilder.AddMenuEntry( AddComponentLabel, AddComponentToolTip, FSlateIcon(), AddComponentAction ); } } AddTrackMenuBuilder.EndSection(); } } }
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 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); TArray<UActorComponent*> ActorComponents; AsActor->GetComponents(ActorComponents); for ( TArray<UActorComponent*>::TIterator ComponentIt(ActorComponents); 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; TArray<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*)GEditorModeTools().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; AssetPickerConfig.ThumbnailScale = 0.0f; // 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(); EntryPopupWindow = FSlateApplication::Get().PushMenu( Parent.ToSharedRef(), 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 ); } } } } }
UPrimitiveComponent* UPhysicsConstraintComponent::GetComponentInternal(EConstraintFrame::Type Frame) const { UPrimitiveComponent* PrimComp = NULL; FName ComponentName = NAME_None; AActor* Actor = NULL; // Frame 1 if(Frame == EConstraintFrame::Frame1) { // Use override component if specified if(OverrideComponent1.IsValid()) { return OverrideComponent1.Get(); } ComponentName = ComponentName1.ComponentName; Actor = ConstraintActor1; } // Frame 2 else { // Use override component if specified if(OverrideComponent2.IsValid()) { return OverrideComponent2.Get(); } ComponentName = ComponentName2.ComponentName; Actor = ConstraintActor2; } // If neither actor nor component name specified, joint to 'world' if(Actor != NULL || ComponentName != NAME_None) { // If no actor specified, but component name is - use Owner if(Actor == NULL) { Actor = GetOwner(); } // If we now have an Actor, lets find a component if(Actor != NULL) { // No name specified, use the root component if(ComponentName == NAME_None) { PrimComp = Cast<UPrimitiveComponent>(Actor->GetRootComponent()); } // Name specified, see if we can find that component.. else { for(UActorComponent* Comp : Actor->GetComponents()) { if(Comp->GetFName() == ComponentName) { PrimComp = Cast<UPrimitiveComponent>(Comp); break; } } } } } return PrimComp; }
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* 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 USimpleConstructionScript::FixupRootNodeParentReferences() { // Get the BlueprintGeneratedClass that owns the SCS UClass* BPGeneratedClass = GetOwnerClass(); if(BPGeneratedClass == NULL) { UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::FixupRootNodeParentReferences() - owner class is NULL; skipping.")); // cannot do the rest of fixup without a BPGC return; } for (int32 NodeIndex=0; NodeIndex < RootNodes.Num(); ++NodeIndex) { // If this root node is parented to a native/inherited component template USCS_Node* RootNode = RootNodes[NodeIndex]; if(RootNode->ParentComponentOrVariableName != NAME_None) { bool bWasFound = false; // If the node is parented to a native component if(RootNode->bIsParentComponentNative) { // Get the Blueprint class default object AActor* CDO = Cast<AActor>(BPGeneratedClass->GetDefaultObject(false)); if(CDO != NULL) { // Look for the parent component in the CDO's components array TInlineComponentArray<UActorComponent*> Components; CDO->GetComponents(Components); for (auto CompIter = Components.CreateConstIterator(); CompIter && !bWasFound; ++CompIter) { UActorComponent* ComponentTemplate = *CompIter; bWasFound = ComponentTemplate->GetFName() == RootNode->ParentComponentOrVariableName; } } else { // SCS and BGClass depends on each other (while their construction). // Class is not ready, so one have to break the dependency circle. continue; } } // Otherwise the node is parented to an inherited SCS node from a parent Blueprint else { // Get the Blueprint hierarchy TArray<const UBlueprintGeneratedClass*> ParentBPClassStack; const bool bErrorFree = UBlueprintGeneratedClass::GetGeneratedClassesHierarchy(BPGeneratedClass, ParentBPClassStack); // Find the parent Blueprint in the hierarchy for(int32 StackIndex = ParentBPClassStack.Num() - 1; StackIndex > 0; --StackIndex) { const UBlueprintGeneratedClass* ParentClass = ParentBPClassStack[StackIndex]; if( ParentClass != NULL && ParentClass->SimpleConstructionScript != NULL && ParentClass->GetFName() == RootNode->ParentComponentOwnerClassName) { // Attempt to locate a match by searching all the nodes that belong to the parent Blueprint's SCS for (USCS_Node* ParentNode : ParentClass->SimpleConstructionScript->GetAllNodes()) { if (ParentNode != nullptr && ParentNode->VariableName == RootNode->ParentComponentOrVariableName) { bWasFound = true; break; } } // We found a match; no need to continue searching the hierarchy break; } } } // Clear parent info if we couldn't find the parent component instance if(!bWasFound) { UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::FixupRootNodeParentReferences() - Couldn't find %s parent component '%s' for '%s' in BlueprintGeneratedClass '%s' (it may have been removed)"), RootNode->bIsParentComponentNative ? TEXT("native") : TEXT("inherited"), *RootNode->ParentComponentOrVariableName.ToString(), *RootNode->GetVariableName().ToString(), *BPGeneratedClass->GetName()); RootNode->bIsParentComponentNative = false; RootNode->ParentComponentOrVariableName = NAME_None; RootNode->ParentComponentOwnerClassName = NAME_None; } } } // call this after we do the above ParentComponentOrVariableName fixup, // because this operates differently for root nodes that have their // ParentComponentOrVariableName field cleared // // repairs invalid scene hierarchies (like when this Blueprint has been // reparented and there is no longer an inherited scene root... meaning one // of the scene component nodes here needs to be promoted) FixupSceneNodeHierarchy(); }
void UActorRecording::StartRecordingActorProperties(ULevelSequence* CurrentSequence, float CurrentSequenceTime) { if(CurrentSequence != nullptr) { // set up our spawnable or possessable for this actor UMovieScene* MovieScene = CurrentSequence->GetMovieScene(); AActor* Actor = GetActorToRecord(); if (bRecordToPossessable) { Guid = MovieScene->AddPossessable(Actor->GetActorLabel(), Actor->GetClass()); CurrentSequence->BindPossessableObject(Guid, *Actor, Actor->GetWorld()); } else { FString TemplateName = GetUniqueSpawnableName(MovieScene, Actor->GetName()); AActor* ObjectTemplate = CastChecked<AActor>(CurrentSequence->MakeSpawnableTemplateFromInstance(*Actor, *TemplateName)); if (ObjectTemplate) { TInlineComponentArray<USkeletalMeshComponent*> SkeletalMeshComponents; ObjectTemplate->GetComponents(SkeletalMeshComponents); for (USkeletalMeshComponent* SkeletalMeshComponent : SkeletalMeshComponents) { SkeletalMeshComponent->SetAnimationMode(EAnimationMode::AnimationSingleNode); SkeletalMeshComponent->bEnableUpdateRateOptimizations = false; SkeletalMeshComponent->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::AlwaysTickPoseAndRefreshBones; SkeletalMeshComponent->ForcedLodModel = 1; } Guid = MovieScene->AddSpawnable(TemplateName, *ObjectTemplate); } } // now add tracks to record if(Guid.IsValid()) { // add our folder FindOrAddFolder(MovieScene); // force set recording to record translations as we need this with no animation UMovieScene3DTransformSectionRecorderSettings* TransformSettings = ActorSettings.GetSettingsObject<UMovieScene3DTransformSectionRecorderSettings>(); check(TransformSettings); TransformSettings->bRecordTransforms = true; // grab components so we can track attachments // don't include non-CDO here as they wont be part of our initial BP (duplicated above) // we will catch these 'extra' components on the first tick const bool bIncludeNonCDO = false; SyncTrackedComponents(bIncludeNonCDO); TInlineComponentArray<USceneComponent*> SceneComponents(GetActorToRecord()); // check if components need recording TInlineComponentArray<USceneComponent*> ValidSceneComponents; for(TWeakObjectPtr<USceneComponent>& SceneComponent : TrackedComponents) { if(ValidComponent(SceneComponent.Get())) { ValidSceneComponents.Add(SceneComponent.Get()); // add all parent components too TArray<USceneComponent*> ParentComponents; SceneComponent->GetParentComponents(ParentComponents); for(USceneComponent* ParentComponent : ParentComponents) { ValidSceneComponents.AddUnique(ParentComponent); } } } ProcessNewComponentArray(ValidSceneComponents); TSharedPtr<FMovieSceneAnimationSectionRecorder> FirstAnimRecorder = nullptr; for(USceneComponent* SceneComponent : ValidSceneComponents) { TSharedPtr<FMovieSceneAnimationSectionRecorder> AnimRecorder = StartRecordingComponentProperties(SceneComponent->GetFName(), SceneComponent, GetActorToRecord(), CurrentSequence, CurrentSequenceTime, AnimationSettings); if(!FirstAnimRecorder.IsValid() && AnimRecorder.IsValid() && GetActorToRecord()->IsA<ACharacter>()) { FirstAnimRecorder = AnimRecorder; } } // we need to create a transform track even if we arent recording transforms if (FSequenceRecorder::Get().GetTransformRecorderFactory().CanRecordObject(GetActorToRecord())) { TSharedPtr<IMovieSceneSectionRecorder> Recorder = FSequenceRecorder::Get().GetTransformRecorderFactory().CreateSectionRecorder(TransformSettings->bRecordTransforms, FirstAnimRecorder); if(Recorder.IsValid()) { Recorder->CreateSection(GetActorToRecord(), MovieScene, Guid, CurrentSequenceTime); Recorder->Record(CurrentSequenceTime); SectionRecorders.Add(Recorder); } } TArray<IMovieSceneSectionRecorderFactory*> ModularFeatures = IModularFeatures::Get().GetModularFeatureImplementations<IMovieSceneSectionRecorderFactory>(MovieSceneSectionRecorderFactoryName); for (IMovieSceneSectionRecorderFactory* Factory : ModularFeatures) { if (Factory->CanRecordObject(GetActorToRecord())) { TSharedPtr<IMovieSceneSectionRecorder> Recorder = Factory->CreateSectionRecorder(ActorSettings); if (Recorder.IsValid()) { Recorder->CreateSection(GetActorToRecord(), MovieScene, Guid, CurrentSequenceTime); Recorder->Record(CurrentSequenceTime); SectionRecorders.Add(Recorder); } } } } } }
void FActorReplacementHelper::Finalize(const TMap<UObject*, UObject*>& OldToNewInstanceMap) { // because this is an editor context it's important to use this execution guard FEditorScriptExecutionGuard ScriptGuard; // run the construction script, which will use the properties we just copied over if (CachedActorData.IsValid()) { CachedActorData->ComponentInstanceData.FindAndReplaceInstances(OldToNewInstanceMap); NewActor->ExecuteConstruction(TargetWorldTransform, &CachedActorData->ComponentInstanceData); } else { FComponentInstanceDataCache DummyComponentData; NewActor->ExecuteConstruction(TargetWorldTransform, &DummyComponentData); } if (TargetAttachParent) { UObject* const* NewTargetAttachParent = OldToNewInstanceMap.Find(TargetAttachParent); if (NewTargetAttachParent) { TargetAttachParent = CastChecked<AActor>(*NewTargetAttachParent); } } if (TargetParentComponent) { UObject* const* NewTargetParentComponent = OldToNewInstanceMap.Find(TargetParentComponent); if (NewTargetParentComponent) { TargetParentComponent = CastChecked<USceneComponent>(*NewTargetParentComponent); } } ApplyAttachments(OldToNewInstanceMap); if (bSelectNewActor) { GEditor->SelectActor(NewActor, /*bInSelected =*/true, /*bNotify =*/true); } TMap<UObject*, UObject*> ConstructedComponentReplacementMap; for (UActorComponent* NewActorComponent : NewActor->GetComponents()) { if (NewActorComponent) { if (UActorComponent** OldActorComponent = OldActorComponentNameMap.Find(NewActorComponent->GetFName())) { ConstructedComponentReplacementMap.Add(*OldActorComponent, NewActorComponent); } } } GEditor->NotifyToolsOfObjectReplacement(ConstructedComponentReplacementMap); // Destroy actor and clear references. NewActor->Modify(); if (GEditor->Layers.IsValid()) // ensure(NULL != GEditor->Layers) ?? While cooking the Layers is NULL. { GEditor->Layers->InitializeNewActorLayers(NewActor); } }
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 != NULL && RootComp->AttachParent != NULL) { 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; }
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; }
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; }
bool UBlueprintThumbnailRenderer::CanVisualizeBlueprint(class UBlueprint* Blueprint) { if ( ThumbnailScene == nullptr ) { ThumbnailScene = new FBlueprintThumbnailScene(); } // Only visualize actor based blueprints if ( Blueprint->GeneratedClass && Blueprint->GeneratedClass->IsChildOf(AActor::StaticClass()) ) { // Try to find any visible primitive components in the native class' CDO AActor* CDO = Blueprint->GeneratedClass->GetDefaultObject<AActor>(); TArray<UActorComponent*> Components; CDO->GetComponents(Components); for ( auto CompIt = Components.CreateConstIterator(); CompIt; ++CompIt ) { if ( ThumbnailScene->IsValidComponentForVisualization(*CompIt) ) { return true; } } // Try to find any visible primitive components in the simple construction script // Do this for all parent blueprint generated classes as well UBlueprint* BlueprintToHarvestComponents = Blueprint; TSet<UBlueprint*> AllVisitedBlueprints; while ( BlueprintToHarvestComponents ) { AllVisitedBlueprints.Add(BlueprintToHarvestComponents); if ( BlueprintToHarvestComponents->SimpleConstructionScript ) { TArray<USCS_Node*> AllNodes = BlueprintToHarvestComponents->SimpleConstructionScript->GetAllNodes(); for ( auto NodeIt = AllNodes.CreateConstIterator(); NodeIt; ++NodeIt ) { if ( ThumbnailScene->IsValidComponentForVisualization((*NodeIt)->ComponentTemplate) ) { return true; } } } UClass* ParentClass = BlueprintToHarvestComponents->ParentClass; BlueprintToHarvestComponents = nullptr; // If the parent class was a blueprint generated class, check it's simple construction script components as well if ( ParentClass ) { UBlueprint* ParentBlueprint = Cast<UBlueprint>(ParentClass->ClassGeneratedBy); // Also make sure we haven't visited the blueprint already. This would only happen if there was a loop of parent classes. if ( ParentBlueprint && !AllVisitedBlueprints.Contains(ParentBlueprint) ) { BlueprintToHarvestComponents = ParentBlueprint; } } } } return false; }