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"
2026-09-20 15:50:23 +02:00
# 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"
2026-09-20 15:50:23 +02:00
# 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 )
) ;
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 " ) ) ;
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 ) ;
}
2026-09-20 15:50:23 +02:00
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 ) )
) ;
}
2026-09-20 15:50:23 +02:00
// 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