Restyle the start menu as a vertical Minecraft-like title screen.
Main buttons stack under each other with Singleplayer, Multiplayer, Options, and Quit subpages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
7cc715cad5
commit
3c7fa78912
@ -3,23 +3,32 @@
|
||||
#include "VocationMainMenuWidget.h"
|
||||
#include "VocationSessionSubsystem.h"
|
||||
#include "VocationGameInstance.h"
|
||||
#include "VocationGraphicsLibrary.h"
|
||||
#include "Components/Button.h"
|
||||
#include "Components/ComboBoxString.h"
|
||||
#include "Components/EditableTextBox.h"
|
||||
#include "Components/TextBlock.h"
|
||||
#include "Components/VerticalBox.h"
|
||||
#include "Components/HorizontalBox.h"
|
||||
#include "Components/VerticalBoxSlot.h"
|
||||
#include "Components/WidgetSwitcher.h"
|
||||
#include "Components/Border.h"
|
||||
#include "Components/SizeBox.h"
|
||||
#include "Components/Overlay.h"
|
||||
#include "Components/OverlaySlot.h"
|
||||
#include "Components/Spacer.h"
|
||||
#include "Blueprint/WidgetTree.h"
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "Kismet/KismetSystemLibrary.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
UTextBlock* MakeLabel(UWidgetTree* Tree, const FName& Name, const FString& Text)
|
||||
void AddPadded(UVerticalBox* Box, UWidget* Child, float PadY = 6.f)
|
||||
{
|
||||
UTextBlock* Label = Tree->ConstructWidget<UTextBlock>(UTextBlock::StaticClass(), Name);
|
||||
Label->SetText(FText::FromString(Text));
|
||||
return Label;
|
||||
if (UVerticalBoxSlot* Slot = Box->AddChildToVerticalBox(Child))
|
||||
{
|
||||
Slot->SetPadding(FMargin(0.f, PadY));
|
||||
Slot->SetHorizontalAlignment(HAlign_Fill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +37,7 @@ void UVocationMainMenuWidget::NativeConstruct()
|
||||
Super::NativeConstruct();
|
||||
BuildUI();
|
||||
RefreshMaps();
|
||||
ShowPage(EMenuPage::Main);
|
||||
|
||||
if (UGameInstance* GI = GetGameInstance())
|
||||
{
|
||||
@ -35,9 +45,7 @@ void UVocationMainMenuWidget::NativeConstruct()
|
||||
{
|
||||
Sessions->OnSessionSearchDetailed.AddDynamic(this, &UVocationMainMenuWidget::OnSessionSearchDetailed);
|
||||
Sessions->OnSessionJoined.AddDynamic(this, &UVocationMainMenuWidget::OnSessionJoined);
|
||||
SetStatus(FString::Printf(TEXT("Online subsystem: %s | Steam: %s"),
|
||||
*Sessions->GetActiveSubsystemName(),
|
||||
Sessions->IsSteamAvailable() ? TEXT("yes") : TEXT("no")));
|
||||
SetStatus(FString::Printf(TEXT("Steam: %s"), Sessions->IsSteamAvailable() ? TEXT("ready") : TEXT("offline / LAN")));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,6 +63,60 @@ void UVocationMainMenuWidget::NativeDestruct()
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
|
||||
UTextBlock* UVocationMainMenuWidget::MakeLabel(const FName& Name, const FString& Text, float Size) const
|
||||
{
|
||||
UTextBlock* Label = WidgetTree->ConstructWidget<UTextBlock>(UTextBlock::StaticClass(), Name);
|
||||
Label->SetText(FText::FromString(Text));
|
||||
FSlateFontInfo Font = Label->GetFont();
|
||||
Font.Size = Size;
|
||||
Label->SetFont(Font);
|
||||
Label->SetJustification(ETextJustify::Center);
|
||||
Label->SetColorAndOpacity(FSlateColor(FLinearColor(0.95f, 0.95f, 0.95f, 1.f)));
|
||||
return Label;
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::StyleMenuButton(UButton* Button) const
|
||||
{
|
||||
if (!Button)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FButtonStyle Style = Button->GetStyle();
|
||||
FSlateBrush Normal;
|
||||
Normal.TintColor = FSlateColor(FLinearColor(0.28f, 0.28f, 0.28f, 0.95f));
|
||||
Normal.DrawAs = ESlateBrushDrawType::Box;
|
||||
Style.SetNormal(Normal);
|
||||
|
||||
FSlateBrush Hovered = Normal;
|
||||
Hovered.TintColor = FSlateColor(FLinearColor(0.45f, 0.45f, 0.2f, 1.f));
|
||||
Style.SetHovered(Hovered);
|
||||
|
||||
FSlateBrush Pressed = Normal;
|
||||
Pressed.TintColor = FSlateColor(FLinearColor(0.2f, 0.2f, 0.2f, 1.f));
|
||||
Style.SetPressed(Pressed);
|
||||
|
||||
Button->SetStyle(Style);
|
||||
}
|
||||
|
||||
UButton* UVocationMainMenuWidget::MakeMenuButton(const FName& Name, const FString& Label, void (UVocationMainMenuWidget::*Callback)())
|
||||
{
|
||||
UButton* Button = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), Name);
|
||||
StyleMenuButton(Button);
|
||||
|
||||
USizeBox* Size = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), *FString::Printf(TEXT("%s_Size"), *Name.ToString()));
|
||||
Size->SetWidthOverride(400.f);
|
||||
Size->SetHeightOverride(44.f);
|
||||
Size->SetContent(Button);
|
||||
|
||||
UTextBlock* Text = MakeLabel(*FString::Printf(TEXT("%s_Label"), *Name.ToString()), Label, 18.f);
|
||||
Button->SetContent(Text);
|
||||
|
||||
// Bind via a thin lambda isn't possible with AddDynamic — callers bind after.
|
||||
(void)Callback;
|
||||
return Button;
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::BuildUI()
|
||||
{
|
||||
if (!WidgetTree)
|
||||
@ -62,117 +124,313 @@ void UVocationMainMenuWidget::BuildUI()
|
||||
return;
|
||||
}
|
||||
|
||||
UVerticalBox* Column = WidgetTree->ConstructWidget<UVerticalBox>(UVerticalBox::StaticClass(), TEXT("Column"));
|
||||
WidgetTree->RootWidget = Column;
|
||||
UBorder* Root = WidgetTree->ConstructWidget<UBorder>(UBorder::StaticClass(), TEXT("RootBorder"));
|
||||
Root->SetBrushColor(FLinearColor(0.05f, 0.08f, 0.12f, 0.88f));
|
||||
Root->SetPadding(FMargin(24.f));
|
||||
WidgetTree->RootWidget = Root;
|
||||
|
||||
auto AddToColumn = [Column](UWidget* Child)
|
||||
UOverlay* Overlay = WidgetTree->ConstructWidget<UOverlay>(UOverlay::StaticClass(), TEXT("RootOverlay"));
|
||||
Root->SetContent(Overlay);
|
||||
|
||||
UVerticalBox* CenterColumn = WidgetTree->ConstructWidget<UVerticalBox>(UVerticalBox::StaticClass(), TEXT("CenterColumn"));
|
||||
if (UOverlaySlot* OverlaySlot = Overlay->AddChildToOverlay(CenterColumn))
|
||||
{
|
||||
if (UVerticalBoxSlot* Slot = Column->AddChildToVerticalBox(Child))
|
||||
{
|
||||
Slot->SetPadding(FMargin(12.f, 6.f));
|
||||
}
|
||||
OverlaySlot->SetHorizontalAlignment(HAlign_Center);
|
||||
OverlaySlot->SetVerticalAlignment(VAlign_Center);
|
||||
}
|
||||
|
||||
TitleText = MakeLabel(TEXT("Title"), TEXT("VocationLife"), 56.f);
|
||||
AddPadded(CenterColumn, TitleText, 4.f);
|
||||
|
||||
SplashText = MakeLabel(TEXT("Splash"), TEXT("A life of many vocations!"), 16.f);
|
||||
SplashText->SetColorAndOpacity(FSlateColor(FLinearColor(1.f, 0.9f, 0.2f, 1.f)));
|
||||
AddPadded(CenterColumn, SplashText, 2.f);
|
||||
|
||||
USpacer* Spacer = WidgetTree->ConstructWidget<USpacer>(USpacer::StaticClass(), TEXT("TitleSpacer"));
|
||||
Spacer->SetSize(FVector2D(1.f, 28.f));
|
||||
AddPadded(CenterColumn, Spacer, 0.f);
|
||||
|
||||
PageSwitcher = WidgetTree->ConstructWidget<UWidgetSwitcher>(UWidgetSwitcher::StaticClass(), TEXT("PageSwitcher"));
|
||||
AddPadded(CenterColumn, PageSwitcher, 8.f);
|
||||
|
||||
// ---- Main page ----
|
||||
UVerticalBox* MainPage = WidgetTree->ConstructWidget<UVerticalBox>(UVerticalBox::StaticClass(), TEXT("MainPage"));
|
||||
PageSwitcher->AddChild(MainPage);
|
||||
|
||||
UButton* BtnSingleplayer = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("BtnSingleplayer"));
|
||||
StyleMenuButton(BtnSingleplayer);
|
||||
{
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("BtnSingleplayerSize"));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetHeightOverride(46.f);
|
||||
S->SetContent(BtnSingleplayer);
|
||||
BtnSingleplayer->SetContent(MakeLabel(TEXT("BtnSingleplayerLbl"), TEXT("Singleplayer"), 18.f));
|
||||
BtnSingleplayer->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnSingleplayerClicked);
|
||||
AddPadded(MainPage, S, 5.f);
|
||||
}
|
||||
|
||||
UButton* BtnMultiplayer = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("BtnMultiplayer"));
|
||||
StyleMenuButton(BtnMultiplayer);
|
||||
{
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("BtnMultiplayerSize"));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetHeightOverride(46.f);
|
||||
S->SetContent(BtnMultiplayer);
|
||||
BtnMultiplayer->SetContent(MakeLabel(TEXT("BtnMultiplayerLbl"), TEXT("Multiplayer"), 18.f));
|
||||
BtnMultiplayer->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnMultiplayerClicked);
|
||||
AddPadded(MainPage, S, 5.f);
|
||||
}
|
||||
|
||||
UButton* BtnOptions = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("BtnOptions"));
|
||||
StyleMenuButton(BtnOptions);
|
||||
{
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("BtnOptionsSize"));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetHeightOverride(46.f);
|
||||
S->SetContent(BtnOptions);
|
||||
BtnOptions->SetContent(MakeLabel(TEXT("BtnOptionsLbl"), TEXT("Options..."), 18.f));
|
||||
BtnOptions->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnOptionsClicked);
|
||||
AddPadded(MainPage, S, 5.f);
|
||||
}
|
||||
|
||||
UButton* BtnQuit = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("BtnQuit"));
|
||||
StyleMenuButton(BtnQuit);
|
||||
{
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("BtnQuitSize"));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetHeightOverride(46.f);
|
||||
S->SetContent(BtnQuit);
|
||||
BtnQuit->SetContent(MakeLabel(TEXT("BtnQuitLbl"), TEXT("Quit Game"), 18.f));
|
||||
BtnQuit->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnQuitClicked);
|
||||
AddPadded(MainPage, S, 5.f);
|
||||
}
|
||||
|
||||
// ---- Singleplayer page ----
|
||||
UVerticalBox* SoloPage = WidgetTree->ConstructWidget<UVerticalBox>(UVerticalBox::StaticClass(), TEXT("SoloPage"));
|
||||
PageSwitcher->AddChild(SoloPage);
|
||||
AddPadded(SoloPage, MakeLabel(TEXT("SoloTitle"), TEXT("Singleplayer"), 28.f), 4.f);
|
||||
AddPadded(SoloPage, MakeLabel(TEXT("SoloMapLbl"), TEXT("Map"), 14.f), 2.f);
|
||||
MapCombo = WidgetTree->ConstructWidget<UComboBoxString>(UComboBoxString::StaticClass(), TEXT("MapCombo"));
|
||||
{
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("MapComboSize"));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetContent(MapCombo);
|
||||
AddPadded(SoloPage, S, 4.f);
|
||||
}
|
||||
{
|
||||
UButton* Play = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("PlaySoloBtn"));
|
||||
StyleMenuButton(Play);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("PlaySoloSize"));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetHeightOverride(46.f);
|
||||
S->SetContent(Play);
|
||||
Play->SetContent(MakeLabel(TEXT("PlaySoloLbl"), TEXT("Play World"), 18.f));
|
||||
Play->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnPlaySoloClicked);
|
||||
AddPadded(SoloPage, S, 8.f);
|
||||
}
|
||||
{
|
||||
UButton* Back = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("SoloBackBtn"));
|
||||
StyleMenuButton(Back);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("SoloBackSize"));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetHeightOverride(40.f);
|
||||
S->SetContent(Back);
|
||||
Back->SetContent(MakeLabel(TEXT("SoloBackLbl"), TEXT("Back"), 16.f));
|
||||
Back->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnBackClicked);
|
||||
AddPadded(SoloPage, S, 4.f);
|
||||
}
|
||||
|
||||
// ---- Multiplayer page ----
|
||||
UVerticalBox* MpPage = WidgetTree->ConstructWidget<UVerticalBox>(UVerticalBox::StaticClass(), TEXT("MpPage"));
|
||||
PageSwitcher->AddChild(MpPage);
|
||||
AddPadded(MpPage, MakeLabel(TEXT("MpTitle"), TEXT("Multiplayer"), 28.f), 4.f);
|
||||
|
||||
auto AddField = [&](UVerticalBox* Page, const TCHAR* LabelName, const TCHAR* Label, UWidget* Field, const TCHAR* SizeName)
|
||||
{
|
||||
AddPadded(Page, MakeLabel(LabelName, Label, 13.f), 2.f);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), SizeName);
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetContent(Field);
|
||||
AddPadded(Page, S, 2.f);
|
||||
};
|
||||
|
||||
AddToColumn(MakeLabel(WidgetTree, TEXT("Title"), TEXT("VocationLife — Start Menu")));
|
||||
AddPadded(MpPage, MakeLabel(TEXT("MpMapLbl"), TEXT("Map"), 13.f), 2.f);
|
||||
MpMapCombo = WidgetTree->ConstructWidget<UComboBoxString>(UComboBoxString::StaticClass(), TEXT("MpMapCombo"));
|
||||
{
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("MpMapComboSize"));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetContent(MpMapCombo);
|
||||
AddPadded(MpPage, S, 2.f);
|
||||
}
|
||||
|
||||
AddToColumn(MakeLabel(WidgetTree, TEXT("MapLabel"), TEXT("Map")));
|
||||
MapCombo = WidgetTree->ConstructWidget<UComboBoxString>(UComboBoxString::StaticClass(), TEXT("MapCombo"));
|
||||
AddToColumn(MapCombo);
|
||||
|
||||
AddToColumn(MakeLabel(WidgetTree, TEXT("BackendLabel"), TEXT("Network Backend")));
|
||||
BackendCombo = WidgetTree->ConstructWidget<UComboBoxString>(UComboBoxString::StaticClass(), TEXT("BackendCombo"));
|
||||
BackendCombo->AddOption(TEXT("Auto"));
|
||||
BackendCombo->AddOption(TEXT("Steam"));
|
||||
BackendCombo->AddOption(TEXT("LAN"));
|
||||
BackendCombo->SetSelectedIndex(0);
|
||||
AddToColumn(BackendCombo);
|
||||
AddField(MpPage, TEXT("BackendLbl"), TEXT("Network"), BackendCombo, TEXT("BackendSize"));
|
||||
|
||||
AddToColumn(MakeLabel(WidgetTree, TEXT("NameLabel"), TEXT("Server Name")));
|
||||
ServerNameBox = WidgetTree->ConstructWidget<UEditableTextBox>(UEditableTextBox::StaticClass(), TEXT("ServerNameBox"));
|
||||
ServerNameBox->SetText(FText::FromString(TEXT("VocationLife")));
|
||||
AddToColumn(ServerNameBox);
|
||||
AddField(MpPage, TEXT("NameLbl"), TEXT("Server Name"), ServerNameBox, TEXT("NameSize"));
|
||||
|
||||
AddToColumn(MakeLabel(WidgetTree, TEXT("PortLabel"), TEXT("Host Port")));
|
||||
PortBox = WidgetTree->ConstructWidget<UEditableTextBox>(UEditableTextBox::StaticClass(), TEXT("PortBox"));
|
||||
PortBox->SetText(FText::FromString(TEXT("7777")));
|
||||
AddToColumn(PortBox);
|
||||
AddField(MpPage, TEXT("PortLbl"), TEXT("Host Port"), PortBox, TEXT("PortSize"));
|
||||
|
||||
AddToColumn(MakeLabel(WidgetTree, TEXT("MaxLabel"), TEXT("Max Players")));
|
||||
MaxPlayersBox = WidgetTree->ConstructWidget<UEditableTextBox>(UEditableTextBox::StaticClass(), TEXT("MaxPlayersBox"));
|
||||
MaxPlayersBox->SetText(FText::FromString(TEXT("4")));
|
||||
AddToColumn(MaxPlayersBox);
|
||||
AddField(MpPage, TEXT("MaxLbl"), TEXT("Max Players"), MaxPlayersBox, TEXT("MaxSize"));
|
||||
|
||||
HostButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("HostButton"));
|
||||
auto AddMpButton = [&](const TCHAR* Name, const TCHAR* Label, TFunction<void()> Bind)
|
||||
{
|
||||
UTextBlock* L = MakeLabel(WidgetTree, TEXT("HostBtnLabel"), TEXT("Host Game"));
|
||||
HostButton->SetContent(L);
|
||||
}
|
||||
HostButton->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnHostClicked);
|
||||
AddToColumn(HostButton);
|
||||
UButton* B = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), Name);
|
||||
StyleMenuButton(B);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), *FString::Printf(TEXT("%sSize"), Name));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetHeightOverride(42.f);
|
||||
S->SetContent(B);
|
||||
B->SetContent(MakeLabel(*FString::Printf(TEXT("%sLbl"), Name), Label, 16.f));
|
||||
Bind();
|
||||
AddPadded(MpPage, S, 4.f);
|
||||
return B;
|
||||
};
|
||||
|
||||
SoloButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("SoloButton"));
|
||||
{
|
||||
UTextBlock* L = MakeLabel(WidgetTree, TEXT("SoloBtnLabel"), TEXT("Play Solo (selected map)"));
|
||||
SoloButton->SetContent(L);
|
||||
UButton* B = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("HostBtn"));
|
||||
StyleMenuButton(B);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("HostBtnSize"));
|
||||
S->SetWidthOverride(400.f); S->SetHeightOverride(42.f); S->SetContent(B);
|
||||
B->SetContent(MakeLabel(TEXT("HostBtnLbl"), TEXT("Host Game"), 16.f));
|
||||
B->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnHostClicked);
|
||||
AddPadded(MpPage, S, 4.f);
|
||||
}
|
||||
{
|
||||
UButton* B = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("FindSteamBtn"));
|
||||
StyleMenuButton(B);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("FindSteamBtnSize"));
|
||||
S->SetWidthOverride(400.f); S->SetHeightOverride(42.f); S->SetContent(B);
|
||||
B->SetContent(MakeLabel(TEXT("FindSteamBtnLbl"), TEXT("Find Steam Games"), 16.f));
|
||||
B->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnFindSteamClicked);
|
||||
AddPadded(MpPage, S, 4.f);
|
||||
}
|
||||
{
|
||||
UButton* B = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("FindLanBtn"));
|
||||
StyleMenuButton(B);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("FindLanBtnSize"));
|
||||
S->SetWidthOverride(400.f); S->SetHeightOverride(42.f); S->SetContent(B);
|
||||
B->SetContent(MakeLabel(TEXT("FindLanBtnLbl"), TEXT("Find LAN Games"), 16.f));
|
||||
B->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnFindLanClicked);
|
||||
AddPadded(MpPage, S, 4.f);
|
||||
}
|
||||
SoloButton->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnSoloClicked);
|
||||
AddToColumn(SoloButton);
|
||||
|
||||
UHorizontalBox* FindRow = WidgetTree->ConstructWidget<UHorizontalBox>(UHorizontalBox::StaticClass(), TEXT("FindRow"));
|
||||
FindSteamButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("FindSteamButton"));
|
||||
FindSteamButton->SetContent(MakeLabel(WidgetTree, TEXT("FindSteamLbl"), TEXT("Find Steam")));
|
||||
FindSteamButton->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnFindSteamClicked);
|
||||
FindLanButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("FindLanButton"));
|
||||
FindLanButton->SetContent(MakeLabel(WidgetTree, TEXT("FindLanLbl"), TEXT("Find LAN")));
|
||||
FindLanButton->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnFindLanClicked);
|
||||
FindRow->AddChildToHorizontalBox(FindSteamButton);
|
||||
FindRow->AddChildToHorizontalBox(FindLanButton);
|
||||
AddToColumn(FindRow);
|
||||
|
||||
AddToColumn(MakeLabel(WidgetTree, TEXT("SessionsLabel"), TEXT("Found Sessions")));
|
||||
SessionCombo = WidgetTree->ConstructWidget<UComboBoxString>(UComboBoxString::StaticClass(), TEXT("SessionCombo"));
|
||||
AddToColumn(SessionCombo);
|
||||
AddField(MpPage, TEXT("SessionsLbl"), TEXT("Found Sessions"), SessionCombo, TEXT("SessionSize"));
|
||||
{
|
||||
UButton* B = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("JoinBtn"));
|
||||
StyleMenuButton(B);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("JoinBtnSize"));
|
||||
S->SetWidthOverride(400.f); S->SetHeightOverride(42.f); S->SetContent(B);
|
||||
B->SetContent(MakeLabel(TEXT("JoinBtnLbl"), TEXT("Join Selected"), 16.f));
|
||||
B->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnJoinSelectedClicked);
|
||||
AddPadded(MpPage, S, 4.f);
|
||||
}
|
||||
|
||||
JoinButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("JoinButton"));
|
||||
JoinButton->SetContent(MakeLabel(WidgetTree, TEXT("JoinBtnLabel"), TEXT("Join Selected Session")));
|
||||
JoinButton->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnJoinSelectedClicked);
|
||||
AddToColumn(JoinButton);
|
||||
|
||||
AddToColumn(MakeLabel(WidgetTree, TEXT("IpLabel"), TEXT("Direct Connect IP")));
|
||||
IpBox = WidgetTree->ConstructWidget<UEditableTextBox>(UEditableTextBox::StaticClass(), TEXT("IpBox"));
|
||||
IpBox->SetText(FText::FromString(TEXT("127.0.0.1")));
|
||||
AddToColumn(IpBox);
|
||||
AddField(MpPage, TEXT("IpLbl"), TEXT("Direct Connect IP"), IpBox, TEXT("IpSize"));
|
||||
|
||||
AddToColumn(MakeLabel(WidgetTree, TEXT("JoinPortLabel"), TEXT("Direct Connect Port")));
|
||||
JoinPortBox = WidgetTree->ConstructWidget<UEditableTextBox>(UEditableTextBox::StaticClass(), TEXT("JoinPortBox"));
|
||||
JoinPortBox->SetText(FText::FromString(TEXT("7777")));
|
||||
AddToColumn(JoinPortBox);
|
||||
AddField(MpPage, TEXT("JoinPortLbl"), TEXT("Port"), JoinPortBox, TEXT("JoinPortSize"));
|
||||
{
|
||||
UButton* B = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("ConnectBtn"));
|
||||
StyleMenuButton(B);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("ConnectBtnSize"));
|
||||
S->SetWidthOverride(400.f); S->SetHeightOverride(42.f); S->SetContent(B);
|
||||
B->SetContent(MakeLabel(TEXT("ConnectBtnLbl"), TEXT("Connect by IP:Port"), 16.f));
|
||||
B->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnConnectIpClicked);
|
||||
AddPadded(MpPage, S, 4.f);
|
||||
}
|
||||
{
|
||||
UButton* B = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("MpBackBtn"));
|
||||
StyleMenuButton(B);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), TEXT("MpBackBtnSize"));
|
||||
S->SetWidthOverride(400.f); S->SetHeightOverride(42.f); S->SetContent(B);
|
||||
B->SetContent(MakeLabel(TEXT("MpBackBtnLbl"), TEXT("Back"), 16.f));
|
||||
B->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnBackClicked);
|
||||
AddPadded(MpPage, S, 4.f);
|
||||
}
|
||||
|
||||
ConnectIpButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), TEXT("ConnectIpButton"));
|
||||
ConnectIpButton->SetContent(MakeLabel(WidgetTree, TEXT("ConnectIpLbl"), TEXT("Connect by IP:Port")));
|
||||
ConnectIpButton->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnConnectIpClicked);
|
||||
AddToColumn(ConnectIpButton);
|
||||
// ---- Options page ----
|
||||
UVerticalBox* OptPage = WidgetTree->ConstructWidget<UVerticalBox>(UVerticalBox::StaticClass(), TEXT("OptPage"));
|
||||
PageSwitcher->AddChild(OptPage);
|
||||
AddPadded(OptPage, MakeLabel(TEXT("OptTitle"), TEXT("Options"), 28.f), 4.f);
|
||||
AddPadded(OptPage, MakeLabel(TEXT("GfxLbl"), TEXT("Graphics Preset"), 14.f), 4.f);
|
||||
|
||||
StatusText = MakeLabel(WidgetTree, TEXT("Status"), TEXT("Ready"));
|
||||
AddToColumn(StatusText);
|
||||
auto AddGfxButton = [&](const TCHAR* Name, const TCHAR* Label)
|
||||
{
|
||||
UButton* B = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), Name);
|
||||
StyleMenuButton(B);
|
||||
USizeBox* S = WidgetTree->ConstructWidget<USizeBox>(USizeBox::StaticClass(), *FString::Printf(TEXT("%sSize"), Name));
|
||||
S->SetWidthOverride(400.f);
|
||||
S->SetHeightOverride(40.f);
|
||||
S->SetContent(B);
|
||||
B->SetContent(MakeLabel(*FString::Printf(TEXT("%sLbl"), Name), Label, 16.f));
|
||||
AddPadded(OptPage, S, 4.f);
|
||||
return B;
|
||||
};
|
||||
|
||||
AddGfxButton(TEXT("GfxLow"), TEXT("Low"))->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnGraphicsLow);
|
||||
AddGfxButton(TEXT("GfxMed"), TEXT("Medium"))->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnGraphicsMedium);
|
||||
AddGfxButton(TEXT("GfxHigh"), TEXT("High"))->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnGraphicsHigh);
|
||||
AddGfxButton(TEXT("GfxUltra"), TEXT("Ultra"))->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnGraphicsUltra);
|
||||
AddGfxButton(TEXT("GfxRT"), TEXT("Ray Tracing"))->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnGraphicsRayTracing);
|
||||
AddGfxButton(TEXT("OptBack"), TEXT("Back"))->OnClicked.AddDynamic(this, &UVocationMainMenuWidget::OnBackClicked);
|
||||
|
||||
StatusText = MakeLabel(TEXT("Status"), TEXT(""), 13.f);
|
||||
StatusText->SetColorAndOpacity(FSlateColor(FLinearColor(0.75f, 0.8f, 0.85f, 1.f)));
|
||||
AddPadded(CenterColumn, StatusText, 12.f);
|
||||
|
||||
VersionText = MakeLabel(TEXT("Version"), TEXT("VocationLife 0.1.0"), 12.f);
|
||||
VersionText->SetJustification(ETextJustify::Left);
|
||||
if (UOverlaySlot* VerSlot = Overlay->AddChildToOverlay(VersionText))
|
||||
{
|
||||
VerSlot->SetHorizontalAlignment(HAlign_Left);
|
||||
VerSlot->SetVerticalAlignment(VAlign_Bottom);
|
||||
VerSlot->SetPadding(FMargin(16.f));
|
||||
}
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::ShowPage(EMenuPage Page)
|
||||
{
|
||||
if (PageSwitcher)
|
||||
{
|
||||
PageSwitcher->SetActiveWidgetIndex(static_cast<int32>(Page));
|
||||
}
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::RefreshMaps()
|
||||
{
|
||||
CachedMaps = UVocationServerSettings::GetAvailableMaps();
|
||||
if (!MapCombo)
|
||||
auto Fill = [this](UComboBoxString* Combo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
MapCombo->ClearOptions();
|
||||
for (const FVocationMapOption& Map : CachedMaps)
|
||||
{
|
||||
MapCombo->AddOption(Map.DisplayName);
|
||||
}
|
||||
if (CachedMaps.Num() > 0)
|
||||
{
|
||||
MapCombo->SetSelectedIndex(0);
|
||||
}
|
||||
if (!Combo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Combo->ClearOptions();
|
||||
for (const FVocationMapOption& Map : CachedMaps)
|
||||
{
|
||||
Combo->AddOption(Map.DisplayName);
|
||||
}
|
||||
if (CachedMaps.Num() > 0)
|
||||
{
|
||||
Combo->SetSelectedIndex(0);
|
||||
}
|
||||
};
|
||||
Fill(MapCombo);
|
||||
Fill(MpMapCombo);
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::SetStatus(const FString& Message)
|
||||
@ -189,16 +447,38 @@ void UVocationMainMenuWidget::LeaveStartMenu()
|
||||
{
|
||||
GI->MarkGameplayStarted();
|
||||
}
|
||||
|
||||
if (APlayerController* PC = GetOwningPlayer())
|
||||
{
|
||||
PC->bShowMouseCursor = false;
|
||||
PC->SetInputMode(FInputModeGameOnly());
|
||||
}
|
||||
|
||||
RemoveFromParent();
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::OnSingleplayerClicked() { ShowPage(EMenuPage::Singleplayer); }
|
||||
void UVocationMainMenuWidget::OnMultiplayerClicked() { ShowPage(EMenuPage::Multiplayer); }
|
||||
void UVocationMainMenuWidget::OnOptionsClicked() { ShowPage(EMenuPage::Options); }
|
||||
void UVocationMainMenuWidget::OnBackClicked() { ShowPage(EMenuPage::Main); }
|
||||
|
||||
void UVocationMainMenuWidget::OnQuitClicked()
|
||||
{
|
||||
if (APlayerController* PC = GetOwningPlayer())
|
||||
{
|
||||
UKismetSystemLibrary::QuitGame(this, PC, EQuitPreference::Quit, false);
|
||||
}
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::OnPlaySoloClicked()
|
||||
{
|
||||
if (UVocationSessionSubsystem* Sessions = GetGameInstance()->GetSubsystem<UVocationSessionSubsystem>())
|
||||
{
|
||||
const int32 MapIndex = MapCombo ? MapCombo->GetSelectedIndex() : 0;
|
||||
const FString MapPath = CachedMaps.IsValidIndex(MapIndex) ? CachedMaps[MapIndex].MapPath : TEXT("/Engine/Maps/Entry");
|
||||
LeaveStartMenu();
|
||||
Sessions->TravelToMap(MapPath, false, 7777);
|
||||
}
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::OnHostClicked()
|
||||
{
|
||||
UVocationSessionSubsystem* Sessions = GetGameInstance() ? GetGameInstance()->GetSubsystem<UVocationSessionSubsystem>() : nullptr;
|
||||
@ -207,7 +487,7 @@ void UVocationMainMenuWidget::OnHostClicked()
|
||||
return;
|
||||
}
|
||||
|
||||
const int32 MapIndex = MapCombo ? MapCombo->GetSelectedIndex() : 0;
|
||||
const int32 MapIndex = MpMapCombo ? MpMapCombo->GetSelectedIndex() : 0;
|
||||
const FString MapPath = CachedMaps.IsValidIndex(MapIndex) ? CachedMaps[MapIndex].MapPath : TEXT("/Engine/Maps/Entry");
|
||||
const int32 Port = PortBox ? FCString::Atoi(*PortBox->GetText().ToString()) : 7777;
|
||||
const int32 MaxPlayers = MaxPlayersBox ? FCString::Atoi(*MaxPlayersBox->GetText().ToString()) : 4;
|
||||
@ -227,7 +507,7 @@ void UVocationMainMenuWidget::OnFindSteamClicked()
|
||||
{
|
||||
if (UVocationSessionSubsystem* Sessions = GetGameInstance()->GetSubsystem<UVocationSessionSubsystem>())
|
||||
{
|
||||
SetStatus(TEXT("Searching Steam sessions..."));
|
||||
SetStatus(TEXT("Searching Steam..."));
|
||||
Sessions->FindSessions(EVocationNetBackend::Steam, false);
|
||||
}
|
||||
}
|
||||
@ -236,7 +516,7 @@ void UVocationMainMenuWidget::OnFindLanClicked()
|
||||
{
|
||||
if (UVocationSessionSubsystem* Sessions = GetGameInstance()->GetSubsystem<UVocationSessionSubsystem>())
|
||||
{
|
||||
SetStatus(TEXT("Searching LAN sessions..."));
|
||||
SetStatus(TEXT("Searching LAN..."));
|
||||
Sessions->FindSessions(EVocationNetBackend::LAN, true);
|
||||
}
|
||||
}
|
||||
@ -251,7 +531,7 @@ void UVocationMainMenuWidget::OnJoinSelectedClicked()
|
||||
SetStatus(TEXT("No session selected"));
|
||||
return;
|
||||
}
|
||||
SetStatus(TEXT("Joining session..."));
|
||||
SetStatus(TEXT("Joining..."));
|
||||
LeaveStartMenu();
|
||||
Sessions->JoinSessionByIndex(Index);
|
||||
}
|
||||
@ -263,20 +543,54 @@ void UVocationMainMenuWidget::OnConnectIpClicked()
|
||||
{
|
||||
const FString IP = IpBox ? IpBox->GetText().ToString() : TEXT("127.0.0.1");
|
||||
const int32 Port = JoinPortBox ? FCString::Atoi(*JoinPortBox->GetText().ToString()) : 7777;
|
||||
SetStatus(FString::Printf(TEXT("Connecting to %s:%d ..."), *IP, Port));
|
||||
SetStatus(FString::Printf(TEXT("Connecting %s:%d"), *IP, Port));
|
||||
LeaveStartMenu();
|
||||
Sessions->ConnectByIP(IP, Port);
|
||||
}
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::OnSoloClicked()
|
||||
void UVocationMainMenuWidget::OnGraphicsLow()
|
||||
{
|
||||
if (UVocationSessionSubsystem* Sessions = GetGameInstance()->GetSubsystem<UVocationSessionSubsystem>())
|
||||
if (UVocationGameInstance* GI = GetGameInstance<UVocationGameInstance>())
|
||||
{
|
||||
const int32 MapIndex = MapCombo ? MapCombo->GetSelectedIndex() : 0;
|
||||
const FString MapPath = CachedMaps.IsValidIndex(MapIndex) ? CachedMaps[MapIndex].MapPath : TEXT("/Engine/Maps/Entry");
|
||||
LeaveStartMenu();
|
||||
Sessions->TravelToMap(MapPath, false, 7777);
|
||||
GI->SetGraphicsPreset(EVocationGraphicsPreset::Low, false);
|
||||
SetStatus(TEXT("Graphics: Low"));
|
||||
}
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::OnGraphicsMedium()
|
||||
{
|
||||
if (UVocationGameInstance* GI = GetGameInstance<UVocationGameInstance>())
|
||||
{
|
||||
GI->SetGraphicsPreset(EVocationGraphicsPreset::Medium, false);
|
||||
SetStatus(TEXT("Graphics: Medium"));
|
||||
}
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::OnGraphicsHigh()
|
||||
{
|
||||
if (UVocationGameInstance* GI = GetGameInstance<UVocationGameInstance>())
|
||||
{
|
||||
GI->SetGraphicsPreset(EVocationGraphicsPreset::High, false);
|
||||
SetStatus(TEXT("Graphics: High"));
|
||||
}
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::OnGraphicsUltra()
|
||||
{
|
||||
if (UVocationGameInstance* GI = GetGameInstance<UVocationGameInstance>())
|
||||
{
|
||||
GI->SetGraphicsPreset(EVocationGraphicsPreset::Ultra, false);
|
||||
SetStatus(TEXT("Graphics: Ultra"));
|
||||
}
|
||||
}
|
||||
|
||||
void UVocationMainMenuWidget::OnGraphicsRayTracing()
|
||||
{
|
||||
if (UVocationGameInstance* GI = GetGameInstance<UVocationGameInstance>())
|
||||
{
|
||||
GI->SetGraphicsPreset(EVocationGraphicsPreset::RayTracing, true);
|
||||
SetStatus(TEXT("Graphics: Ray Tracing"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,12 +604,11 @@ void UVocationMainMenuWidget::OnSessionSearchDetailed(const TArray<FVocationSess
|
||||
SessionCombo->ClearOptions();
|
||||
for (const FVocationSessionSearchEntry& Entry : Sessions)
|
||||
{
|
||||
SessionCombo->AddOption(FString::Printf(TEXT("%s [%s] %d/%d %s"),
|
||||
SessionCombo->AddOption(FString::Printf(TEXT("%s [%s] %d/%d"),
|
||||
*Entry.DisplayName,
|
||||
*Entry.MapName,
|
||||
Entry.MaxPlayers - Entry.OpenSlots,
|
||||
Entry.MaxPlayers,
|
||||
Entry.bIsLAN ? TEXT("LAN") : TEXT("Online")));
|
||||
Entry.MaxPlayers));
|
||||
}
|
||||
if (Sessions.Num() > 0)
|
||||
{
|
||||
@ -310,7 +623,7 @@ void UVocationMainMenuWidget::OnSessionSearchDetailed(const TArray<FVocationSess
|
||||
|
||||
void UVocationMainMenuWidget::OnSessionJoined(bool bSuccess)
|
||||
{
|
||||
SetStatus(bSuccess ? TEXT("Join/host ok") : TEXT("Join/host failed"));
|
||||
SetStatus(bSuccess ? TEXT("Connected") : TEXT("Connection failed"));
|
||||
if (bSuccess)
|
||||
{
|
||||
LeaveStartMenu();
|
||||
|
||||
@ -12,10 +12,12 @@ class UComboBoxString;
|
||||
class UButton;
|
||||
class UTextBlock;
|
||||
class UVerticalBox;
|
||||
class UHorizontalBox;
|
||||
class UWidgetSwitcher;
|
||||
class UBorder;
|
||||
class USizeBox;
|
||||
|
||||
/**
|
||||
* In-game multiplayer menu: map select, Steam/LAN host, IP:Port join.
|
||||
* Minecraft-style start menu: vertical button stack with submenus.
|
||||
*/
|
||||
UCLASS()
|
||||
class VOCATIONLIFE_API UVocationMainMenuWidget : public UUserWidget
|
||||
@ -27,80 +29,60 @@ public:
|
||||
virtual void NativeDestruct() override;
|
||||
|
||||
protected:
|
||||
enum class EMenuPage : uint8
|
||||
{
|
||||
Main = 0,
|
||||
Singleplayer = 1,
|
||||
Multiplayer = 2,
|
||||
Options = 3
|
||||
};
|
||||
|
||||
void BuildUI();
|
||||
void RefreshMaps();
|
||||
void SetStatus(const FString& Message);
|
||||
|
||||
UFUNCTION()
|
||||
void OnHostClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void OnFindSteamClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void OnFindLanClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void OnJoinSelectedClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void OnConnectIpClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void OnSoloClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void OnSessionSearchDetailed(const TArray<FVocationSessionSearchEntry>& Sessions);
|
||||
|
||||
UFUNCTION()
|
||||
void OnSessionJoined(bool bSuccess);
|
||||
|
||||
void ShowPage(EMenuPage Page);
|
||||
UButton* MakeMenuButton(const FName& Name, const FString& Label, void (UVocationMainMenuWidget::*Callback)());
|
||||
UTextBlock* MakeLabel(const FName& Name, const FString& Text, float Size = 18.f) const;
|
||||
void StyleMenuButton(UButton* Button) const;
|
||||
void LeaveStartMenu();
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UComboBoxString> MapCombo;
|
||||
UFUNCTION() void OnSingleplayerClicked();
|
||||
UFUNCTION() void OnMultiplayerClicked();
|
||||
UFUNCTION() void OnOptionsClicked();
|
||||
UFUNCTION() void OnQuitClicked();
|
||||
UFUNCTION() void OnBackClicked();
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UComboBoxString> BackendCombo;
|
||||
UFUNCTION() void OnPlaySoloClicked();
|
||||
UFUNCTION() void OnHostClicked();
|
||||
UFUNCTION() void OnFindSteamClicked();
|
||||
UFUNCTION() void OnFindLanClicked();
|
||||
UFUNCTION() void OnJoinSelectedClicked();
|
||||
UFUNCTION() void OnConnectIpClicked();
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UComboBoxString> SessionCombo;
|
||||
UFUNCTION() void OnGraphicsLow();
|
||||
UFUNCTION() void OnGraphicsMedium();
|
||||
UFUNCTION() void OnGraphicsHigh();
|
||||
UFUNCTION() void OnGraphicsUltra();
|
||||
UFUNCTION() void OnGraphicsRayTracing();
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UEditableTextBox> ServerNameBox;
|
||||
UFUNCTION() void OnSessionSearchDetailed(const TArray<FVocationSessionSearchEntry>& Sessions);
|
||||
UFUNCTION() void OnSessionJoined(bool bSuccess);
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UEditableTextBox> PortBox;
|
||||
UPROPERTY() TObjectPtr<UWidgetSwitcher> PageSwitcher;
|
||||
UPROPERTY() TObjectPtr<UTextBlock> TitleText;
|
||||
UPROPERTY() TObjectPtr<UTextBlock> SplashText;
|
||||
UPROPERTY() TObjectPtr<UTextBlock> StatusText;
|
||||
UPROPERTY() TObjectPtr<UTextBlock> VersionText;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UEditableTextBox> IpBox;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UEditableTextBox> JoinPortBox;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UEditableTextBox> MaxPlayersBox;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UTextBlock> StatusText;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UButton> HostButton;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UButton> FindSteamButton;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UButton> FindLanButton;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UButton> JoinButton;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UButton> ConnectIpButton;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UButton> SoloButton;
|
||||
UPROPERTY() TObjectPtr<UComboBoxString> MapCombo;
|
||||
UPROPERTY() TObjectPtr<UComboBoxString> MpMapCombo;
|
||||
UPROPERTY() TObjectPtr<UComboBoxString> BackendCombo;
|
||||
UPROPERTY() TObjectPtr<UComboBoxString> SessionCombo;
|
||||
UPROPERTY() TObjectPtr<UEditableTextBox> ServerNameBox;
|
||||
UPROPERTY() TObjectPtr<UEditableTextBox> PortBox;
|
||||
UPROPERTY() TObjectPtr<UEditableTextBox> IpBox;
|
||||
UPROPERTY() TObjectPtr<UEditableTextBox> JoinPortBox;
|
||||
UPROPERTY() TObjectPtr<UEditableTextBox> MaxPlayersBox;
|
||||
|
||||
TArray<FVocationMapOption> CachedMaps;
|
||||
TArray<FVocationSessionSearchEntry> CachedSessions;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user