Unreal Engine Module - Create a Joinable Session Using a Dedicated Server - add Create Match Session UI
This tutorial isn't applicable to the AccelByte Gaming Service (AGS) Starter tier. It requires the AccelByte Multiplayer Server (AMS) or Armada, which isn't currently supported on AGS Starter.
To support both server mode at once, Peer to Peer (P2P) and Dedicated Server (DS), separate the menu widget and the widget that actually connects to the session creation functionality which will be shown inside the menu widget. Those widgets, in order, are the Create Match Session widget and Create Match Session DS widget.
In this tutorial, the widget that you'll prepare is the Create Match Session DS.
About the Create Match Session menu
The Create Match Session menu is a widget in Byte Wars used to select the game mode and server type for the session creation.
The Create Match Session menu consists of two parts:
- The C++ class
CreateMatchSessionWidget
, where most of our implementation will be in.- Header file:
\Source\AccelByteWars\TutorialModules\MatchSessionEssentials\UI\CreateMatchSessionWidget.h
- CPP file:
\Source\AccelByteWars\TutorialModules\MatchSessionEssentials\UI\CreateMatchSessionWidget.cpp
- Header file:
- The widget blueprint class
W_CreateMatchSession
that was created and designed using Unreal Motion Graphics (UMG).- Widget Blueprint file:
\Content\TutorialModules\MatchSessionEssentials\UI\W_CreateMatchSession.uasset
- Widget Blueprint file:
The Create Match Session menu has four states:
- Select Game Mode : showing a selection of game modes, which are Elimination and Team Deathmatch.
- Select Network Type : showing a selection of network type. In this module, this will only display DS.
- Loading : showing the creation status and a cancel button.
- Error : showing a retry and back button.
The state changes are possible using a combination of Unreal Motion Graphic's Widget Switcher and our AccelByteWars Widget Switcher. The AccelByteWars Widget Switcher is a custom Widget Switcher with predefined states: empty, loading, error, and success. Here are the declarations of the mentioned components in the header file.
private:
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UWidgetSwitcher- Ws_ContentOuter;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UAccelByteWarsWidgetSwitcher- Ws_Processing;
To switch between states, the Create Match Session widget has the following function:
void UCreateMatchSessionWidget::SwitchContent(const EContentType ContentType)
{
UWidget- Target = nullptr;
UWidget- FocusTarget = Btn_GameModeType_BackToCreateSession;
bool bShowBackButton = true;
switch (ContentType)
{
case EContentType::SELECT_GAMEMODE:
Target = W_SelectGameModeType;
CameraTargetY = 600.0f;
FocusTarget = Btn_Elimination;
break;
case EContentType::SELECT_NETWORKTYPE:
Target = W_SelectGameModeNetworkType;
CameraTargetY = 750.0f;
FocusTarget = W_SelectGameModeNetworkTypeButtonOuter->HasAnyChildren() ?
W_SelectGameModeNetworkTypeButtonOuter->GetChildAt(0) :
Btn_ServerType_BackToCreateSession;
break;
case EContentType::LOADING:
Target = W_Processing;
CameraTargetY = 825.0f;
Ws_Processing->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Loading);
FocusTarget = Ws_Processing;
bShowBackButton = false;
break;
case EContentType::ERROR:
Target = W_Processing;
Ws_Processing->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error);
CameraTargetY = 825.0f;
FocusTarget = Ws_Processing;
bShowBackButton = false;
break;
}
FocusTarget->SetUserFocus(GetOwningPlayer());
Ws_ContentOuter->SetActiveWidget(Target);
Btn_GameModeType_BackToCreateSession->SetVisibility(bShowBackButton ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
}
Select Game Mode state
Here, players will see two buttons to select one of the offered game mode, Elimination or Team Deathmatch. Upon clicking the button, the widget will then store what game mode the player have selected.
Those buttons are declared in the header file.
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase- Btn_Elimination;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase- Btn_TeamDeathMatch;
The stored selected game mode can be accessed via this function.
EGameModeType GetSelectedGameModeType() const { return SelectedGameModeType; }
Select Network Type state
This state is where the player can select which network type the session will use. By default, this state is empty. This is where you will attach your Create Match Session DS widget to.
Loading state
This state is comprised of a loading message, which can be set to any message and a cancel button that can be enabled and disabled. To do so, call SetLoadingMessage
just before calling SwitchContent(EContentType::LOADING)
.
void UCreateMatchSessionWidget::SetLoadingMessage(const FText& Message, const bool bEnableCancelButton) const
{
Ws_Processing->LoadingMessage = Message;
Ws_Processing->bEnableCancelButton = bEnableCancelButton;
}
Error state
This state is comprised of an error message, which can be set to any message and a retry button that can be enabled and disabled. To do so, call SetErrorMessage
just before calling SwitchContent(EContentType::Error)
.
void UCreateMatchSessionWidget::SetErrorMessage(const FText& Message, const bool bShowRetryButton) const
{
Ws_Processing->ErrorMessage = Message;
Ws_Processing->bShowRetryButtonOnError = bShowRetryButton;
}
About the Create Match Session DS
The Create Match Session DS widget consists of only one button that will be spawned inside the Create Match Session menu.
The Create Match Session DS widget consists of two parts:
- The C++ class
CreateMatchSessionDSWidget_Starter
where most of our implementation will be in.- Header file:
\Source\AccelByteWars\TutorialModules\Play\MatchSessionDS\UI\CreateMatchSessionDSWidget_Starter.h
- CPP file:
\Source\AccelByteWars\TutorialModules\MatchSessionDS\UI\CreateMatchSessionDSWidget_Starter.cpp
- Header file:
- The widget blueprint class
W_CreateMatchSession
that was created and designed using Unreal Motion Graphics (UMG).- Widget Blueprint file:
\Content\TutorialModules\MatchSessionDS\UI\W_CreateMatchSession.uasset
- Widget Blueprint file:
In the header file, you will see OnlineSession
, which is your gateway to the session functionalities, the button itself, and a pointer to the parent widget.
private:
UPROPERTY()
UAccelByteWarsOnlineSessionBase- OnlineSession;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase- Btn_StartMatchSessionDS;
UPROPERTY()
UCreateMatchSessionWidget- W_Parent;
The codes that assigned the Online Session class and to the parent widget is seen on the NativeOnActivated
function.
void UCreateMatchSessionDSWidget_Starter::NativeOnActivated()
{
Super::NativeOnActivated();
UOnlineSession- BaseOnlineSession = GetWorld()->GetGameInstance()->GetOnlineSession();
if (!ensure(BaseOnlineSession))
{
return;
}
OnlineSession = Cast<UAccelByteWarsOnlineSessionBase>(BaseOnlineSession);
W_Parent = GetFirstOccurenceOuter<UCreateMatchSessionWidget>();
if (!ensure(W_Parent))
{
return;
}
...
}
Here is a preview of the Create Match Session DS widget.
Ready the Create Match Session DS widget
The functionalities needed for the Create Match Session DS widget are the create session and the cancel joining session. You are going to prepare the widget for those functionalities.
Open the
CreateMatchSessionDSWidget_Starter
header file and add the following function declarations:protected:
UFUNCTION()
void CreateSession() const;
void OnCreateSessionComplete(FName SessionName, bool bSucceeded) const;On to the implementation, open the
CreateMatchSessionDSWidget_Starter
CPP file and add these implementations. In theCreateSession
, change the Create Match Session menu widget state to its "Loading" state with the Cancel button disabled since the request can't be canceled while it's being sent. For theOnCreateSessionComplete
, if the request succeeds, change the menu widget state to "Loading" with the Cancel button enabled. If not, change the menu widget state to Error.void UCreateMatchSessionDSWidget_Starter::CreateSession() const
{
if (OnlineSession->ValidateToStartSession.IsBound() &&
!OnlineSession->ValidateToStartSession.Execute())
{
return;
}
W_Parent->SetLoadingMessage(TEXT_REQUESTING_SESSION_CREATION, false);
W_Parent->SwitchContent(UCreateMatchSessionWidget::EContentType::LOADING);
// TODO: Call the session creation through Online Session
}
void UCreateMatchSessionDSWidget_Starter::OnCreateSessionComplete(FName SessionName, bool bSucceeded) const
{
// Abort if not a game session.
if (!SessionName.IsEqual(OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession)))
{
return;
}
if (bSucceeded)
{
W_Parent->SetLoadingMessage(TEXT_JOINING_SESSION, true);
W_Parent->SwitchContent(UCreateMatchSessionWidget::EContentType::LOADING);
}
else
{
W_Parent->SetErrorMessage(TEXT_FAILED_TO_CREATE_SESSION, true);
W_Parent->SwitchContent(UCreateMatchSessionWidget::EContentType::ERROR);
}
}Now, write codes for the cancel joining functionality. Go back to
CreateMatchSessionDSWidget_Starter
header file and add the following function declarations:protected:
UFUNCTION()
void CancelJoiningSession() const;
void OnCancelJoiningSessionComplete(FName SessionName, bool bSucceeded) const;Next, open the
CreateMatchSessionDSWidget_Starter
CPP file and add these function implementations. For theCancelJoiningSession
, change the Create Match Session menu widget state to Loading with the Cancel button disabled. If theOnCancelJoiningSessionComplete
succeeds, transition back to the "Select Game Mode" state. Otherwise, transition to the "Error" state.void UCreateMatchSessionDSWidget_Starter::CancelJoiningSession() const
{
W_Parent->SetLoadingMessage(TEXT_LEAVING_SESSION, false);
W_Parent->SwitchContent(UCreateMatchSessionWidget::EContentType::LOADING);
// TODO: Call the cancel joining functionality through Online Session
}
void UCreateMatchSessionDSWidget_Starter::OnCancelJoiningSessionComplete(FName SessionName, bool bSucceeded) const
{
// Abort if not a game session.
if (!SessionName.IsEqual(OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession)))
{
return;
}
if (bSucceeded)
{
W_Parent->SwitchContent(UCreateMatchSessionWidget::EContentType::SELECT_GAMEMODE);
}
else
{
W_Parent->SetErrorMessage(TEXT_FAILED_TO_LEAVE_SESSION, false);
W_Parent->SwitchContent(UCreateMatchSessionWidget::EContentType::ERROR);
}
}You can also let the player know when the DS is ready or when there's an error. Go back to the
CreateMatchSessionDSWidget_Starter
header file and add this function declaration.protected:
void OnSessionServerUpdateReceived(
const FName SessionName,
const FOnlineError& Error,
const bool bHasClientTravelTriggered) const;Open the
CreateMatchSessionDSWidget_Starter
CPP file and add this function implementation. If this function succeeds, change the loading message. Otherwise, show the error.void UCreateMatchSessionDSWidget_Starter::OnSessionServerUpdateReceived(
const FName SessionName,
const FOnlineError& Error,
const bool bHasClientTravelTriggered) const
{
// Abort if not a game session.
if (!SessionName.IsEqual(OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession)))
{
return;
}
if (Error.bSucceeded && !bHasClientTravelTriggered)
{
// waiting for further update
W_Parent->SetLoadingMessage(TEXT_JOINING_SESSION, true);
W_Parent->SwitchContent(UCreateMatchSessionWidget::EContentType::LOADING);
}
else if (!bHasClientTravelTriggered && !Error.bSucceeded)
{
W_Parent->SetErrorMessage(TEXT_FAILED_TO_JOIN_SESSION, false);
W_Parent->SwitchContent(UCreateMatchSessionWidget::EContentType::ERROR);
}
}Now that you have all the functions declared and implemented, you can bind the widget components to those functions. In
CreateMatchSessionDSWidget_Starter
CPP file, navigate to theNativeOnActivated
function and add the highlighted lines in the following codes:void UCreateMatchSessionDSWidget_Starter::NativeOnActivated()
{
...
// TODO: Add your Online Session delegates setup here
Btn_StartMatchSessionDS->OnClicked().AddUObject(this, &ThisClass::CreateSession);
W_Parent->GetProcessingWidgetComponent()->OnCancelClicked.AddUObject(this, &ThisClass::CancelJoiningSession);
W_Parent->GetProcessingWidgetComponent()->OnRetryClicked.AddUObject(this, &ThisClass::CreateSession);
}With the binding done, it's time to implement codes to unbind it when the widget is no longer in use. Still in the CPP file, navigate to
NativeOnDeactivated
and add the highlighted lines in the following codes:void UCreateMatchSessionDSWidget_Starter::NativeOnDeactivated()
{
...
// TODO: Add your Online Session delegates cleanup here
Btn_StartMatchSessionDS->OnClicked().RemoveAll(this);
W_Parent->GetProcessingWidgetComponent()->OnRetryClicked.RemoveAll(this);
W_Parent->GetProcessingWidgetComponent()->OnCancelClicked.RemoveAll(this);
}Now, build the
AccelByteWars
project and open it with Unreal Editor once it's done building.In the Unreal Editor, from the Content Browser, navigate to
Content\TutorialModules\Play\MatchSessionDS\UI\
and openW_CreateMatchSessionDS_Starter
. Make sure that all widgets are bound properly in the Bind Widgets tab, stacked just beside the Hierarchy tab by default, and the Parent class is set toCreateMatchSessionDSWidget_Starter
.To test out the Create Match Session DS widget, open
Content\TutorialModules\Play\MatchSessionDS\DA_MatchSessionDSEssentials.uasset
and enable theIs Starter Mode Active
. Save the Data Asset.Click Play in the editor, then go to Online Play > Play Online > Create Match Session. The starter UI appears.
Congratulations! You have finished setting up the Create Match Session DS widget.
Resources
- The files used in this tutorial section are available in the Byte Wars GitHub repository.
- AccelByteWars/Content/TutorialModules/Play/MatchSessionDS/UI/W_CreateMatchSessionDS_Starter.uasset
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/UI/CreateMatchSessionDSWidget_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/UI/CreateMatchSessionDSWidget_Starter.cpp
- AccelByteWars/Content/TutorialModules/Play/MatchSessionDS/UI/DA_MatchSessionDSEssentials.uasset