Files
UnrealEngine/Engine/Source/Programs/BuildStorageTool/Private/BuildStorageTool.cpp
2025-05-18 13:04:45 +08:00

359 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BuildStorageTool.h"
#include "Experimental/ZenServerInterface.h"
#include "Features/IModularFeatures.h"
#include "Framework/Application/SlateApplication.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Framework/Notifications/NotificationManager.h"
#include "GenericPlatform/GenericPlatformFile.h"
#include "HAL/PlatformProcess.h"
#include "Misc/CompilationResult.h"
#include "Misc/MessageDialog.h"
#include "Misc/Optional.h"
#include "Misc/Timespan.h"
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
#include "RequiredProgramMainCPPInclude.h"
#include "SBuildActivity.h"
#include "SBuildSelection.h"
#include "SBuildLogin.h"
#include "SMessageDialog.h"
#include "StandaloneRenderer.h"
#include "BuildStorageToolStyle.h"
#include "Tasks/Task.h"
#include "Templates/SharedPointer.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Input/SCheckBox.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "Widgets/Text/STextBlock.h"
#include "ZenServiceInstanceManager.h"
#include "BuildServiceInstanceManager.h"
#if PLATFORM_WINDOWS
#include "Runtime/Launch/Resources/Windows/Resource.h"
#include "Windows/WindowsApplication.h"
#include "Windows/AllowWindowsPlatformTypes.h"
#include <shellapi.h>
#include "Windows/HideWindowsPlatformTypes.h"
#elif PLATFORM_LINUX
#include "UnixCommonStartup.h"
#elif PLATFORM_MAC
#include "Mac/MacProgramDelegate.h"
#include "LaunchEngineLoop.h"
#else
#error "Unsupported platform!"
#endif
#define LOCTEXT_NAMESPACE "BuildStorageTool"
// These macros are not properly defined by UBT in the case of an engine program with bTreatAsEngineModule=true
// So define them here as a workaround
#define IMPLEMENT_ENCRYPTION_KEY_REGISTRATION()
#define IMPLEMENT_SIGNING_KEY_REGISTRATION()
IMPLEMENT_APPLICATION(BuildStorageTool, "BuildStorageTool");
static void OnRequestExit()
{
RequestEngineExit(TEXT("BuildStorageTool Closed"));
}
static void HideOnCloseOverride(const TSharedRef<SWindow>& WindowBeingClosed)
{
WindowBeingClosed->HideWindow();
}
class FBuildStorageToolApp
{
FCriticalSection CriticalSection;
FSlateApplication& Slate;
TSharedPtr<SWindow> Window;
TSharedPtr<SNotificationItem> CompileNotification;
TSharedPtr<UE::Zen::FServiceInstanceManager> ZenServiceInstanceManager;
TSharedPtr<UE::Zen::Build::FServiceInstanceManager> BuildServiceInstanceManager;
std::atomic<bool> bLatentExclusiveOperationActive = false;
void ExitTool()
{
FSlateApplication::Get().RequestDestroyWindow(Window.ToSharedRef());
}
bool CanExecuteExclusiveAction()
{
return !bLatentExclusiveOperationActive;
}
TSharedRef< SWidget > MakeMainMenu()
{
FMenuBarBuilder MenuBuilder( nullptr );
{
// Control
MenuBuilder.AddPullDownMenu(
LOCTEXT( "FileMenu", "File" ),
LOCTEXT( "FileMenu_ToolTip", "Opens the file menu" ),
FOnGetContent::CreateRaw( this, &FBuildStorageToolApp::FillFileMenu ) );
}
// Create the menu bar
TSharedRef< SWidget > MenuBarWidget = MenuBuilder.MakeWidget();
MenuBarWidget->SetVisibility( EVisibility::Visible ); // Work around for menu bar not showing on Mac
return MenuBarWidget;
}
TSharedRef<SWidget> FillFileMenu()
{
const bool bCloseSelfOnly = false;
const bool bSearchable = false;
const bool bRecursivelySearchable = false;
FMenuBuilder MenuBuilder(true,
nullptr,
TSharedPtr<FExtender>(),
bCloseSelfOnly,
&FCoreStyle::Get(),
bSearchable,
NAME_None,
bRecursivelySearchable);
MenuBuilder.AddMenuEntry(
LOCTEXT("Exit", "Exit"),
LOCTEXT("Exit_ToolTip", "Exits the Storage Server UI"),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateRaw( this, &FBuildStorageToolApp::ExitTool ),
FCanExecuteAction::CreateRaw(this, &FBuildStorageToolApp::CanExecuteExclusiveAction)
),
NAME_None,
EUserInterfaceActionType::Button
);
return MenuBuilder.MakeWidget();
}
public:
FBuildStorageToolApp(FSlateApplication& InSlate)
: Slate(InSlate)
{
ZenServiceInstanceManager = MakeShared<UE::Zen::FServiceInstanceManager>();
BuildServiceInstanceManager = MakeShared<UE::Zen::Build::FServiceInstanceManager>();
InstallMessageDialogOverride();
}
virtual ~FBuildStorageToolApp()
{
RemoveMessageDialogOverride();
}
void Run()
{
Window =
SNew(SWindow)
.Title(GetWindowTitle())
.ClientSize(FVector2D(900.0f, 600.0f))
.ActivationPolicy(EWindowActivationPolicy::Always)
.SizingRule(ESizingRule::UserSized)
.IsTopmostWindow(false)
.FocusWhenFirstShown(false)
.SupportsMaximize(true)
.SupportsMinimize(true)
.HasCloseButton(true)
[
SNew(SBorder)
.BorderImage(FCoreStyle::Get().GetBrush("ToolPanel.GroupBorder"))
[
SNew(SVerticalBox)
// Menu
+ SVerticalBox::Slot()
.AutoHeight()
[
MakeMainMenu()
]
// Login panel
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0.0f, 10.0f, 5.0f, 0.0f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Top)
[
SNew(SBuildLogin)
.ZenServiceInstance(ZenServiceInstanceManager.ToSharedRef(), &UE::Zen::FServiceInstanceManager::GetZenServiceInstance)
.BuildServiceInstance(BuildServiceInstanceManager.ToSharedRef(), &UE::Zen::Build::FServiceInstanceManager::GetBuildServiceInstance)
]
// Selection panel
+ SVerticalBox::Slot()
.Padding(0.0f, 10.0f, 5.0f, 0.0f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Top)
[
SNew(SBuildSelection)
.ZenServiceInstance(ZenServiceInstanceManager.ToSharedRef(), &UE::Zen::FServiceInstanceManager::GetZenServiceInstance)
.BuildServiceInstance(BuildServiceInstanceManager.ToSharedRef(), &UE::Zen::Build::FServiceInstanceManager::GetBuildServiceInstance)
.OnBuildTransferStarted_Lambda([this]
(UE::Zen::Build::FBuildServiceInstance::FBuildTransfer Transfer, FStringView Name, FStringView Platform)
{
BuildActivity->AddBuildTransfer(Transfer, Name, Platform);
})
]
// Activity panel
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0.0f, 10.0f, 5.0f, 0.0f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Bottom)
[
SAssignNew(BuildActivity, SBuildActivity)
.ZenServiceInstance(ZenServiceInstanceManager.ToSharedRef(), &UE::Zen::FServiceInstanceManager::GetZenServiceInstance)
.BuildServiceInstance(BuildServiceInstanceManager.ToSharedRef(), &UE::Zen::Build::FServiceInstanceManager::GetBuildServiceInstance)
]
]
];
Slate.AddWindow(Window.ToSharedRef(), true);
// Setting focus seems to have to happen after the Window has been added
Slate.ClearKeyboardFocus(EFocusCause::Cleared);
// loop until the app is ready to quit
while (!IsEngineExitRequested())
{
BeginExitIfRequested();
FTaskGraphInterface::Get().ProcessThreadUntilIdle(ENamedThreads::GameThread);
FTSTicker::GetCoreTicker().Tick(FApp::GetDeltaTime());
Slate.PumpMessages();
Slate.Tick();
FPlatformProcess::Sleep(1.0f / 30.0f);
}
// Make sure the window is hidden, because it might take a while for the background thread to finish.
Window->HideWindow();
}
private:
FText GetWindowTitle()
{
return LOCTEXT("WindowTitle", "Unreal Build Storage Tool");
}
EAppReturnType::Type OnModalMessageDialog(EAppMsgCategory InMessageCategory, EAppMsgType::Type InMessage, const FText& InText, const FText& InTitle)
{
if (IsInGameThread() && FSlateApplication::IsInitialized() && FSlateApplication::Get().CanAddModalWindow())
{
return OpenModalMessageDialog_Internal(InMessageCategory, InMessage, InText, InTitle, Window);
}
else
{
return FPlatformMisc::MessageBoxExt(InMessage, *InText.ToString(), *InTitle.ToString());
}
}
void InstallMessageDialogOverride()
{
FCoreDelegates::ModalMessageDialog.BindRaw(this, &FBuildStorageToolApp::OnModalMessageDialog);
}
void RemoveMessageDialogOverride()
{
FCoreDelegates::ModalMessageDialog.Unbind();
}
TSharedPtr<SBuildActivity> BuildActivity;
};
int BuildStorageToolMain(const TCHAR* CmdLine)
{
ON_SCOPE_EXIT
{
RequestEngineExit(TEXT("Exiting"));
FEngineLoop::AppPreExit();
FModuleManager::Get().UnloadModulesAtShutdown();
FEngineLoop::AppExit();
};
const FTaskTagScope Scope(ETaskTag::EGameThread);
// start up the main loop
GEngineLoop.PreInit(CmdLine);
FSystemWideCriticalSection SystemWideBuildStorageToolCritSec(TEXT("BuildStorageTool"));
if (!SystemWideBuildStorageToolCritSec.IsValid())
{
return true;
}
check(GConfig && GConfig->IsReadyForUse());
// Initialize high DPI mode
FSlateApplication::InitHighDPI(true);
{
// Create the platform slate application (what FSlateApplication::Get() returns)
TSharedRef<FSlateApplication> Slate = FSlateApplication::Create(MakeShareable(FPlatformApplicationMisc::CreateApplication()));
{
// Initialize renderer
TSharedRef<FSlateRenderer> SlateRenderer = GetStandardStandaloneRenderer();
// Try to initialize the renderer. It's possible that we launched when the driver crashed so try a few times before giving up.
bool bRendererInitialized = Slate->InitializeRenderer(SlateRenderer, true);
if (!bRendererInitialized)
{
// Close down the Slate application
FSlateApplication::Shutdown();
return false;
}
// Set the normal UE IsEngineExitRequested() when outer frame is closed
Slate->SetExitRequestedHandler(FSimpleDelegate::CreateStatic(&OnRequestExit));
// Prepare the custom Slate styles
FBuildStorageToolStyle::Initialize();
// Set the icon
FAppStyle::SetAppStyleSet(FBuildStorageToolStyle::Get());
// Run the inner application loop
FBuildStorageToolApp App(Slate.Get());
App.Run();
// Clean up the custom styles
FBuildStorageToolStyle::Shutdown();
}
// Close down the Slate application
FSlateApplication::Shutdown();
}
return true;
}
#if PLATFORM_WINDOWS
int WINAPI WinMain(_In_ HINSTANCE hCurrInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
hInstance = hCurrInstance;
return BuildStorageToolMain(GetCommandLineW())? 0 : 1;
}
#elif PLATFORM_LINUX
int main(int argc, char* argv[])
{
return CommonUnixMain(argc, argv, &BuildStorageToolMain);
}
#elif PLATFORM_MAC
int main(int argc, char* argv[])
{
[MacProgramDelegate mainWithArgc : argc argv : argv programMain : BuildStorageToolMain programExit : FEngineLoop::AppExit] ;
}
#else
#error "Unsupported platform!"
#endif
#undef LOCTEXT_NAMESPACE