Files
ProjectEleri/Source/ProjectEleriEditor/Private/ProjectEleriEditorModule.cpp

169 lines
6.5 KiB
C++
Raw Normal View History

2026-07-11 10:43:52 +02:00
#include "ProjectEleriEditorModule.h"
2026-09-05 21:20:30 +02:00
#include "Framework/Docking/TabManager.h"
2026-07-11 10:43:52 +02:00
#include "Modules/ModuleManager.h"
#include "PropertyEditorModule.h"
#include "Styling/AppStyle.h"
2026-09-05 21:20:30 +02:00
#include "ToolMenus.h"
#include "Widgets/Docking/SDockTab.h"
2026-07-11 10:43:52 +02:00
#include "ItemDataAssetCustomization.h"
2026-09-05 21:20:30 +02:00
#include "ItemEditorWindow.h"
2026-09-20 14:22:08 +02:00
#include "NpcScheduleActionCustomization.h"
#include "NpcScheduleAssetCustomization.h"
#include "ScheduleAssetRecheck.h"
2026-09-05 21:20:30 +02:00
#define LOCTEXT_NAMESPACE "ProjectEleriEditorModule"
IMPLEMENT_GAME_MODULE(FProjectEleriEditorModule, ProjectEleriEditor);
const FName FProjectEleriEditorModule::ItemEditorTabName(TEXT("ProjectEleriItemEditor"));
void FProjectEleriEditorModule::StartupModule()
{
// Details customization for the item data asset (property map generation widget).
FPropertyEditorModule& PropEd = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropEd.RegisterCustomClassLayout(
TEXT("ItemDataAsset"),
FOnGetDetailCustomizationInstance::CreateStatic(&FItemDataAssetCustomization::MakeInstance)
);
2026-09-20 14:22:08 +02:00
// Details customization for schedule actions, so an anchor is picked from the level instead of
// being typed in as a PersistentId. Registered under the struct's script name, which is the C++
// struct name without its F prefix.
PropEd.RegisterCustomPropertyTypeLayout(
TEXT("ScheduledAction"),
FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FNpcScheduleActionCustomization::MakeInstance)
);
// Details customization for the schedule asset itself, which draws the day its actions describe as
// a strip under everything else the panel shows. Registered under the class's script name, which is
// the C++ class name without its U prefix.
PropEd.RegisterCustomClassLayout(
TEXT("NpcScheduleAsset"),
FOnGetDetailCustomizationInstance::CreateStatic(&FNpcScheduleAssetCustomization::MakeInstance)
);
2026-09-05 21:20:30 +02:00
// Register the Item Editor as a docking tab.
if (FGlobalTabmanager::Get()->HasTabSpawner(ItemEditorTabName))
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(ItemEditorTabName);
}
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(
ItemEditorTabName,
FOnSpawnTab::CreateLambda([](const FSpawnTabArgs& Args)
{
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
.Label(LOCTEXT("ItemEditorTabLabel", "Item Editor"))
.ToolTipText(LOCTEXT("ItemEditorTabTooltip", "Search items by name and edit their data assets"))
[
SNew(SItemEditorWindow)
];
}))
.SetDisplayName(LOCTEXT("ItemEditorDisplayName", "Item Editor"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
// Add a menu entry to open the window. Menus might not be ready yet during startup.
if (UToolMenus::IsToolMenuUIEnabled())
{
RegisterMenus();
}
else
{
UToolMenus::RegisterStartupCallback(
FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FProjectEleriEditorModule::RegisterMenus));
}
}
void FProjectEleriEditorModule::ShutdownModule()
{
if (FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
{
FPropertyEditorModule& PropEd = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropEd.UnregisterCustomClassLayout(TEXT("ItemDataAsset"));
2026-09-20 14:22:08 +02:00
PropEd.UnregisterCustomPropertyTypeLayout(TEXT("ScheduledAction"));
PropEd.UnregisterCustomClassLayout(TEXT("NpcScheduleAsset"));
2026-09-05 21:20:30 +02:00
}
if (FGlobalTabmanager::Get()->HasTabSpawner(ItemEditorTabName))
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(ItemEditorTabName);
}
UToolMenus::UnregisterOwner(this);
}
void FProjectEleriEditorModule::OpenItemEditorTab()
{
FGlobalTabmanager::Get()->TryInvokeTab(ItemEditorTabName);
}
void FProjectEleriEditorModule::RecheckScheduleAssets()
{
// Thin on purpose: the sweep reports what it found, in a notification and in the log, so all that
// is left for the module is to give it somewhere to be reached from. Whatever it was not able to
// answer for is part of that report rather than something to be decided again here.
ScheduleAssetRecheck::RecheckAllScheduleAssets();
}
2026-09-05 21:20:30 +02:00
void FProjectEleriEditorModule::RegisterMenus()
{
FToolMenuOwnerScoped OwnerScoped(this);
if (UToolMenu* WindowMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Window"))
{
FToolMenuSection& Section = WindowMenu->AddSection(
TEXT("ItemEditor"),
LOCTEXT("ItemEditorSectionLabel", "Eleri Tools"),
FToolMenuInsert(NAME_None, EToolMenuInsertType::First)
);
Section.AddMenuEntry(
TEXT("OpenItemEditor"),
LOCTEXT("ItemEditorMenuLabel", "Item Editor"),
LOCTEXT("ItemEditorMenuTooltip", "Open a window to search items by name and edit their data assets."),
FSlateIcon(),
FUIAction(FExecuteAction::CreateRaw(this, &FProjectEleriEditorModule::OpenItemEditorTab))
);
}
// The Tools menu of the level editor, in a section of this module's own so that the entries this
// module adds are gathered in one place instead of being scattered among the engine's tools.
if (UToolMenu* ToolsMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Tools"))
{
FToolMenuSection& Section = ToolsMenu->AddSection(
TEXT("ScheduleAssets"),
LOCTEXT("ScheduleAssetsSectionLabel", "Eleri Tools"),
FToolMenuInsert(NAME_None, EToolMenuInsertType::First)
);
Section.AddMenuEntry(
TEXT("RecheckScheduleAssets"),
LOCTEXT("RecheckScheduleAssetsMenuLabel", "Recheck Schedule Assets"),
LOCTEXT("RecheckScheduleAssetsTooltip", "Compare every NPC schedule asset's recorded anchor positions with the anchors standing in this level, and save the assets that have moved."),
FSlateIcon(),
FUIAction(FExecuteAction::CreateRaw(this, &FProjectEleriEditorModule::RecheckScheduleAssets))
);
}
// The level editor toolbar keeps a stretch of itself clear for plugins that want a button there, so
// this adds to a slot that already exists rather than registering a toolbar of its own that would
// then have to be found a place on screen.
if (UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar.User"))
{
FToolMenuSection& Section = ToolbarMenu->FindOrAddSection(TEXT("ScheduleAssets"));
Section.AddEntry(FToolMenuEntry::InitToolBarButton(
TEXT("RecheckScheduleAssets"),
FUIAction(FExecuteAction::CreateRaw(this, &FProjectEleriEditorModule::RecheckScheduleAssets)),
LOCTEXT("RecheckScheduleAssetsToolbarLabel", "Recheck Schedules"),
LOCTEXT("RecheckScheduleAssetsTooltip", "Compare every NPC schedule asset's recorded anchor positions with the anchors standing in this level, and save the assets that have moved."),
FSlateIcon(FAppStyle::GetAppStyleSetName(), TEXT("Icons.Adjust"))
));
}
2026-09-05 21:20:30 +02:00
}
2026-07-11 10:43:52 +02:00
2026-09-05 21:20:30 +02:00
#undef LOCTEXT_NAMESPACE