
해당 플러그인 출시 성공 했습니다.
Fab의 등록하는 과정을 확인하고 싶으신 분들은 다음 글을 읽어주세요!
https://sonsazang.tistory.com/133
언리얼엔진 제작한 플러그인 FAB에 출시하기(Part2)
https://sonsazang.tistory.com/131 언리얼 에디터 툴바에 Level Selector 플러그인 만들기 (Part 1)개발하게 된 과정언리얼 프로젝트를 개발하다 보면 여러 레벨을 오가면서 Play In Editor(PIE)를 자주 실행하게 됩
sonsazang.tistory.com
개발하게 된 과정
언리얼 프로젝트를 개발하다 보면 여러 레벨을 오가면서 Play In Editor(PIE)를 자주 실행하게 됩니다.
그런데 매번 콘텐츠 브라우저에서 레벨을 더블 클릭하고, PIE 버튼을 누르는 과정이 반복되면 생각보다 많은 클릭과 시간이 소모되죠.
그래서 이번 글에서는 언리얼 에디터 툴바에 직접 레벨 선택 드롭다운과 Play 버튼을 추가하는 플러그인을 만들어 보았습니다.
단순한 기능이지만, 레벨 테스트가 많은 프로젝트에서는 꽤 유용하게 사용할 수 있습니다.
https://github.com/SONSAZANG/UnrealCustomLevelStartPlugin
GitHub - SONSAZANG/UnrealCustomLevelStartPlugin: 언리얼엔진 5 - 특정 레벨을 클릭해서 바로 시작할 수 있는
언리얼엔진 5 - 특정 레벨을 클릭해서 바로 시작할 수 있는 플러그인. Contribute to SONSAZANG/UnrealCustomLevelStartPlugin development by creating an account on GitHub.
github.com
개발 환경
- 언리얼 엔진 버전: Unreal Engine 5.5
- 플러그인 타입: Editor Toolbar Button (C++)
- 주요 사용 모듈: ToolMenus, LevelEditor, UnrealEd
플러그인 생성

1. 언리얼 에디터 상단 메뉴 > Edit > Plugins
2. 왼쪽 상단 > Add > Editor Toolbar Button 선택
3. 플러그인 이름 작성 (LevelSelector)
4. Create Plugin 선택
5. 프로젝트 루트 경로 > Plugins (새로 생성됩니다) > LevelSelector(설정한 플러그인 이름) > Source > LevelSelector 안에 있는 LevelSelector.h와 LevelSelector.cpp를 수정하게 됩니다. 파일명은 설정한 플러그인 이름으로 설정됩니다.

소스 코드 작성
우선 LevelSelector.h의 코드부터 분석하겠습니다.
// LevelSelector.h
// Copyright (c) 2025 SONSAZANG. All Rights Reserved.
#pragma once
#include "Modules/ModuleManager.h"
class FToolBarBuilder;
class FMenuBuilder;
class FLevelSelectorModule : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
TSharedRef<SWidget> GenerateDropdownMenu();
FString SelectedMapName;
void OnLevelSelected(FString LevelName);
void OnPlayClicked();
private:
void RegisterMenus();
};
StartupModule()
- 플러그인이 로드될 때 호출되는 초기화 함수
- 여기서 ToolMenus 콜백을 등록해 툴바를 확장하는 작업을 수행합니다.
void FLevelSelectorModule::StartupModule()
{
FLevelSelectorStyle::Initialize();
FLevelSelectorStyle::ReloadTextures();
FLevelSelectorCommands::Register();
UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FLevelSelectorModule::RegisterMenus));
}
ShutdownModule()
- 플러그인이 언로드되거나 에디터가 종료될 때 호출되는 함수
- 등록한 메뉴나 스타일 등의 리소스를 정리합니다.
void FLevelSelectorModule::ShutdownModule()
{
UToolMenus::UnRegisterStartupCallback(this);
UToolMenus::UnregisterOwner(this);
FLevelSelectorStyle::Shutdown();
FLevelSelectorCommands::Unregister();
}
RegisterMenus()
- 에디터 툴바를 확장하고, 드롭다운과 Play 버튼을 추가하는 핵심 함수
- ToolMenus API를 사용해 메뉴 섹션을 만들고 항목을 삽입합니다.
void FLevelSelectorModule::RegisterMenus()
{
FToolMenuOwnerScoped OwnerScoped(this);
UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar.PlayToolBar");
{
FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("PluginTools");
FToolMenuEntry DropdownEntry = FToolMenuEntry::InitComboButton(
"LevelSelectorDropdown",
FUIAction(),
FOnGetContent::CreateRaw(this, &FLevelSelectorModule::GenerateDropdownMenu),
TAttribute<FText>::Create([this]() {
return SelectedMapName.IsEmpty()
? FText::FromString(TEXT("Level Selector"))
: FText::FromString(FString::Printf(TEXT("[ %s ]"), *SelectedMapName));
}),
LOCTEXT("LevelSelectorDropdown_Tooltip", "Select a level to open"),
FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Level")
);
DropdownEntry.StyleNameOverride = "CalloutToolbar";
Section.AddEntry(DropdownEntry);
FToolMenuEntry PlayButtonEntry = FToolMenuEntry::InitToolBarButton(
"PlaySelectedLevel",
FUIAction(FExecuteAction::CreateRaw(this, &FLevelSelectorModule::OnPlayClicked)),
LOCTEXT("PlayLevel_Label", "Play Level"),
LOCTEXT("PlayLevel_Tooltip", "Play selected level"),
FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Play")
);
Section.AddEntry(PlayButtonEntry);
}
}
GenerateDropdownMenu()
- 드롭다운 버튼을 클릭했을 때 펼쳐지는 메뉴 위젯을 생성한다.
- Content/Maps 경로에서 .umap 파일을 찾아 목록으로 보여준다.
TSharedRef<SWidget> FLevelSelectorModule::GenerateDropdownMenu()
{
TArray<FString> MapNames;
const FString MapsDir = FPaths::ProjectContentDir() + TEXT("Maps/");
IFileManager::Get().FindFilesRecursive(MapNames, *MapsDir, TEXT("*.umap"), true, false);
FMenuBuilder MenuBuilder(true, nullptr);
for (const FString& MapPath : MapNames)
{
FString NameOnly = FPaths::GetBaseFilename(MapPath);
MenuBuilder.AddMenuEntry(
FText::FromString(*NameOnly),
FText::FromString(*NameOnly),
FSlateIcon(),
FUIAction(FExecuteAction::CreateRaw(this, &FLevelSelectorModule::OnLevelSelected, NameOnly))
);
}
return MenuBuilder.MakeWidget();
}
OnLevelSelected(FString LevelName)
- 드롭다운에서 특정 레벨으 선택했을 때 호출되는 함수
- 선택한 맵 이름을 내부 변수 SelectedMapName에 저장합니다.'
void FLevelSelectorModule::OnLevelSelected(FString LevelName)
{
SelectedMapName = LevelName;
UE_LOG(LogTemp, Log, TEXT("Selected Level: %s"), *LevelName);
}
OnPlayClicked()
- "Play Level" 버튼이 클릭되었을 때 실행되는 함수
- SelectedMapName에 저장된 레벨을 열고, PIE(Play In Editor)로 바로 해당 레벨을 실행합니다.
void FLevelSelectorModule::OnPlayClicked()
{
if (SelectedMapName.IsEmpty())
{
UE_LOG(LogTemp, Warning, TEXT("No Level Selected!"));
}
const FString MapPath = FString::Printf(TEXT("/Game/Maps/%s"), *SelectedMapName);
if (!FPackageName::DoesPackageExist(MapPath))
{
UE_LOG(LogTemp, Warning, TEXT("Map does not exist : %s"), *SelectedMapName);
}
UEditorLoadingAndSavingUtils::LoadMap(MapPath);
FLevelEditorModule &LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
TSharedPtr<IAssetViewport> ActiveLevelViewport = LevelEditorModule.GetFirstActiveViewport();
if (GUnrealEd)
{
FRequestPlaySessionParams Params;
Params.WorldType = EPlaySessionWorldType::PlayInEditor;
Params.SessionDestination = EPlaySessionDestinationType::InProcess;
Params.DestinationSlateViewport = ActiveLevelViewport;
GUnrealEd->RequestPlaySession(Params);
}
UE_LOG(LogTemp, Log, TEXT("OnPlayClicked: %s"), *SelectedMapName);
}
플러그인 기능 테스트
1. 에디터 툴바에 추가된 드롭다운 에디터 유틸리티 확인

2. "Play Level" 버튼 클릭 시 선택된 레벨 실행

정리
작은 기능이지만, 반복되는 작업을 줄여주는 아주 실용적인 플러그인이었습니다.
실제로 작업할 때 여러 테스트 레벨을 전환하며 사용하는 데 꽤 만족스러웠고, 툴바에 바로 붙는 느낌이 아주 편했어요.
다음 글에서는 Fab 마켓에 등록하는 전체 과정을 정리해보려고 합니다.
감사합니다.

해당 플러그인 출시 성공 했습니다.
Fab의 등록하는 과정을 확인하고 싶으신 분들은 다음 글을 읽어주세요!
https://sonsazang.tistory.com/133
언리얼엔진 제작한 플러그인 FAB에 출시하기(Part2)
https://sonsazang.tistory.com/131 언리얼 에디터 툴바에 Level Selector 플러그인 만들기 (Part 1)개발하게 된 과정언리얼 프로젝트를 개발하다 보면 여러 레벨을 오가면서 Play In Editor(PIE)를 자주 실행하게 됩
sonsazang.tistory.com
개발하게 된 과정
언리얼 프로젝트를 개발하다 보면 여러 레벨을 오가면서 Play In Editor(PIE)를 자주 실행하게 됩니다.
그런데 매번 콘텐츠 브라우저에서 레벨을 더블 클릭하고, PIE 버튼을 누르는 과정이 반복되면 생각보다 많은 클릭과 시간이 소모되죠.
그래서 이번 글에서는 언리얼 에디터 툴바에 직접 레벨 선택 드롭다운과 Play 버튼을 추가하는 플러그인을 만들어 보았습니다.
단순한 기능이지만, 레벨 테스트가 많은 프로젝트에서는 꽤 유용하게 사용할 수 있습니다.
https://github.com/SONSAZANG/UnrealCustomLevelStartPlugin
GitHub - SONSAZANG/UnrealCustomLevelStartPlugin: 언리얼엔진 5 - 특정 레벨을 클릭해서 바로 시작할 수 있는
언리얼엔진 5 - 특정 레벨을 클릭해서 바로 시작할 수 있는 플러그인. Contribute to SONSAZANG/UnrealCustomLevelStartPlugin development by creating an account on GitHub.
github.com
개발 환경
- 언리얼 엔진 버전: Unreal Engine 5.5
- 플러그인 타입: Editor Toolbar Button (C++)
- 주요 사용 모듈: ToolMenus, LevelEditor, UnrealEd
플러그인 생성

1. 언리얼 에디터 상단 메뉴 > Edit > Plugins
2. 왼쪽 상단 > Add > Editor Toolbar Button 선택
3. 플러그인 이름 작성 (LevelSelector)
4. Create Plugin 선택
5. 프로젝트 루트 경로 > Plugins (새로 생성됩니다) > LevelSelector(설정한 플러그인 이름) > Source > LevelSelector 안에 있는 LevelSelector.h와 LevelSelector.cpp를 수정하게 됩니다. 파일명은 설정한 플러그인 이름으로 설정됩니다.

소스 코드 작성
우선 LevelSelector.h의 코드부터 분석하겠습니다.
// LevelSelector.h
// Copyright (c) 2025 SONSAZANG. All Rights Reserved.
#pragma once
#include "Modules/ModuleManager.h"
class FToolBarBuilder;
class FMenuBuilder;
class FLevelSelectorModule : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
TSharedRef<SWidget> GenerateDropdownMenu();
FString SelectedMapName;
void OnLevelSelected(FString LevelName);
void OnPlayClicked();
private:
void RegisterMenus();
};
StartupModule()
- 플러그인이 로드될 때 호출되는 초기화 함수
- 여기서 ToolMenus 콜백을 등록해 툴바를 확장하는 작업을 수행합니다.
void FLevelSelectorModule::StartupModule()
{
FLevelSelectorStyle::Initialize();
FLevelSelectorStyle::ReloadTextures();
FLevelSelectorCommands::Register();
UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FLevelSelectorModule::RegisterMenus));
}
ShutdownModule()
- 플러그인이 언로드되거나 에디터가 종료될 때 호출되는 함수
- 등록한 메뉴나 스타일 등의 리소스를 정리합니다.
void FLevelSelectorModule::ShutdownModule()
{
UToolMenus::UnRegisterStartupCallback(this);
UToolMenus::UnregisterOwner(this);
FLevelSelectorStyle::Shutdown();
FLevelSelectorCommands::Unregister();
}
RegisterMenus()
- 에디터 툴바를 확장하고, 드롭다운과 Play 버튼을 추가하는 핵심 함수
- ToolMenus API를 사용해 메뉴 섹션을 만들고 항목을 삽입합니다.
void FLevelSelectorModule::RegisterMenus()
{
FToolMenuOwnerScoped OwnerScoped(this);
UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar.PlayToolBar");
{
FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("PluginTools");
FToolMenuEntry DropdownEntry = FToolMenuEntry::InitComboButton(
"LevelSelectorDropdown",
FUIAction(),
FOnGetContent::CreateRaw(this, &FLevelSelectorModule::GenerateDropdownMenu),
TAttribute<FText>::Create([this]() {
return SelectedMapName.IsEmpty()
? FText::FromString(TEXT("Level Selector"))
: FText::FromString(FString::Printf(TEXT("[ %s ]"), *SelectedMapName));
}),
LOCTEXT("LevelSelectorDropdown_Tooltip", "Select a level to open"),
FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Level")
);
DropdownEntry.StyleNameOverride = "CalloutToolbar";
Section.AddEntry(DropdownEntry);
FToolMenuEntry PlayButtonEntry = FToolMenuEntry::InitToolBarButton(
"PlaySelectedLevel",
FUIAction(FExecuteAction::CreateRaw(this, &FLevelSelectorModule::OnPlayClicked)),
LOCTEXT("PlayLevel_Label", "Play Level"),
LOCTEXT("PlayLevel_Tooltip", "Play selected level"),
FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Play")
);
Section.AddEntry(PlayButtonEntry);
}
}
GenerateDropdownMenu()
- 드롭다운 버튼을 클릭했을 때 펼쳐지는 메뉴 위젯을 생성한다.
- Content/Maps 경로에서 .umap 파일을 찾아 목록으로 보여준다.
TSharedRef<SWidget> FLevelSelectorModule::GenerateDropdownMenu()
{
TArray<FString> MapNames;
const FString MapsDir = FPaths::ProjectContentDir() + TEXT("Maps/");
IFileManager::Get().FindFilesRecursive(MapNames, *MapsDir, TEXT("*.umap"), true, false);
FMenuBuilder MenuBuilder(true, nullptr);
for (const FString& MapPath : MapNames)
{
FString NameOnly = FPaths::GetBaseFilename(MapPath);
MenuBuilder.AddMenuEntry(
FText::FromString(*NameOnly),
FText::FromString(*NameOnly),
FSlateIcon(),
FUIAction(FExecuteAction::CreateRaw(this, &FLevelSelectorModule::OnLevelSelected, NameOnly))
);
}
return MenuBuilder.MakeWidget();
}
OnLevelSelected(FString LevelName)
- 드롭다운에서 특정 레벨으 선택했을 때 호출되는 함수
- 선택한 맵 이름을 내부 변수 SelectedMapName에 저장합니다.'
void FLevelSelectorModule::OnLevelSelected(FString LevelName)
{
SelectedMapName = LevelName;
UE_LOG(LogTemp, Log, TEXT("Selected Level: %s"), *LevelName);
}
OnPlayClicked()
- "Play Level" 버튼이 클릭되었을 때 실행되는 함수
- SelectedMapName에 저장된 레벨을 열고, PIE(Play In Editor)로 바로 해당 레벨을 실행합니다.
void FLevelSelectorModule::OnPlayClicked()
{
if (SelectedMapName.IsEmpty())
{
UE_LOG(LogTemp, Warning, TEXT("No Level Selected!"));
}
const FString MapPath = FString::Printf(TEXT("/Game/Maps/%s"), *SelectedMapName);
if (!FPackageName::DoesPackageExist(MapPath))
{
UE_LOG(LogTemp, Warning, TEXT("Map does not exist : %s"), *SelectedMapName);
}
UEditorLoadingAndSavingUtils::LoadMap(MapPath);
FLevelEditorModule &LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
TSharedPtr<IAssetViewport> ActiveLevelViewport = LevelEditorModule.GetFirstActiveViewport();
if (GUnrealEd)
{
FRequestPlaySessionParams Params;
Params.WorldType = EPlaySessionWorldType::PlayInEditor;
Params.SessionDestination = EPlaySessionDestinationType::InProcess;
Params.DestinationSlateViewport = ActiveLevelViewport;
GUnrealEd->RequestPlaySession(Params);
}
UE_LOG(LogTemp, Log, TEXT("OnPlayClicked: %s"), *SelectedMapName);
}
플러그인 기능 테스트
1. 에디터 툴바에 추가된 드롭다운 에디터 유틸리티 확인

2. "Play Level" 버튼 클릭 시 선택된 레벨 실행

정리
작은 기능이지만, 반복되는 작업을 줄여주는 아주 실용적인 플러그인이었습니다.
실제로 작업할 때 여러 테스트 레벨을 전환하며 사용하는 데 꽤 만족스러웠고, 툴바에 바로 붙는 느낌이 아주 편했어요.
다음 글에서는 Fab 마켓에 등록하는 전체 과정을 정리해보려고 합니다.
감사합니다.