EM_Task/UnrealEd/Private/Layers/LayersSubsystem.cpp
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

1383 lines
41 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Layers/LayersSubsystem.h"
#include "Engine/Brush.h"
#include "Components/PrimitiveComponent.h"
#include "Layers/Layer.h"
#include "LevelEditorViewport.h"
#include "Misc/IFilter.h"
#include "Engine/Selection.h"
#include "Engine/World.h"
#include "EngineUtils.h"
#include "Editor.h"
#include "ActorEditorUtils.h"
class FLayersBroadcast
{
public:
/**
* Constructor
*/
FLayersBroadcast(ULayersSubsystem* InLayersSubsystem);
/**
* Destructor
*/
~FLayersBroadcast();
void Deinitialize();
private:
void Initialize();
/**
* Delegate handler for FEditorDelegates::MapChange. It internally calls LayersSubsystem->EditorMapChange().
**/
void OnEditorMapChange(uint32 MapChangeFlags = 0);
/**
* Delegate handler for FEditorDelegates::RefreshLayerBrowser. It internally calls LayersSubsystem->EditorRefreshLayerBrowser() to refresh the actors of each layer.
**/
void OnEditorRefreshLayerBrowser();
ULayersSubsystem* LayersSubsystem;
bool bIsInitialized;
};
FLayersBroadcast::FLayersBroadcast(ULayersSubsystem* InLayersSubsystem)
: LayersSubsystem(InLayersSubsystem), bIsInitialized(false)
{
Initialize();
}
FLayersBroadcast::~FLayersBroadcast()
{
Deinitialize();
}
void FLayersBroadcast::Deinitialize()
{
if (bIsInitialized)
{
bIsInitialized = false;
// Remove all callback functions from FEditorDelegates::MapChange.Broadcast() and FEditorDelegates::RefreshLayerBrowser.Broadcast()
FEditorDelegates::MapChange.RemoveAll(this);
FEditorDelegates::RefreshLayerBrowser.RemoveAll(this);
}
}
void FLayersBroadcast::Initialize()
{
if (!bIsInitialized)
{
bIsInitialized = true;
// Add callback function to FEditorDelegates::MapChange.Broadcast() and FEditorDelegates::RefreshLayerBrowser.Broadcast()
FEditorDelegates::MapChange.AddRaw(this, &FLayersBroadcast::OnEditorMapChange);
FEditorDelegates::RefreshLayerBrowser.AddRaw(this, &FLayersBroadcast::OnEditorRefreshLayerBrowser);
}
}
void FLayersBroadcast::OnEditorMapChange(uint32 MapChangeFlags)
{
LayersSubsystem->EditorMapChange();
}
void FLayersBroadcast::OnEditorRefreshLayerBrowser()
{
LayersSubsystem->EditorRefreshLayerBrowser();
}
void ULayersSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
// Subsystems are loaded, so we can set up the broadcast functions for GetEditorSubsystem<ULayersSubsystem>()
LayersBroadcast = MakeShareable(new FLayersBroadcast(this));
}
void ULayersSubsystem::Deinitialize()
{
Super::Deinitialize();
LayersBroadcast->Deinitialize();
}
ULayersSubsystem::~ULayersSubsystem()
{
}
void ULayersSubsystem::EditorMapChange()
{
LayersChanged.Broadcast(ELayersAction::Reset, NULL, NAME_None);
}
void ULayersSubsystem::EditorRefreshLayerBrowser()
{
// bNotifySelectionChange is false because the functions calling FEditorDelegates::RefreshLayerBrowser.Broadcast usually call GEditor->NoteSelectionChange
const bool bNotifySelectionChange = false;
const bool bRedrawViewports = false;
UpdateAllActorsVisibility(bNotifySelectionChange, bRedrawViewports);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Operations on Levels
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ULayersSubsystem::AddLevelLayerInformation(ULevel* Level)
{
if (Level)
{
for (auto ActorIter = Level->Actors.CreateConstIterator(); ActorIter; ++ActorIter)
{
InitializeNewActorLayers(*ActorIter);
}
}
}
void ULayersSubsystem::RemoveLevelLayerInformation(ULevel* Level)
{
if (Level)
{
for (auto ActorIter = Level->Actors.CreateConstIterator(); ActorIter; ++ActorIter)
{
DisassociateActorFromLayers(*ActorIter);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Operations on an individual actor.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ULayersSubsystem::IsActorValidForLayer(AActor* Actor)
{
if (!Actor || Actor->GetClass() == nullptr || Actor->GetWorld() == nullptr)
{
return false;
}
const bool bIsBuilderBrush = FActorEditorUtils::IsABuilderBrush(Actor);
const bool bIsHidden = (Actor->GetClass()->GetDefaultObject<AActor>()->bHiddenEd == true);
const bool bIsInEditorWorld = (Actor->GetWorld()->WorldType == EWorldType::Editor);
const bool bIsValid = !bIsHidden && !bIsBuilderBrush && bIsInEditorWorld;
return bIsValid;
}
bool ULayersSubsystem::InitializeNewActorLayers(AActor* Actor)
{
if (!IsActorValidForLayer(Actor))
{
return false;
}
for (auto LayerNameIt = Actor->Layers.CreateConstIterator(); LayerNameIt; ++LayerNameIt)
{
const FName LayerName = *LayerNameIt;
ULayer* Layer = EnsureLayerExists(LayerName);
Layer->Modify();
AddActorToStats(Layer, Actor);
}
// update per-view visibility info
UpdateActorAllViewsVisibility(Actor);
// update general actor visibility
bool bActorModified = false;
bool bActorSelectionChanged = false;
const bool bActorNotifySelectionChange = true;
const bool bActorRedrawViewports = false;
UpdateActorVisibility(Actor, bActorSelectionChanged, bActorModified, bActorNotifySelectionChange, bActorRedrawViewports);
return Actor->Layers.Num() > 0;
}
bool ULayersSubsystem::DisassociateActorFromLayers(AActor* Actor)
{
if (!IsActorValidForLayer(Actor))
{
return false;
}
bool bChangeOccurred = false;
for (auto LayerNameIt = Actor->Layers.CreateConstIterator(); LayerNameIt; ++LayerNameIt)
{
const FName LayerName = *LayerNameIt;
ULayer* Layer = EnsureLayerExists(LayerName);
Layer->Modify();
RemoveActorFromStats(Layer, Actor);
bChangeOccurred = true;
}
return bChangeOccurred;
}
UWorld* ULayersSubsystem::GetWorld() const
{
return GWorld;
}
bool ULayersSubsystem::AddActorToLayer(AActor* Actor, const FName& LayerName)
{
TArray<AActor*> Actors;
Actors.Add(Actor);
TArray<FName> LayerNames;
LayerNames.Add(LayerName);
return AddActorsToLayers(Actors, LayerNames);
}
bool ULayersSubsystem::AddActorToLayers(AActor* Actor, const TArray<FName>& LayerNames)
{
TArray<AActor*> Actors;
Actors.Add(Actor);
return AddActorsToLayers(Actors, LayerNames);
}
bool ULayersSubsystem::AddActorsToLayer(const TArray<AActor*>& Actors, const FName& LayerName)
{
TArray<FName> LayerNames;
LayerNames.Add(LayerName);
return AddActorsToLayers(Actors, LayerNames);
}
bool ULayersSubsystem::AddActorsToLayer(const TArray<TWeakObjectPtr<AActor>>& Actors, const FName& LayerName)
{
TArray<FName> LayerNames;
LayerNames.Add(LayerName);
return AddActorsToLayers(Actors, LayerNames);
}
bool ULayersSubsystem::AddActorsToLayers(const TArray<AActor*>& Actors, const TArray<FName>& LayerNames)
{
bool bChangesOccurred = false;
if (LayerNames.Num() > 0)
{
GEditor->GetSelectedActors()->BeginBatchSelectOperation();
for (auto ActorIt = Actors.CreateConstIterator(); ActorIt; ++ActorIt)
{
AActor* Actor = *ActorIt;
if (!IsActorValidForLayer(Actor))
{
continue;
}
bool bActorWasModified = false;
for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt)
{
const FName& LayerName = *LayerNameIt;
if (!Actor->Layers.Contains(LayerName))
{
if (!bActorWasModified)
{
Actor->Modify();
bActorWasModified = true;
}
ULayer* Layer = EnsureLayerExists(LayerName);
Actor->Layers.Add(LayerName);
Layer->Modify();
AddActorToStats(Layer, Actor);
}
} // END Iteration over Layers
if (bActorWasModified)
{
// update per-view visibility info
UpdateActorAllViewsVisibility(Actor);
// update general actor visibility
bool bActorModified = false;
bool bActorSelectionChanged = false;
const bool bActorNotifySelectionChange = true;
const bool bActorRedrawViewports = false;
UpdateActorVisibility(Actor, bActorSelectionChanged, bActorModified, bActorNotifySelectionChange, bActorRedrawViewports);
bChangesOccurred = true;
}
} // END Iteration over Actors
GEditor->GetSelectedActors()->EndBatchSelectOperation();
}
return bChangesOccurred;
}
bool ULayersSubsystem::AddActorsToLayers(const TArray<TWeakObjectPtr<AActor>>& Actors, const TArray<FName>& LayerNames)
{
TArray<AActor*> ActorsRawPtr;
for (auto ActorIt = Actors.CreateConstIterator(); ActorIt; ++ActorIt)
{
AActor* Actor = (*ActorIt).Get();
ActorsRawPtr.Add(Actor);
}
return AddActorsToLayers(ActorsRawPtr, LayerNames);
}
bool ULayersSubsystem::RemoveActorFromLayer(AActor* Actor, const FName& LayerName, const bool bUpdateStats)
{
TArray<AActor*> Actors;
Actors.Add(Actor);
TArray<FName> LayerNames;
LayerNames.Add(LayerName);
return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats);
}
bool ULayersSubsystem::RemoveActorFromLayers(AActor* Actor, const TArray<FName>& LayerNames, const bool bUpdateStats)
{
TArray<AActor*> Actors;
Actors.Add(Actor);
return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats);
}
bool ULayersSubsystem::RemoveActorsFromLayer(const TArray<AActor*>& Actors, const FName& LayerName, const bool bUpdateStats)
{
TArray<FName> LayerNames;
LayerNames.Add(LayerName);
return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats);
}
bool ULayersSubsystem::RemoveActorsFromLayer(const TArray<TWeakObjectPtr<AActor>>& Actors, const FName& LayerName, const bool bUpdateStats)
{
TArray<FName> LayerNames;
LayerNames.Add(LayerName);
return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats);
}
bool ULayersSubsystem::RemoveActorsFromLayers(const TArray<AActor*>& Actors, const TArray<FName>& LayerNames, const bool bUpdateStats)
{
GEditor->GetSelectedActors()->BeginBatchSelectOperation();
bool bChangesOccurred = false;
for (auto ActorIt = Actors.CreateConstIterator(); ActorIt; ++ActorIt)
{
AActor* Actor = *ActorIt;
if (!IsActorValidForLayer(Actor))
{
continue;
}
bool ActorWasModified = false;
for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt)
{
const FName& LayerName = *LayerNameIt;
if (Actor->Layers.Contains(LayerName))
{
if (!ActorWasModified)
{
Actor->Modify();
ActorWasModified = true;
}
Actor->Layers.Remove(LayerName);
ULayer* Layer;
if (bUpdateStats && TryGetLayer(LayerName, Layer))
{
Layer->Modify();
RemoveActorFromStats(Layer, Actor);
}
}
} // END Iteration over Layers
if (ActorWasModified)
{
// update per-view visibility info
UpdateActorAllViewsVisibility(Actor);
// update general actor visibility
bool bActorModified = false;
bool bActorSelectionChanged = false;
const bool bActorNotifySelectionChange = true;
const bool bActorRedrawViewports = false;
UpdateActorVisibility(Actor, bActorSelectionChanged, bActorModified, bActorNotifySelectionChange, bActorRedrawViewports);
bChangesOccurred = true;
}
} // END Iteration over Actors
GEditor->GetSelectedActors()->EndBatchSelectOperation();
return bChangesOccurred;
}
bool ULayersSubsystem::RemoveActorsFromLayers(const TArray<TWeakObjectPtr<AActor>>& Actors, const TArray<FName>& LayerNames, const bool bUpdateStats)
{
TArray<AActor*> ActorsRawPtr;
for (auto ActorIt = Actors.CreateConstIterator(); ActorIt; ++ActorIt)
{
AActor* Actor = (*ActorIt).Get();
ActorsRawPtr.Add(Actor);
}
return RemoveActorsFromLayers(ActorsRawPtr, LayerNames, bUpdateStats);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Operations on selected actors.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TArray<AActor*> ULayersSubsystem::GetSelectedActors() const
{
// Unfortunately, the batch selection operation is not entirely effective
// and the result can be that the iterator becomes invalid when adding an actor to a layer
// due to unintended selection change notifications being fired.
TArray<AActor*> CurrentlySelectedActors;
for (FSelectionIterator It(GEditor->GetSelectedActorIterator()); It; ++It)
{
AActor* Actor = static_cast<AActor*>(*It);
checkSlow(Actor->IsA(AActor::StaticClass()));
CurrentlySelectedActors.Add(Actor);
}
return CurrentlySelectedActors;
}
bool ULayersSubsystem::AddSelectedActorsToLayer(const FName& LayerName)
{
return AddActorsToLayer(GetSelectedActors(), LayerName);
}
bool ULayersSubsystem::RemoveSelectedActorsFromLayer(const FName& LayerName)
{
return RemoveActorsFromLayer(GetSelectedActors(), LayerName);
}
bool ULayersSubsystem::AddSelectedActorsToLayers(const TArray<FName>& LayerNames)
{
return AddActorsToLayers(GetSelectedActors(), LayerNames);
}
bool ULayersSubsystem::RemoveSelectedActorsFromLayers(const TArray<FName>& LayerNames)
{
return RemoveActorsFromLayers(GetSelectedActors(), LayerNames);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Operations on actors in layers
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ULayersSubsystem::SelectActorsInLayer(const FName& LayerName, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden)
{
return SelectActorsInLayer(LayerName, bSelect, bNotify, bSelectEvenIfHidden, nullptr);
}
bool ULayersSubsystem::SelectActorsInLayer(const FName& LayerName, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden, const TSharedPtr<ActorFilter>& Filter)
{
GEditor->GetSelectedActors()->BeginBatchSelectOperation();
bool bChangesOccurred = false;
// Iterate over all actors, looking for actors in the specified layers.
for (FActorIterator It(GetWorld()); It; ++It)
{
AActor* Actor = *It;
if (!IsActorValidForLayer(Actor))
{
continue;
}
if (Filter.IsValid() && !Filter->PassesFilter(Actor))
{
continue;
}
if (Actor->Layers.Contains(LayerName))
{
// The actor was found to be in a specified layer.
// Set selection state and move on to the next actor.
bool bNotifyForActor = false;
GEditor->GetSelectedActors()->Modify();
GEditor->SelectActor(Actor, bSelect, bNotifyForActor, bSelectEvenIfHidden);
bChangesOccurred = true;
}
}
GEditor->GetSelectedActors()->EndBatchSelectOperation();
if (bNotify)
{
GEditor->NoteSelectionChange();
}
return bChangesOccurred;
}
bool ULayersSubsystem::SelectActorsInLayers(const TArray<FName>& LayerNames, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden)
{
return SelectActorsInLayers(LayerNames, bSelect, bNotify, bSelectEvenIfHidden, nullptr);
}
bool ULayersSubsystem::SelectActorsInLayers(const TArray<FName>& LayerNames, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden, const TSharedPtr<ActorFilter>& Filter)
{
if (LayerNames.Num() == 0)
{
return true;
}
GEditor->GetSelectedActors()->BeginBatchSelectOperation();
bool bChangesOccurred = false;
// Iterate over all actors, looking for actors in the specified layers.
for (AActor* Actor: FActorRange(GetWorld()))
{
if (!IsActorValidForLayer(Actor))
{
continue;
}
if (Filter.IsValid() && !Filter->PassesFilter(TWeakObjectPtr<AActor>(Actor)))
{
continue;
}
for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt)
{
if (Actor->Layers.Contains(*LayerNameIt))
{
// The actor was found to be in a specified layer.
// Set selection state and move on to the next actor.
bool bNotifyForActor = false;
GEditor->GetSelectedActors()->Modify();
GEditor->SelectActor(Actor, bSelect, bNotifyForActor, bSelectEvenIfHidden);
bChangesOccurred = true;
break;
}
}
}
GEditor->GetSelectedActors()->EndBatchSelectOperation();
if (bNotify)
{
GEditor->NoteSelectionChange();
}
return bChangesOccurred;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Operations on actor viewport visibility regarding layers
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ULayersSubsystem::UpdatePerViewVisibility(FLevelEditorViewportClient* ViewportClient, const FName& LayerThatChanged)
{
const int32 ViewIndex = ViewportClient->ViewIndex;
// get the viewport client
// Iterate over all actors, looking for actors in the specified layers.
if (ViewportClient->GetWorld() == NULL)
{
return;
}
for (FActorIterator It(ViewportClient->GetWorld()); It; ++It)
{
AActor* Actor = *It;
if (!IsActorValidForLayer(Actor))
{
continue;
}
// if the view has nothing hidden, just quickly mark the actor as visible in this view
if (ViewportClient->ViewHiddenLayers.Num() == 0)
{
// if the actor had this view hidden, then unhide it
if (Actor->HiddenEditorViews & ((uint64)1 << ViewIndex))
{
// make sure this actor doesn't have the view set
Actor->HiddenEditorViews &= ~((uint64)1 << ViewIndex);
Actor->MarkComponentsRenderStateDirty();
}
}
// else if we were given a name that was changed, only update actors with that name in their layers,
// otherwise update all actors
else if (LayerThatChanged == NAME_Skip || Actor->Layers.Contains(LayerThatChanged))
{
UpdateActorViewVisibility(ViewportClient, Actor);
}
}
// make sure we redraw the viewport
ViewportClient->Invalidate();
}
void ULayersSubsystem::UpdateAllViewVisibility(const FName& LayerThatChanged)
{
// update all views's hidden layers if they had this one
for (FLevelEditorViewportClient* ViewportClient: GEditor->GetLevelViewportClients())
{
UpdatePerViewVisibility(ViewportClient, LayerThatChanged);
}
}
void ULayersSubsystem::UpdateActorViewVisibility(FLevelEditorViewportClient* ViewportClient, AActor* Actor, bool bReregisterIfDirty)
{
// get the viewport client
const int32 ViewIndex = ViewportClient->ViewIndex;
int32 NumHiddenLayers = 0;
// look for which of the actor layers are hidden
for (int32 LayerIndex = 0; LayerIndex < Actor->Layers.Num(); LayerIndex++)
{
// if its in the view hidden list, this layer is hidden for this actor
if (ViewportClient->ViewHiddenLayers.Find(Actor->Layers[LayerIndex]) != -1)
{
NumHiddenLayers++;
// right now, if one is hidden, the actor is hidden
break;
}
}
uint64 OriginalHiddenViews = Actor->HiddenEditorViews;
// right now, if one is hidden, the actor is hidden
if (NumHiddenLayers)
{
Actor->HiddenEditorViews |= ((uint64)1 << ViewIndex);
}
else
{
Actor->HiddenEditorViews &= ~((uint64)1 << ViewIndex);
}
// reregister if we changed the visibility bits, as the rendering thread needs them
if (bReregisterIfDirty && OriginalHiddenViews != Actor->HiddenEditorViews)
{
Actor->MarkComponentsRenderStateDirty();
// make sure we redraw the viewport
ViewportClient->Invalidate();
}
}
void ULayersSubsystem::UpdateActorAllViewsVisibility(AActor* Actor)
{
uint64 OriginalHiddenViews = Actor->HiddenEditorViews;
for (FLevelEditorViewportClient* ViewportClient: GEditor->GetLevelViewportClients())
{
// don't have this reattach, as we can do it once for all views
UpdateActorViewVisibility(ViewportClient, Actor, false);
}
// reregister if we changed the visibility bits, as the rendering thread needs them
if (OriginalHiddenViews != Actor->HiddenEditorViews)
{
return;
}
Actor->MarkComponentsRenderStateDirty();
// redraw all viewports if the actor
for (FLevelEditorViewportClient* ViewportClient: GEditor->GetLevelViewportClients())
{
// make sure we redraw all viewports
ViewportClient->Invalidate();
}
}
void ULayersSubsystem::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)
{
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 (UActorComponent* Component: Actor->GetComponents())
{
UPrimitiveComponent* PrimitiveComponent = Cast<UPrimitiveComponent>(Component);
if (PrimitiveComponent && PrimitiveComponent->IsRegistered())
{
// Push visibility to the render thread
PrimitiveComponent->PushEditorVisibilityToProxy(Actor->HiddenEditorViews);
}
}
}
}
static void UpdateBrushLayerVisibility(ABrush* Brush, bool bIsHidden)
{
ULevel* Level = Brush->GetLevel();
if (!Level)
{
return;
}
UModel* Model = Level->Model;
if (!Model)
{
return;
}
bool bAnySurfaceWasFound = false;
for (FBspSurf& Surf: Model->Surfs)
{
if (Surf.Actor == Brush)
{
Surf.bHiddenEdLayer = bIsHidden;
bAnySurfaceWasFound = true;
}
}
if (bAnySurfaceWasFound)
{
Level->UpdateModelComponents();
Model->InvalidSurfaces = true;
}
}
bool ULayersSubsystem::UpdateActorVisibility(AActor* Actor, bool& bOutSelectionChanged, bool& bOutActorModified, const bool bNotifySelectionChange, const bool bRedrawViewports)
{
bOutActorModified = false;
bOutSelectionChanged = false;
if (!IsActorValidForLayer(Actor))
{
return false;
}
// If the actor doesn't belong to any layers
if (Actor->Layers.Num() == 0)
{
// If the actor is also hidden
if (Actor->bHiddenEdLayer)
{
// Actors that don't belong to any layer shouldn't be hidden
Actor->bHiddenEdLayer = false;
Actor->MarkComponentsRenderStateDirty();
bOutActorModified = true;
}
return bOutActorModified;
}
bool bActorBelongsToVisibleLayer = false;
for (int32 LayerIndex = 0; LayerIndex < GetWorld()->Layers.Num(); ++LayerIndex)
{
ULayer* Layer = GetWorld()->Layers[LayerIndex];
if (!Layer->bIsVisible)
{
continue;
}
if (Actor->Layers.Contains(Layer->LayerName))
{
if (Actor->bHiddenEdLayer)
{
Actor->bHiddenEdLayer = false;
Actor->MarkComponentsRenderStateDirty();
bOutActorModified = true;
if (ABrush* Brush = Cast<ABrush>(Actor))
{
const bool bIsHidden = false;
UpdateBrushLayerVisibility(Brush, bIsHidden);
}
}
// Stop, because we found at least one visible layer the actor belongs to
bActorBelongsToVisibleLayer = true;
break;
}
}
// If the actor isn't part of a visible layer, hide and de-select it.
if (!bActorBelongsToVisibleLayer)
{
if (!Actor->bHiddenEdLayer)
{
Actor->bHiddenEdLayer = true;
Actor->MarkComponentsRenderStateDirty();
bOutActorModified = true;
if (ABrush* Brush = Cast<ABrush>(Actor))
{
const bool bIsHidden = true;
UpdateBrushLayerVisibility(Brush, bIsHidden);
}
}
// if the actor was selected, mark it as unselected
if (Actor->IsSelected())
{
bool bSelect = false;
bool bNotify = false;
bool bIncludeHidden = true;
GEditor->SelectActor(Actor, bSelect, bNotify, bIncludeHidden);
bOutSelectionChanged = true;
bOutActorModified = true;
}
}
if (bNotifySelectionChange && bOutSelectionChanged)
{
GEditor->NoteSelectionChange();
}
if (bRedrawViewports)
{
GEditor->RedrawLevelEditingViewports();
}
return bOutActorModified || bOutSelectionChanged;
}
bool ULayersSubsystem::UpdateAllActorsVisibility(const bool bNotifySelectionChange, const bool bRedrawViewports)
{
bool bSelectionChanged = false;
bool bChangesOccurred = false;
for (FActorIterator It(GetWorld()); It; ++It)
{
AActor* Actor = *It;
bool bActorModified = false;
bool bActorSelectionChanged = false;
const bool bActorNotifySelectionChange = false;
const bool bActorRedrawViewports = false;
bChangesOccurred |= UpdateActorVisibility(Actor, bActorSelectionChanged /*OUT*/, bActorModified /*OUT*/, bActorNotifySelectionChange, bActorRedrawViewports);
bSelectionChanged |= bActorSelectionChanged;
}
if (bNotifySelectionChange && bSelectionChanged)
{
GEditor->NoteSelectionChange();
}
if (bRedrawViewports)
{
GEditor->RedrawLevelEditingViewports();
}
return bChangesOccurred;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Operations on layers
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ULayersSubsystem::AppendActorsFromLayer(const FName& LayerName, TArray<AActor*>& InOutActors) const
{
AppendActorsFromLayer(LayerName, InOutActors, nullptr);
}
#define LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_1 \
for (FActorIterator ActorIt(GetWorld()); ActorIt; ++ActorIt) \
{
#define LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_2 \
if (Filter.IsValid() && !Filter->PassesFilter(Actor)) \
{ \
continue; \
} \
\
if (Actor->Layers.Contains(LayerName)) \
{ \
InOutActors.Add(Actor); \
} \
}
void ULayersSubsystem::AppendActorsFromLayer(const FName& LayerName, TArray<AActor*>& InOutActors, const TSharedPtr<ActorFilter>& Filter) const
{
LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_1
AActor* Actor = *ActorIt;
LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_2
}
void ULayersSubsystem::AppendActorsFromLayer(const FName& LayerName, TArray<TWeakObjectPtr<AActor>>& InOutActors, const TSharedPtr<ActorFilter>& Filter) const
{
LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_1
const TWeakObjectPtr<AActor> Actor = *ActorIt;
LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_2
}
void ULayersSubsystem::AppendActorsFromLayers(const TArray<FName>& LayerNames, TArray<AActor*>& InOutActors) const
{
AppendActorsFromLayers(LayerNames, InOutActors, nullptr);
}
#define LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_1 \
for (FActorIterator ActorIt(GetWorld()); ActorIt; ++ActorIt) \
{
#define LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_2 \
if (Filter.IsValid() && !Filter->PassesFilter(Actor)) \
{ \
continue; \
} \
\
for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt) \
{ \
const FName& LayerName = *LayerNameIt; \
\
if (Actor->Layers.Contains(LayerName)) \
{ \
InOutActors.Add(Actor); \
break; \
} \
} \
}
void ULayersSubsystem::AppendActorsFromLayers(const TArray<FName>& LayerNames, TArray<AActor*>& InOutActors, const TSharedPtr<ActorFilter>& Filter) const
{
LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_1
AActor* Actor = *ActorIt;
LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_2
}
void ULayersSubsystem::AppendActorsFromLayers(const TArray<FName>& LayerNames, TArray<TWeakObjectPtr<AActor>>& InOutActors, const TSharedPtr<ActorFilter>& Filter) const
{
LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_1
const TWeakObjectPtr<AActor> Actor = *ActorIt;
LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_2
}
TArray<AActor*> ULayersSubsystem::GetActorsFromLayer(const FName& LayerName) const
{
TArray<AActor*> OutActors;
AppendActorsFromLayer(LayerName, OutActors);
return OutActors;
}
TArray<AActor*> ULayersSubsystem::GetActorsFromLayer(const FName& LayerName, const TSharedPtr<ActorFilter>& Filter) const
{
TArray<AActor*> OutActors;
AppendActorsFromLayer(LayerName, OutActors, Filter);
return OutActors;
}
TArray<AActor*> ULayersSubsystem::GetActorsFromLayers(const TArray<FName>& LayerNames) const
{
TArray<AActor*> OutActors;
AppendActorsFromLayers(LayerNames, OutActors);
return OutActors;
}
TArray<AActor*> ULayersSubsystem::GetActorsFromLayers(const TArray<FName>& LayerNames, const TSharedPtr<ActorFilter>& Filter) const
{
TArray<AActor*> OutActors;
AppendActorsFromLayers(LayerNames, OutActors, Filter);
return OutActors;
}
void ULayersSubsystem::SetLayerVisibility(const FName& LayerName, const bool bIsVisible)
{
ULayer* Layer = EnsureLayerExists(LayerName);
check(Layer != nullptr);
Layer->Modify();
Layer->bIsVisible = bIsVisible;
LayersChanged.Broadcast(ELayersAction::Modify, Layer, "bIsVisible");
UpdateAllActorsVisibility(true, true);
}
void ULayersSubsystem::SetLayersVisibility(const TArray<FName>& LayerNames, const bool bIsVisible)
{
if (LayerNames.Num() == 0)
{
return;
}
bool bChangeOccurred = false;
for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt)
{
ULayer* Layer = EnsureLayerExists(*LayerNameIt);
check(Layer != NULL);
if (Layer->bIsVisible != bIsVisible)
{
Layer->Modify();
Layer->bIsVisible = bIsVisible;
LayersChanged.Broadcast(ELayersAction::Modify, Layer, "bIsVisible");
bChangeOccurred = true;
}
}
if (bChangeOccurred)
{
UpdateAllActorsVisibility(true, true);
}
}
void ULayersSubsystem::ToggleLayerVisibility(const FName& LayerName)
{
ULayer* Layer = EnsureLayerExists(LayerName);
check(Layer != NULL);
Layer->Modify();
Layer->bIsVisible = !Layer->bIsVisible;
LayersChanged.Broadcast(ELayersAction::Modify, Layer, "bIsVisible");
UpdateAllActorsVisibility(true, true);
}
void ULayersSubsystem::ToggleLayersVisibility(const TArray<FName>& LayerNames)
{
if (LayerNames.Num() == 0)
{
return;
}
for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt)
{
ULayer* Layer = EnsureLayerExists(*LayerNameIt);
check(Layer != NULL);
Layer->Modify();
Layer->bIsVisible = !Layer->bIsVisible;
LayersChanged.Broadcast(ELayersAction::Modify, Layer, "bIsVisible");
}
UpdateAllActorsVisibility(true, true);
}
void ULayersSubsystem::MakeAllLayersVisible()
{
TArray<FName> AllLayerNames;
ULayersSubsystem::AddAllLayerNamesTo(AllLayerNames);
for (auto LayerIt = GetWorld()->Layers.CreateIterator(); LayerIt; ++LayerIt)
{
ULayer* Layer = *LayerIt;
if (!Layer->bIsVisible)
{
Layer->Modify();
Layer->bIsVisible = true;
LayersChanged.Broadcast(ELayersAction::Modify, TWeakObjectPtr<ULayer>(Layer), "bIsVisible");
}
}
UpdateAllActorsVisibility(true, true);
}
ULayer* ULayersSubsystem::GetLayer(const FName& LayerName) const
{
for (auto LayerIt = GetWorld()->Layers.CreateConstIterator(); LayerIt; ++LayerIt)
{
ULayer* Layer = *LayerIt;
if (Layer->LayerName == LayerName)
{
return Layer;
}
}
return nullptr;
}
bool ULayersSubsystem::IsLayer(const FName& LayerName)
{
ULayer* OutLayer = GetLayer(LayerName);
return (OutLayer != nullptr);
}
bool ULayersSubsystem::TryGetLayer(const FName& LayerName, ULayer*& OutLayer)
{
OutLayer = GetLayer(LayerName);
return (OutLayer != nullptr);
}
void ULayersSubsystem::AddAllLayerNamesTo(TArray<FName>& OutLayers) const
{
for (auto LayerIt = GetWorld()->Layers.CreateConstIterator(); LayerIt; ++LayerIt)
{
ULayer* Layer = *LayerIt;
OutLayers.Add(Layer->LayerName);
}
}
#define LAYERS_SUBSYSTEM_ADD_ALL_LAYERS_TO \
for (auto LayerIt = GetWorld()->Layers.CreateConstIterator(); LayerIt; ++LayerIt) \
{ \
OutLayers.Add(*LayerIt); \
}
void ULayersSubsystem::AddAllLayersTo(TArray<ULayer*>& OutLayers) const
{
LAYERS_SUBSYSTEM_ADD_ALL_LAYERS_TO
}
void ULayersSubsystem::AddAllLayersTo(TArray<TWeakObjectPtr<ULayer>>& OutLayers) const {
LAYERS_SUBSYSTEM_ADD_ALL_LAYERS_TO}
ULayer* ULayersSubsystem::CreateLayer(const FName& LayerName)
{
ULayer* NewLayer = NewObject<ULayer>(GetWorld(), NAME_None, RF_Transactional);
check(NewLayer != NULL);
GetWorld()->Modify();
GetWorld()->Layers.Add(NewLayer);
NewLayer->LayerName = LayerName;
NewLayer->bIsVisible = true;
LayersChanged.Broadcast(ELayersAction::Add, NewLayer, NAME_None);
return NewLayer;
}
void ULayersSubsystem::DeleteLayers(const TArray<FName>& LayersToDelete)
{
TArray<FName> ValidLayersToDelete;
for (auto LayerNameIt = LayersToDelete.CreateConstIterator(); LayerNameIt; ++LayerNameIt)
{
if (IsLayer(*LayerNameIt))
{
ValidLayersToDelete.Add(*LayerNameIt);
}
}
// Iterate over all actors, looking for actors in the specified layers.
for (FActorIterator It(GetWorld()); It; ++It)
{
AActor* Actor = *It;
// The Layer must exist in order to remove actors from it,
// so we have to wait to delete the ULayer object till after
// all the actors have been disassociated with it.
RemoveActorFromLayers(Actor, ValidLayersToDelete, false);
}
bool bValidLayerExisted = false;
for (int LayerIndex = GetWorld()->Layers.Num() - 1; LayerIndex >= 0; LayerIndex--)
{
if (LayersToDelete.Contains(GetWorld()->Layers[LayerIndex]->LayerName))
{
GetWorld()->Modify();
GetWorld()->Layers.RemoveAt(LayerIndex);
bValidLayerExisted = true;
}
}
LayersChanged.Broadcast(ELayersAction::Delete, NULL, NAME_None);
}
void ULayersSubsystem::DeleteLayer(const FName& LayerToDelete)
{
if (!IsLayer(LayerToDelete))
{
return;
}
// Iterate over all actors, looking for actors in the specified layer.
for (FActorIterator It(GetWorld()); It; ++It)
{
AActor* Actor = *It;
// The Layer must exist in order to remove actors from it,
// so we have to wait to delete the ULayer object till after
// all the actors have been disassociated with it.
RemoveActorFromLayer(Actor, LayerToDelete, false);
}
bool bValidLayerExisted = false;
for (int LayerIndex = GetWorld()->Layers.Num() - 1; LayerIndex >= 0; LayerIndex--)
{
if (LayerToDelete == GetWorld()->Layers[LayerIndex]->LayerName)
{
GetWorld()->Modify();
GetWorld()->Layers.RemoveAt(LayerIndex);
bValidLayerExisted = true;
}
}
LayersChanged.Broadcast(ELayersAction::Delete, NULL, NAME_None);
}
bool ULayersSubsystem::RenameLayer(const FName& OriginalLayerName, const FName& NewLayerName)
{
// We specifically don't pass the original LayerName by reference to avoid it changing
// it's original value, in case, it would be the reference of the Layer's actually FName
if (OriginalLayerName == NewLayerName)
{
return false;
}
ULayer* Layer;
if (!TryGetLayer(OriginalLayerName, Layer))
{
return false;
}
Layer->Modify();
const FName OriginalLayerNameCopy = OriginalLayerName; // Otherwise, bug if RenameLayer(Layer->LayerName, NewLayerName) after the next LayerName rename
Layer->LayerName = NewLayerName;
Layer->ActorStats.Empty();
// Iterate over all actors, swapping layers.
for (FActorIterator It(GetWorld()); It; ++It)
{
AActor* Actor = *It;
if (!IsActorValidForLayer(Actor))
{
continue;
}
if (ULayersSubsystem::RemoveActorFromLayer(Actor, OriginalLayerNameCopy))
{
// No need to mark the actor as modified these functions take care of that
AddActorToLayer(Actor, NewLayerName);
}
}
// update all views's hidden layers if they had this one
for (FLevelEditorViewportClient* ViewportClient: GEditor->GetLevelViewportClients())
{
if (ViewportClient->ViewHiddenLayers.Remove(OriginalLayerNameCopy) > 0)
{
ViewportClient->ViewHiddenLayers.AddUnique(NewLayerName);
ViewportClient->Invalidate();
}
}
LayersChanged.Broadcast(ELayersAction::Rename, Layer, "LayerName");
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Helper functions.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ULayersSubsystem::AddActorToStats(ULayer* Layer, AActor* Actor)
{
if (!Actor)
{
return;
}
UClass* ActorClass = Actor->GetClass();
bool bFoundClassStats = false;
for (auto StatsIt = Layer->ActorStats.CreateIterator(); StatsIt; ++StatsIt)
{
FLayerActorStats& Stats = *StatsIt;
if (Stats.Type == ActorClass)
{
Stats.Total++;
bFoundClassStats = true;
break;
}
}
if (!bFoundClassStats)
{
FLayerActorStats NewActorStats;
NewActorStats.Total = 1;
NewActorStats.Type = ActorClass;
Layer->ActorStats.Add(NewActorStats);
}
LayersChanged.Broadcast(ELayersAction::Modify, Layer, TEXT("ActorStats"));
}
void ULayersSubsystem::RemoveActorFromStats(ULayer* Layer, AActor* Actor)
{
if (!Actor)
{
return;
}
UClass* ActorClass = Actor->GetClass();
bool bFoundClassStats = false;
for (int StatsIndex = 0; StatsIndex < Layer->ActorStats.Num(); StatsIndex++)
{
FLayerActorStats& Stats = Layer->ActorStats[StatsIndex];
if (Stats.Type == ActorClass)
{
bFoundClassStats = true;
--Stats.Total;
if (Stats.Total == 0)
{
Layer->ActorStats.RemoveAt(StatsIndex);
}
break;
}
}
if (bFoundClassStats)
{
LayersChanged.Broadcast(ELayersAction::Modify, Layer, TEXT("ActorStats"));
}
}
ULayer* ULayersSubsystem::EnsureLayerExists(const FName& LayerName)
{
ULayer* Layer;
if (!TryGetLayer(LayerName, Layer))
{
Layer = CreateLayer(LayerName);
}
return Layer;
}