// Copyright (c) 2026 Reignance Studios. MIT License, see LICENSE. #include "Framework/Notifications/NotificationManager.h" #include "HAL/IConsoleManager.h" #include "HAL/PlatformProcess.h" #include "Modules/ModuleManager.h" #include "RSNetAuditRunner.h" #include "ToolMenus.h" #include "Widgets/Notifications/SNotificationList.h" #define LOCTEXT_NAMESPACE "RSNetAudit" class FRSNetAuditModule : public IModuleInterface { public: virtual void StartupModule() override { UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FRSNetAuditModule::RegisterMenus)); } virtual void ShutdownModule() override { UToolMenus::UnRegisterStartupCallback(this); UToolMenus::UnregisterOwner(this); } static void RunFromEditor() { const FRSAuditResult Result = FRSNetAuditRunner::Run(FRSAuditOptions()); FNotificationInfo Info(FText::Format( LOCTEXT("Done", "GAS Net Audit: {0} errors, {1} warnings, {2} info"), Result.Count(ERSAuditSeverity::Error), Result.Count(ERSAuditSeverity::Warning), Result.Count(ERSAuditSeverity::Info))); Info.ExpireDuration = 8.f; Info.bUseSuccessFailIcons = true; const FString HtmlPath = Result.HtmlPath; Info.Hyperlink = FSimpleDelegate::CreateLambda([HtmlPath]() { FPlatformProcess::LaunchFileInDefaultExternalApplication(*HtmlPath); }); Info.HyperlinkText = LOCTEXT("OpenReport", "Open report"); if (TSharedPtr Item = FSlateNotificationManager::Get().AddNotification(Info)) { Item->SetCompletionState(Result.Count(ERSAuditSeverity::Error) > 0 ? SNotificationItem::CS_Fail : SNotificationItem::CS_Success); } } private: void RegisterMenus() { FToolMenuOwnerScoped OwnerScoped(this); UToolMenu* Menu = UToolMenus::Get()->ExtendMenu(TEXT("LevelEditor.MainMenu.Tools")); // The (Name, Label) overload is 5.4+; setting Label works on 5.3 too. FToolMenuSection& Section = Menu->FindOrAddSection(TEXT("RSNetAudit")); Section.Label = LOCTEXT("Section", "Multiplayer"); Section.AddMenuEntry( TEXT("RunGASNetAudit"), LOCTEXT("Run", "Run GAS Net Audit"), LOCTEXT("RunTip", "Scan abilities, PlayerStates and AttributeSets for multiplayer mistakes and open a report."), FSlateIcon(), FUIAction(FExecuteAction::CreateStatic(&FRSNetAuditModule::RunFromEditor))); } }; static FAutoConsoleCommand GRSNetAuditCommand( TEXT("RSNetAudit.Run"), TEXT("Runs the GAS Net Audit and writes a report to Saved/RSNetAudit."), FConsoleCommandDelegate::CreateStatic(&FRSNetAuditModule::RunFromEditor)); #undef LOCTEXT_NAMESPACE IMPLEMENT_MODULE(FRSNetAuditModule, RSNetAudit)