1383 lines
41 KiB
C++
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;
|
|
}
|