// Copyright Epic Games, Inc. All Rights Reserved. #include "ActorHierarchy.h" #include "Engine/Engine.h" #include "Engine/World.h" #include "EngineUtils.h" #include "WorldTreeItem.h" #include "LevelTreeItem.h" #include "ActorTreeItem.h" #include "ActorDescTreeItem.h" #include "ComponentTreeItem.h" #include "ActorFolderTreeItem.h" #include "ISceneOutlinerMode.h" #include "ActorEditorUtils.h" #include "LevelUtils.h" #include "GameFramework/WorldSettings.h" #include "EditorActorFolders.h" #include "EditorFolderUtils.h" #include "LevelInstance/LevelInstanceInterface.h" #include "LevelInstance/LevelInstanceSubsystem.h" #include "Modules/ModuleManager.h" #include "WorldPartition/WorldPartitionHelpers.h" #include "WorldPartition/WorldPartitionActorDesc.h" #include "WorldPartition/IWorldPartitionEditorModule.h" #include "WorldPartition/WorldPartitionSubsystem.h" #include "ActorFolder.h" TUniquePtr FActorHierarchy::Create(ISceneOutlinerMode* Mode, const TWeakObjectPtr& World) { FActorHierarchy* Hierarchy = new FActorHierarchy(Mode, World); GEngine->OnLevelActorAdded().AddRaw(Hierarchy, &FActorHierarchy::OnLevelActorAdded); GEngine->OnLevelActorDeleted().AddRaw(Hierarchy, &FActorHierarchy::OnLevelActorDeleted); GEngine->OnLevelActorDetached().AddRaw(Hierarchy, &FActorHierarchy::OnLevelActorDetached); GEngine->OnLevelActorAttached().AddRaw(Hierarchy, &FActorHierarchy::OnLevelActorAttached); GEngine->OnLevelActorFolderChanged().AddRaw(Hierarchy, &FActorHierarchy::OnLevelActorFolderChanged); GEngine->OnLevelActorListChanged().AddRaw(Hierarchy, &FActorHierarchy::OnLevelActorListChanged); GEngine->OnActorFolderAdded().AddRaw(Hierarchy, &FActorHierarchy::OnActorFolderAdded); GEngine->OnActorFoldersUpdatedEvent().AddRaw(Hierarchy, &FActorHierarchy::OnActorFoldersUpdatedEvent); IWorldPartitionEditorModule& WorldPartitionEditorModule = FModuleManager::LoadModuleChecked("WorldPartitionEditor"); WorldPartitionEditorModule.OnWorldPartitionCreated().AddRaw(Hierarchy, &FActorHierarchy::OnWorldPartitionCreated); if (World.IsValid()) { if (World->PersistentLevel) { World->PersistentLevel->OnLoadedActorAddedToLevelEvent.AddRaw(Hierarchy, &FActorHierarchy::OnLoadedActorAdded); World->PersistentLevel->OnLoadedActorRemovedFromLevelEvent.AddRaw(Hierarchy, &FActorHierarchy::OnLoadedActorRemoved); } World->OnWorldPartitionInitialized().AddRaw(Hierarchy, &FActorHierarchy::OnWorldPartitionInitialized); World->OnWorldPartitionUninitialized().AddRaw(Hierarchy, &FActorHierarchy::OnWorldPartitionUninitialized); if (UWorldPartition* WorldPartition = World->GetWorldPartition()) { WorldPartition->OnActorDescAddedEvent.AddRaw(Hierarchy, &FActorHierarchy::OnActorDescAdded); WorldPartition->OnActorDescRemovedEvent.AddRaw(Hierarchy, &FActorHierarchy::OnActorDescRemoved); } } FWorldDelegates::LevelAddedToWorld.AddRaw(Hierarchy, &FActorHierarchy::OnLevelAdded); FWorldDelegates::LevelRemovedFromWorld.AddRaw(Hierarchy, &FActorHierarchy::OnLevelRemoved); auto& Folders = FActorFolders::Get(); Folders.OnFolderCreated.AddRaw(Hierarchy, &FActorHierarchy::OnBroadcastFolderCreate); Folders.OnFolderMoved.AddRaw(Hierarchy, &FActorHierarchy::OnBroadcastFolderMove); Folders.OnFolderDeleted.AddRaw(Hierarchy, &FActorHierarchy::OnBroadcastFolderDelete); return TUniquePtr(Hierarchy); } FActorHierarchy::FActorHierarchy(ISceneOutlinerMode* Mode, const TWeakObjectPtr& World) : ISceneOutlinerHierarchy(Mode) , RepresentingWorld(World) { } FActorHierarchy::~FActorHierarchy() { if (GEngine) { GEngine->OnLevelActorAdded().RemoveAll(this); GEngine->OnLevelActorDeleted().RemoveAll(this); GEngine->OnLevelActorDetached().RemoveAll(this); GEngine->OnLevelActorAttached().RemoveAll(this); GEngine->OnLevelActorFolderChanged().RemoveAll(this); GEngine->OnLevelActorListChanged().RemoveAll(this); GEngine->OnActorFolderAdded().RemoveAll(this); GEngine->OnActorFoldersUpdatedEvent().RemoveAll(this); } IWorldPartitionEditorModule& WorldPartitionEditorModule = FModuleManager::LoadModuleChecked("WorldPartitionEditor"); WorldPartitionEditorModule.OnWorldPartitionCreated().RemoveAll(this); if (RepresentingWorld.IsValid()) { if (RepresentingWorld->PersistentLevel) { RepresentingWorld->PersistentLevel->OnLoadedActorAddedToLevelEvent.RemoveAll(this); RepresentingWorld->PersistentLevel->OnLoadedActorRemovedFromLevelEvent.RemoveAll(this); } RepresentingWorld->OnWorldPartitionInitialized().RemoveAll(this); RepresentingWorld->OnWorldPartitionUninitialized().RemoveAll(this); if (UWorldPartition* WorldPartition = RepresentingWorld->GetWorldPartition()) { WorldPartition->OnActorDescAddedEvent.RemoveAll(this); WorldPartition->OnActorDescRemovedEvent.RemoveAll(this); } } FWorldDelegates::LevelAddedToWorld.RemoveAll(this); FWorldDelegates::LevelRemovedFromWorld.RemoveAll(this); if (FActorFolders::IsAvailable()) { auto& Folders = FActorFolders::Get(); Folders.OnFolderCreated.RemoveAll(this); Folders.OnFolderMoved.RemoveAll(this); Folders.OnFolderDeleted.RemoveAll(this); } } static FFolder GetFolderPathFromActorDesc(UWorld* InWorld, const FWorldPartitionActorDesc* InActorDesc) { if (UWorld* OuterWorld = InActorDesc->GetContainer() ? InActorDesc->GetContainer()->GetTypedOuter() : InWorld) { ULevel* OuterLevel = OuterWorld->PersistentLevel; if (OuterLevel->IsUsingActorFolders()) { if (UActorFolder* ActorFolder = OuterLevel->GetActorFolder(InActorDesc->GetFolderGuid())) { return ActorFolder->GetFolder(); } return FFolder::GetWorldRootFolder(OuterWorld).GetRootObject(); } return FFolder(FFolder::GetWorldRootFolder(OuterWorld).GetRootObject(), InActorDesc->GetFolderPath()); } return FFolder::GetInvalidFolder(); } FSceneOutlinerTreeItemPtr FActorHierarchy::FindOrCreateParentItem(const ISceneOutlinerTreeItem& Item, const TMap& Items, bool bCreate) { if (Item.IsA()) { return nullptr; } else if (const FActorTreeItem* ActorTreeItem = Item.CastTo()) { if (AActor* Actor = ActorTreeItem->Actor.Get()) { // Parent Actor (Actor attachement / parenting) if (AActor* ParentActor = Actor->GetSceneOutlinerParent()) { if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(ParentActor)) { return *ParentItem; } // If Parent can be listed in SceneOutliner return nullptr so it gets created else if (ParentActor->IsListedInSceneOutliner()) { return bCreate ? Mode->CreateItemFor(ParentActor, true) : nullptr; } } // Parent Folder FFolder Folder = Actor->GetFolder(); if (Mode->ShouldShowFolders() && !Folder.IsNone()) { if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(Folder)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(FActorFolderTreeItem(Folder, ActorTreeItem->Actor->GetWorld()), true) : nullptr; } } // Parent Level Instance if (ILevelInstanceInterface* OwningLevelInstance = Cast(Folder.GetRootObjectPtr())) { const ILevelInstanceInterface* LevelInstance = Cast(Actor); const bool bIsAnEditingLevelInstance = LevelInstance ? LevelInstance->IsEditing() : false; // Parent this to a LevelInstance if the parent LevelInstance is being edited or if this is a sub LevelInstance which is being edited if (bShowingLevelInstances || (OwningLevelInstance->IsEditing() || bIsAnEditingLevelInstance)) { AActor* OwningActor = CastChecked(OwningLevelInstance); if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(OwningActor)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(OwningActor, true) : nullptr; } } } // Parent Level Using Actor Folders ULevel* OwningLevel = Cast(Folder.GetRootObjectPtr()); // For the persistent level, fallback on the world if (OwningLevel && !OwningLevel->IsPersistentLevel()) { if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(OwningLevel)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(OwningLevel, true) : nullptr; } } } } else if (const FActorFolderTreeItem* FolderItem = Item.CastTo()) { // We should never call FindParents on a folder item if folders are not being shown check(Mode->ShouldShowFolders()); const FFolder ParentPath = FolderItem->GetFolder().GetParent(); // Parent Folder if (!ParentPath.IsNone()) { if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(ParentPath)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(FActorFolderTreeItem(ParentPath, FolderItem->World), true) : nullptr; } } // Parent Level Instance else if (ILevelInstanceInterface* OwningLevelInstance = Cast(ParentPath.GetRootObjectPtr())) { if (bShowingLevelInstances || OwningLevelInstance->IsEditing()) { AActor* OwningActor = CastChecked(OwningLevelInstance); if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(OwningActor)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(OwningActor, true) : nullptr; } } } // Parent Level Using Actor Folders else if (ULevel* OwningLevel = Cast(ParentPath.GetRootObjectPtr())) { // For the persistent level, fallback on the world if (!OwningLevel->IsPersistentLevel()) { if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(OwningLevel)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(OwningLevel, true) : nullptr; } } } } else if (const FComponentTreeItem* ComponentTreeItem = Item.CastTo()) { if (AActor* Owner = ComponentTreeItem->Component->GetOwner()) { if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(Owner)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(Owner, true) : nullptr; } } // do not default to world on Component items return nullptr; } else if (const FActorDescTreeItem* ActorDescItem = Item.CastTo()) { if (const FWorldPartitionActorDesc* ActorDesc = ActorDescItem->ActorDescHandle.Get()) { const FFolder ActorDescFolder = GetFolderPathFromActorDesc(RepresentingWorld.Get(), ActorDesc); if (!ActorDescFolder.IsNone()) { if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(ActorDescFolder)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(FActorFolderTreeItem(ActorDescFolder, RepresentingWorld), true) : nullptr; } } // Parent Actor (Actor attachement / parenting) const FGuid& ParentActorGuid = ActorDesc->GetSceneOutlinerParent(); if (ParentActorGuid.IsValid()) { if (UActorDescContainer* ActorDescContainer = ActorDesc->GetContainer()) { if (const FWorldPartitionActorDesc* ParentActorDesc = ActorDescContainer->GetActorDesc(ParentActorGuid)) { // If parent actor is loaded if (AActor* ParentActor = ParentActorDesc->GetActor()) { // Find loaded parent actor node (from the object ptr) if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(ParentActor)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(ParentActor, true) : nullptr; } } // Find unloaded parent actor node (from the guid) if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(ParentActorGuid)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(FActorDescTreeItem(ParentActorGuid, ActorDescContainer)) : nullptr; } } } } else if (UActorDescContainer* ActorDescContainer = ActorDesc->GetContainer()) { const ULevelInstanceSubsystem* LevelInstanceSubsystem = UWorld::GetSubsystem(RepresentingWorld.Get()); UWorld* OuterWorld = ActorDescContainer->GetTypedOuter(); // If parent actor is loaded if (AActor* ParentActor = OuterWorld ? Cast(LevelInstanceSubsystem->GetOwningLevelInstance(OuterWorld->PersistentLevel)) : nullptr) { if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(ParentActor)) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(ParentActor, true) : nullptr; } } } } } // If we get here return world item if (const FSceneOutlinerTreeItemPtr* ParentItem = Items.Find(RepresentingWorld.Get())) { return *ParentItem; } else { return bCreate ? Mode->CreateItemFor(RepresentingWorld.Get(), true) : nullptr; } } void FActorHierarchy::CreateComponentItems(const AActor* Actor, TArray& OutItems) const { check(Actor); // Add all this actors components if showing components and the owning actor was created if (bShowingComponents) { for (UActorComponent* Component : Actor->GetComponents()) { if (Component != nullptr) { if (FSceneOutlinerTreeItemPtr ComponentItem = Mode->CreateItemFor(Component)) { OutItems.Add(ComponentItem); } } } } } void FActorHierarchy::CreateWorldChildren(UWorld* World, TArray& OutItems) const { check(World); if (Mode->ShouldShowFolders()) { // Add any folders which might match the current search terms FActorFolders::Get().ForEachFolder(*World, [this, &World, &OutItems](const FFolder& Folder) { if (FSceneOutlinerTreeItemPtr FolderItem = Mode->CreateItemFor(FActorFolderTreeItem(Folder, World))) { OutItems.Add(FolderItem); } return true; }); } const ULevelInstanceSubsystem* LevelInstanceSubsystem = World->GetSubsystem(); // Create all actor items for (FActorIterator ActorIt(World); ActorIt; ++ActorIt) { AActor* Actor = *ActorIt; // If we are not showing LevelInstances, LevelInstance sub actor items should not be created unless they belong to a LevelInstance which is being edited if (LevelInstanceSubsystem) { if (const ILevelInstanceInterface* ParentLevelInstance = LevelInstanceSubsystem->GetParentLevelInstance(Actor)) { if (!bShowingLevelInstances && !ParentLevelInstance->IsEditing()) { continue; } } } if (FSceneOutlinerTreeItemPtr ActorItem = Mode->CreateItemFor(Actor)) { if (bShowingOnlyActorWithValidComponents) { int32 InsertLocation = OutItems.Num(); // Create all component items CreateComponentItems(Actor, OutItems); if (OutItems.Num() != InsertLocation) { // Add the actor before the components OutItems.Insert(ActorItem, InsertLocation); } } else { OutItems.Add(ActorItem); // Create all component items CreateComponentItems(Actor, OutItems); } } } if (bShowingUnloadedActors) { if (UWorldPartitionSubsystem* WorldPartitionSubsystem = UWorld::GetSubsystem(World)) { WorldPartitionSubsystem->ForEachWorldPartition([this, LevelInstanceSubsystem, &OutItems](UWorldPartition* WorldPartition) { // Skip unloaded actors if they are part of a non editing level instance and the outliner hides the content of level instances if (!bShowingLevelInstances) { UWorld* OuterWorld = WorldPartition->GetTypedOuter(); ULevel* OuterLevel = OuterWorld ? OuterWorld->PersistentLevel : nullptr; ILevelInstanceInterface* LevelInstance = LevelInstanceSubsystem ? LevelInstanceSubsystem->GetOwningLevelInstance(OuterLevel) : nullptr; if (LevelInstance && !LevelInstance->IsEditing()) { return true; } } FWorldPartitionHelpers::ForEachActorDesc(WorldPartition, [this, &OutItems](const FWorldPartitionActorDesc* ActorDesc) { if (ActorDesc != nullptr && !ActorDesc->IsLoaded(true)) { if (const FSceneOutlinerTreeItemPtr ActorDescItem = Mode->CreateItemFor(FActorDescTreeItem(ActorDesc->GetGuid(), ActorDesc->GetContainer()))) { OutItems.Add(ActorDescItem); } } return true; }); return true; }); } } } void FActorHierarchy::CreateItems(TArray& OutItems) const { if (RepresentingWorld.IsValid()) { UWorld* RepresentingWorldPtr = RepresentingWorld.Get(); check(RepresentingWorldPtr); if (FSceneOutlinerTreeItemPtr WorldItem = Mode->CreateItemFor(RepresentingWorldPtr)) { OutItems.Add(WorldItem); } // Create world children regardless of if a world item was created CreateWorldChildren(RepresentingWorldPtr, OutItems); } } void FActorHierarchy::CreateChildren(const FSceneOutlinerTreeItemPtr& Item, TArray& OutChildren) const { auto CreateChildrenFolders = [this](UWorld* InWorld, const FFolder& InParentFolder, const FFolder::FRootObject& InFolderRootObject, TArray& OutChildren) { FActorFolders::Get().ForEachFolderWithRootObject(*InWorld, InFolderRootObject, [this, InWorld, &InParentFolder, &OutChildren](const FFolder& Folder) { if (Folder.IsChildOf(InParentFolder)) { if (FSceneOutlinerTreeItemPtr NewFolderItem = Mode->CreateItemFor(FActorFolderTreeItem(Folder, InWorld))) { OutChildren.Add(NewFolderItem); } } return true; }); }; UWorld* World = RepresentingWorld.Get(); if (FWorldTreeItem* WorldItem = Item->CastTo()) { check(WorldItem->World == RepresentingWorld); CreateWorldChildren(WorldItem->World.Get(), OutChildren); } else if (const FActorTreeItem* ParentActorItem = Item->CastTo()) { AActor* ParentActor = ParentActorItem->Actor.Get(); check(ParentActor->GetWorld() == RepresentingWorld); CreateComponentItems(ParentActor, OutChildren); TArray ChildActors; if (const ILevelInstanceInterface* LevelInstanceParent = Cast(ParentActor)) { const ULevelInstanceSubsystem* LevelInstanceSubsystem = RepresentingWorld->GetSubsystem(); check(LevelInstanceSubsystem); LevelInstanceSubsystem->ForEachActorInLevelInstance(LevelInstanceParent, [this, LevelInstanceParent, LevelInstanceSubsystem, &ChildActors](AActor* SubActor) { const ILevelInstanceInterface* LevelInstance = Cast(SubActor); const bool bIsAnEditingLevelInstance = LevelInstance ? LevelInstanceSubsystem->IsEditingLevelInstance(LevelInstance) : false; if (bShowingLevelInstances || (LevelInstanceSubsystem->IsEditingLevelInstance(LevelInstanceParent) || bIsAnEditingLevelInstance)) { ChildActors.Add(SubActor); } return true; }); check(World == CastChecked(LevelInstanceParent)->GetWorld()); FFolder ParentFolder = ParentActor->GetFolder(); CreateChildrenFolders(World, ParentFolder, ParentActor, OutChildren); } else { TFunction GetAttachedActors = [&ChildActors, &GetAttachedActors](AActor* Child) { ChildActors.Add(Child); Child->ForEachAttachedActors(GetAttachedActors); // Always continue return true; }; // Grab all direct/indirect children of an actor ParentActor->ForEachAttachedActors(GetAttachedActors); } for (auto ChildActor : ChildActors) { if (FSceneOutlinerTreeItemPtr ChildActorItem = Mode->CreateItemFor(ChildActor)) { OutChildren.Add(ChildActorItem); CreateComponentItems(ChildActor, OutChildren); } } } else if (FActorFolderTreeItem* FolderItem = Item->CastTo()) { check(Mode->ShouldShowFolders()); check(World == FolderItem->World.Get()); FFolder ParentFolder = FolderItem->GetFolder(); check(!ParentFolder.IsNone()); CreateChildrenFolders(World, ParentFolder, ParentFolder.GetRootObject(), OutChildren); } } void FActorHierarchy::FullRefreshEvent() { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::FullRefresh; HierarchyChangedEvent.Broadcast(EventData); } void FActorHierarchy::OnWorldPartitionCreated(UWorld* InWorld) { if (RepresentingWorld.Get() == InWorld) { FullRefreshEvent(); } } void FActorHierarchy::OnLevelActorAdded(AActor* InActor) { if (InActor != nullptr && RepresentingWorld.Get() == InActor->GetWorld()) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Added; EventData.Items.Add(Mode->CreateItemFor(InActor)); HierarchyChangedEvent.Broadcast(EventData); } } void FActorHierarchy::OnLevelActorDeleted(AActor* InActor) { if (InActor != nullptr && RepresentingWorld.Get() == InActor->GetWorld()) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Removed; EventData.ItemIDs.Add(InActor); HierarchyChangedEvent.Broadcast(EventData); } } void FActorHierarchy::OnLevelActorAttached(AActor* InActor, const AActor* InParent) { if (InActor != nullptr && RepresentingWorld.Get() == InActor->GetWorld()) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Moved; EventData.ItemIDs.Add(InActor); HierarchyChangedEvent.Broadcast(EventData); } } void FActorHierarchy::OnLevelActorDetached(AActor* InActor, const AActor* InParent) { if (InActor != nullptr && RepresentingWorld.Get() == InActor->GetWorld()) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Moved; EventData.ItemIDs.Add(InActor); HierarchyChangedEvent.Broadcast(EventData); } } void FActorHierarchy::OnLoadedActorAdded(AActor& InActor) { OnLevelActorAdded(&InActor); FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Removed; EventData.ItemIDs.Add(InActor.GetActorGuid()); HierarchyChangedEvent.Broadcast(EventData); } void FActorHierarchy::OnLoadedActorRemoved(AActor& InActor) { OnLevelActorDeleted(&InActor); if (bShowingUnloadedActors) { if (UWorldPartition* WorldPartition = RepresentingWorld->GetWorldPartition()) { const FGuid& ActorGuid = InActor.GetActorGuid(); if (WorldPartition->GetActorDesc(ActorGuid) != nullptr) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Added; EventData.Items.Add(Mode->CreateItemFor(FActorDescTreeItem(ActorGuid, WorldPartition))); HierarchyChangedEvent.Broadcast(EventData); } } } } void FActorHierarchy::OnActorDescAdded(FWorldPartitionActorDesc* ActorDesc) { if (bShowingUnloadedActors && ActorDesc && !ActorDesc->IsLoaded(true)) { if (UWorldPartition* WorldPartition = RepresentingWorld->GetWorldPartition()) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Added; EventData.Items.Add(Mode->CreateItemFor(FActorDescTreeItem(ActorDesc->GetGuid(), WorldPartition))); HierarchyChangedEvent.Broadcast(EventData); } } } void FActorHierarchy::OnActorDescRemoved(FWorldPartitionActorDesc* ActorDesc) { if (bShowingUnloadedActors && ActorDesc) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Removed; EventData.ItemIDs.Add(ActorDesc->GetGuid()); HierarchyChangedEvent.Broadcast(EventData); } } void FActorHierarchy::OnWorldPartitionInitialized(UWorldPartition* InWorldPartition) { FullRefreshEvent(); } void FActorHierarchy::OnWorldPartitionUninitialized(UWorldPartition* InWorldPartition) { FullRefreshEvent(); } void FActorHierarchy::OnComponentsUpdated() { FullRefreshEvent(); } void FActorHierarchy::OnLevelActorListChanged() { FullRefreshEvent(); } void FActorHierarchy::OnActorFoldersUpdatedEvent(ULevel* InLevel) { FullRefreshEvent(); } void FActorHierarchy::OnActorFolderAdded(UActorFolder* InActorFolder) { check(InActorFolder); ULevel* Level = InActorFolder->GetOuterULevel(); if (Level && Mode->ShouldShowFolders() && (RepresentingWorld.Get() == Level->GetWorld())) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Added; EventData.Items.Add(Mode->CreateItemFor(FActorFolderTreeItem(InActorFolder->GetFolder(), RepresentingWorld))); HierarchyChangedEvent.Broadcast(EventData); } } void FActorHierarchy::OnLevelAdded(ULevel* InLevel, UWorld* InWorld) { if (InLevel != nullptr && RepresentingWorld.Get() == InWorld) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Added; EventData.Items.Reserve(InLevel->Actors.Num()); for (AActor* Actor : InLevel->Actors) { if (Actor != nullptr) { EventData.Items.Add(Mode->CreateItemFor(Actor)); } } HierarchyChangedEvent.Broadcast(EventData); } } void FActorHierarchy::OnLevelRemoved(ULevel* InLevel, UWorld* InWorld) { if (InLevel != nullptr && RepresentingWorld.Get() == InWorld) { { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Removed; EventData.ItemIDs.Reserve(InLevel->Actors.Num()); for (AActor* Actor : InLevel->Actors) { if (Actor != nullptr) { EventData.ItemIDs.Add(Actor); } } HierarchyChangedEvent.Broadcast(EventData); } // If either this level or the owning world are using actor folders, remove level's actor folders if (InLevel->IsUsingActorFolders() || InWorld->PersistentLevel->IsUsingActorFolders()) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Removed; EventData.ItemIDs.Add(InLevel); HierarchyChangedEvent.Broadcast(EventData); } } } /** Called when a folder is to be created */ void FActorHierarchy::OnBroadcastFolderCreate(UWorld& InWorld, const FFolder& InNewFolder) { if (Mode->ShouldShowFolders() && RepresentingWorld.Get() == &InWorld) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Added; EventData.Items.Add(Mode->CreateItemFor(FActorFolderTreeItem(InNewFolder, &InWorld))); EventData.ItemActions = SceneOutliner::ENewItemAction::Select | SceneOutliner::ENewItemAction::Rename; HierarchyChangedEvent.Broadcast(EventData); } } /** Called when a folder is to be moved */ void FActorHierarchy::OnBroadcastFolderMove(UWorld& InWorld, const FFolder& InOldFolder, const FFolder& InNewFolder) { if (Mode->ShouldShowFolders() && RepresentingWorld.Get() == &InWorld) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::FolderMoved; EventData.ItemIDs.Add(InOldFolder); EventData.NewPaths.Add(InNewFolder); HierarchyChangedEvent.Broadcast(EventData); } } /** Called when a folder is to be deleted */ void FActorHierarchy::OnBroadcastFolderDelete(UWorld& InWorld, const FFolder& InFolder) { if (Mode->ShouldShowFolders() && RepresentingWorld.Get() == &InWorld) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Removed; EventData.ItemIDs.Add(InFolder); HierarchyChangedEvent.Broadcast(EventData); } } void FActorHierarchy::OnLevelActorFolderChanged(const AActor* InActor, FName OldPath) { if (Mode->ShouldShowFolders() && RepresentingWorld.Get() == InActor->GetWorld()) { FSceneOutlinerHierarchyChangedData EventData; EventData.Type = FSceneOutlinerHierarchyChangedData::Moved; EventData.ItemIDs.Add(FSceneOutlinerTreeItemID(InActor)); HierarchyChangedEvent.Broadcast(EventData); } }