Skip to main content

Match session creation UI - Joinable sessions with dedicated servers - (Unreal Engine module)

Last updated on October 24, 2024

To support both server modes at once (peer-to-peer (P2P) and dedicated server (DS)), separate the menu widget and the widget that connects to the session creation functionality that will be shown inside the menu widget. Those widgets 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. It has been provided for you in the Resources section and consists of two parts:

  • CreateMatchSessionWidget: A C++ class where most of the implementation will be.
    • Header file: \Source\AccelByteWars\TutorialModules\MatchSessionEssentials\UI\CreateMatchSessionWidget.h
    • CPP file: \Source\AccelByteWars\TutorialModules\MatchSessionEssentials\UI\CreateMatchSessionWidget.cpp
  • W_CreateMatchSession: A widget Blueprint class that was created and designed using Unreal Motion Graphics (UMG).
    • Widget Blueprint file: \Content\TutorialModules\MatchSessionEssentials\UI\W_CreateMatchSession.uasset

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 types. In this module, this will display Dedicated Server.
  • 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 the Unreal Motion Graphics'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;
}

DesiredFocusTargetButton = FocusTarget;
FocusTarget->SetUserFocus(GetOwningPlayer());
Ws_ContentOuter->SetActiveWidget(Target);
Btn_GameModeType_BackToCreateSession->SetVisibility(bShowBackButton ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
RequestRefreshFocus();
}

Select Game Mode state

Here, players will see two buttons to select one of the offered game modes, Elimination or Team Deathmatch. Upon clicking the button, the widget will then store what game mode the player have selected.

Preview of the Select Game Mode state Unreal Byte Wars joinable sessions dedicated server

Those buttons are declared in the Header file:

private:
// ...
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:

public:
// ...
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.

Preview of the Select Network Type state Unreal Byte Wars joinable sessions dedicated server

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;
}

Preview of the Loading state Unreal Byte Wars joinable sessions dedicated server

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;
}

Preview of the Error state Unreal Byte Wars joinable sessions dedicated server

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. It is available in the Resources section and is made of two parts:

  • CreateMatchSessionDSWidget_Starter: A C++ class where most of our implementation will be.
    • Header file: \Source\AccelByteWars\TutorialModules\Play\MatchSessionDS\UI\CreateMatchSessionDSWidget_Starter.h
    • CPP file: \Source\AccelByteWars\TutorialModules\MatchSessionDS\UI\CreateMatchSessionDSWidget_Starter.cpp
  • W_CreateMatchSession: A widget Blueprint class that was created and designed using Unreal Motion Graphics (UMG).
    • Widget Blueprint file: \Content\TutorialModules\MatchSessionDS\UI\W_CreateMatchSession.uasset

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.

protected:
// ...
UPROPERTY()
UAccelByteWarsOnlineSessionBase* OnlineSession;
private:
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_StartMatchSessionDS;

UPROPERTY()
UCreateMatchSessionWidget* W_Parent;

The code that assigns the Online Session class and the parent widget is seen on the NativeOnActivated function.

void UCreateMatchSessionDSWidget_Starter::NativeOnActivated()
{
// ...
// Get online session
UOnlineSession* BaseOnlineSession = GetWorld()->GetGameInstance()->GetOnlineSession();
if (!ensure(BaseOnlineSession))
{
return;
}
OnlineSession = Cast<UAccelByteWarsOnlineSessionBase>(BaseOnlineSession);

// Get parent menu widget
W_Parent = GetFirstOccurenceOuter<UCreateMatchSessionWidget>();
if (!ensure(W_Parent))
{
return;
}
// ...
}

Here is a preview of the Create Match Session DS widget.

Preview of the Create Match Session DS widget Unreal Byte Wars joinable sessions dedicated server

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.

  1. Open the CreateMatchSessionDSWidget_Starter Header file and add the following function declarations:

    protected:
    UFUNCTION()
    void CreateSession() const;

    void OnCreateSessionComplete(FName SessionName, bool bSucceeded) const;
  2. Open the CreateMatchSessionDSWidget_Starter CPP file and add the implementations below. In the CreateSession, 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 the OnCreateSessionComplete, 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);
    // ...
    }
    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);
    }
    }
  3. Write code 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;
  4. Open the CreateMatchSessionDSWidget_Starter CPP file and add the function implementations below. For the CancelJoiningSession, change the Create Match Session menu widget state to Loading with the cancel button disabled. If the OnCancelJoiningSessionComplete 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);
    // ...
    }
    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);
    }
    }
  5. You can also let the player know when the dedicated server 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;
  6. 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)
    {
    // Keep showing the loading state until the client travels to the server.
    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);
    }
    }
  7. 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 the NativeOnActivated function and add the following code:

    void UCreateMatchSessionDSWidget_Starter::NativeOnActivated()
    {
    // ...
    Btn_StartMatchSessionDS->OnClicked().AddUObject(this, &ThisClass::CreateSession);
    }
  8. With the binding done, implement code to unbind it when the widget is no longer in use. Still in the CPP file, navigate to NativeOnDeactivated and add the following code:

    void UCreateMatchSessionDSWidget_Starter::NativeOnDeactivated()
    {
    // ...
    Btn_StartMatchSessionDS->OnClicked().RemoveAll(this);
    W_Parent->GetProcessingWidgetComponent()->OnRetryClicked.RemoveAll(this);
    W_Parent->GetProcessingWidgetComponent()->OnCancelClicked.RemoveAll(this);
    }
  9. Build the project and open it with the Unreal Editor once it's done.

  10. In the Unreal Editor, from the Content Browser, navigate to Content\TutorialModules\Play\MatchSessionDS\UI\ and open W_CreateMatchSessionDS_Starter. Make sure that all widgets are bound properly in the Bind Widgets tab and the Parent class is set to CreateMatchSessionDSWidget_Starter.

    Bind widgets tab Unreal Byte Wars joinable sessions dedicated server

  11. Open Content\TutorialModules\Play\MatchSessionDS\DA_MatchSessionDSEssentials.uasset and enable the Is Starter Mode Active. Save the Data Asset.

    Data Asset changes preview Unreal Byte Wars joinable sessions dedicated server

  12. Click Play in the editor. Go to Online Play > Play Online > Create Match Session. The UI will appear if implemented correctly.

Resources