Files
UnrealEngine/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserModule.cpp
2025-05-18 13:04:45 +08:00

210 lines
6.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "WorldBrowserModule.h"
#include "Widgets/SWidget.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Modules/ModuleManager.h"
#include "EditorModeRegistry.h"
#include "EditorModes.h"
#include "LevelCollectionCommands.h"
#include "LevelFolders.h"
#include "Engine/WorldComposition.h"
#include "StreamingLevels/StreamingLevelEdMode.h"
#include "Tiles/WorldTileCollectionModel.h"
#include "StreamingLevels/StreamingLevelCollectionModel.h"
#include "SWorldHierarchy.h"
#include "SWorldDetails.h"
#include "Tiles/SWorldComposition.h"
#include "Framework/MultiBox/MultiBoxExtender.h"
#include "LevelEditor.h"
#include "EditorLevelUtils.h"
#include "ThumbnailRendering/ThumbnailManager.h"
IMPLEMENT_MODULE( FWorldBrowserModule, WorldBrowser );
#define LOCTEXT_NAMESPACE "WorldBrowser"
/**
* Fills the level menu with extra options
*/
TSharedRef<FExtender> FWorldBrowserModule::BindLevelMenu(const TSharedRef<FUICommandList> CommandList)
{
TSharedRef<FExtender> Extender(new FExtender());
Extender->AddMenuExtension("LevelListing", EExtensionHook::Before, CommandList, FMenuExtensionDelegate::CreateRaw(this, &FWorldBrowserModule::BuildLevelMenu));
return Extender;
}
void FWorldBrowserModule::BuildLevelMenu(FMenuBuilder& MenuBuilder)
{
UWorld* EditorWorld = GEditor->GetEditorWorldContext().World();
TSharedPtr<FLevelCollectionModel> Model = SharedWorldModel(EditorWorld);
if (Model.IsValid())
{
FLevelModelList ModelList = Model->GetFilteredLevels();
for (TSharedPtr<FLevelModel> LevelModel : ModelList)
{
FUIAction Action(FExecuteAction::CreateRaw(this, &FWorldBrowserModule::SetCurrentSublevel, LevelModel),
FCanExecuteAction(),
FIsActionChecked::CreateRaw(this, &FWorldBrowserModule::IsCurrentSublevel, LevelModel));
MenuBuilder.AddMenuEntry(FText::FromString(LevelModel->GetDisplayName()), FText::GetEmpty(), FSlateIcon(), Action, NAME_None, EUserInterfaceActionType::Button);
}
}
}
bool FWorldBrowserModule::IsCurrentSublevel(TSharedPtr<FLevelModel> InLevelModel)
{
return InLevelModel->IsCurrent();
}
void FWorldBrowserModule::SetCurrentSublevel(TSharedPtr<FLevelModel> InLevelModel)
{
InLevelModel->MakeLevelCurrent();
}
void FWorldBrowserModule::StartupModule()
{
FLevelCollectionCommands::Register();
// register the editor mode
FEditorModeRegistry::Get().RegisterMode<FStreamingLevelEdMode>(
FBuiltinEditorModes::EM_StreamingLevel,
NSLOCTEXT("WorldBrowser", "StreamingLevelMode", "Level Transform Editing"));
if (ensure(GEngine))
{
GEngine->OnWorldAdded().AddRaw(this, &FWorldBrowserModule::OnWorldCreated);
GEngine->OnWorldDestroyed().AddRaw(this, &FWorldBrowserModule::OnWorldDestroyed);
}
UWorldComposition::WorldCompositionChangedEvent.AddRaw(this, &FWorldBrowserModule::OnWorldCompositionChanged);
// Have to check GIsEditor because right now editor modules can be loaded by the game
// Once LoadModule is guaranteed to return NULL for editor modules in game, this can be removed
// Without this check, loading the level editor in the game will crash
if (GIsEditor)
{
// Extend the level viewport levels menu
FLevelEditorModule& LevelEditorModule = FModuleManager::Get().LoadModuleChecked<FLevelEditorModule>("LevelEditor");
LevelMenuExtender = FLevelEditorModule::FLevelEditorMenuExtender::CreateRaw(this, &FWorldBrowserModule::BindLevelMenu);
auto& MenuExtenders = LevelEditorModule.GetAllLevelEditorLevelMenuExtenders();
MenuExtenders.Add(LevelMenuExtender);
LevelMenuExtenderHandle = MenuExtenders.Last().GetHandle();
}
FLevelFolders::Init();
}
void FWorldBrowserModule::ShutdownModule()
{
ReleaseWorldModel();
ShutdownDelegate.Broadcast();
FLevelFolders::Cleanup();
if (GEngine)
{
GEngine->OnWorldAdded().RemoveAll(this);
GEngine->OnWorldDestroyed().RemoveAll(this);
}
UWorldComposition::WorldCompositionChangedEvent.RemoveAll(this);
FLevelCollectionCommands::Unregister();
// unregister the editor mode
FEditorModeRegistry::Get().UnregisterMode(FBuiltinEditorModes::EM_StreamingLevel);
}
void FWorldBrowserModule::ReleaseWorldModel()
{
if (WorldModel)
{
// So we have to be the last owner of this model
check(WorldModel.IsUnique());
WorldModel.Reset();
}
}
TSharedRef<SWidget> FWorldBrowserModule::CreateWorldBrowserHierarchy()
{
return CreateWorldBrowserHierarchyWidget()->GetWidget();
}
TSharedRef<UE::WorldHierarchy::IWorldHierarchy> FWorldBrowserModule::CreateWorldBrowserHierarchyWidget()
{
UWorld* EditorWorld = GEditor->GetEditorWorldContext().World();
return SNew(SWorldHierarchy).InWorld(EditorWorld);
}
TSharedRef<SWidget> FWorldBrowserModule::CreateWorldBrowserDetails()
{
UWorld* EditorWorld = GEditor->GetEditorWorldContext().World();
return SNew(SWorldDetails).InWorld(EditorWorld);
}
TSharedRef<SWidget> FWorldBrowserModule::CreateWorldBrowserComposition()
{
UWorld* EditorWorld = GEditor->GetEditorWorldContext().World();
return SNew(SWorldComposition).InWorld(EditorWorld);
}
void FWorldBrowserModule::OnWorldCreated(UWorld* InWorld)
{
if (InWorld &&
InWorld->WorldType == EWorldType::Editor)
{
OnBrowseWorld.Broadcast(InWorld);
}
}
void FWorldBrowserModule::OnWorldCompositionChanged(UWorld* InWorld)
{
if (InWorld &&
InWorld->WorldType == EWorldType::Editor)
{
OnBrowseWorld.Broadcast(NULL);
// Release World Model here so that a new one gets created in ShareWorldModel even if the World is the same.
ReleaseWorldModel();
OnBrowseWorld.Broadcast(InWorld);
}
}
void FWorldBrowserModule::OnWorldDestroyed(UWorld* InWorld)
{
// Is there any editors alive?
if (WorldModel.IsValid())
{
UWorld* ManagedWorld = WorldModel->GetWorld(/*bEvenIfPendingKill*/true);
// Is it our world gets cleaned up?
if (ManagedWorld == InWorld)
{
// Will reset all references to a shared world model
OnBrowseWorld.Broadcast(NULL);
ReleaseWorldModel();
}
}
}
TSharedPtr<FLevelCollectionModel> FWorldBrowserModule::SharedWorldModel(UWorld* InWorld)
{
if (!WorldModel.IsValid() || WorldModel->GetWorld() != InWorld)
{
if (InWorld)
{
if (InWorld->WorldComposition)
{
WorldModel = FWorldTileCollectionModel::Create(InWorld);
}
else
{
WorldModel = FStreamingLevelCollectionModel::Create(InWorld);
}
}
}
return WorldModel;
}
#undef LOCTEXT_NAMESPACE