Skip to main content

Add a Waiting Screen - Login Queue - (Unreal Engine module)

Last updated on June 12, 2024

What's on the menu

The related files are available in the Resources section and consist of the following components:

  • LoginQueueWidget_Starter, a C++ class containing the logic to handle the interactions of the widget.
    • Header file: \Source\AccelByteWars\TutorialModules\Access\LoginQueue\UI\LoginQueueWidget_Starter.h
    • Source file: \Source\AccelByteWars\TutorialModules\Access\LoginQueue\UI\LoginQueueWidget_Starter.cpp
  • W_LoginQueue_Starter, a Blueprint widget created through Unreal Motion Graphics (UMG) and is a descendant of the LoginQueueWidget_Starter class.
    • Widget Blueprint file: \Content\TutorialModules\Access\LoginQueue\UI\W_LoginQueue_Starter.uasset

This menu is attached to the Login menu from Login with device ID module. The login, login failed, and login successful will still be handled by that menu. This menu will handle the waiting in queue and canceling logins while in the queue state.

In order to manipulate the Login menu, the menu has a reference to the Login menu. Here is the declaration of that reference:

private:
UPROPERTY()
ULoginWidget* W_Parent;

The implementation to get that reference is in the OnActivated function:

void ULoginQueueWidget_Starter::NativeOnActivated()
{
...
W_Parent = GetFirstOccurenceOuter<ULoginWidget_Starter>();
...
}

The Login Queue menu also have a reference to a subsystem class that you will implement during the Implement Subsystem step.

protected:
UPROPERTY()
ULoginQueueSubsystem_Starter* LoginQueueSubsystem;
void ULoginQueueWidget_Starter::NativeOnActivated()
{
...
LoginQueueSubsystem = GetGameInstance()->GetSubsystem<ULoginQueueSubsystem_Starter>();
ensure(LoginQueueSubsystem);
...
}

The Login Queue menu has two states:

  • In Queue: showing the queue information and a cancel button.
  • Loading: indicating that the cancel request was sent and is currently waiting for response.

The state changes are possible using the Unreal Motion Graphics's Widget Switcher and references to each state's parent component. Here are the declarations of the mentioned components in the Header file:

private:
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UWidgetSwitcher* Ws_Root;

UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UWidget* W_InQueue;

UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UWidget* W_Loading;

In Queue state

Here, the game shows a cancel button and information about the queue such as estimated waiting time, position in queue, and queue status last updated time.

Preview of In Queue state

Those components are declared in the header file:

    UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_CancelQueue;

UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_PositionInQueue;

UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_EstimatedWaitingTime;

UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_UpdatedAt;

Loading state

This state doesn't really do anything in itself. It is only an indication that the cancel request is currently in process. Therefore, this widget doesn't have any reference in the CPP side.

Preview of Loading state

Ready the menu

  1. Open the LoginQueueWidget_Starter Header file and add the following function declarations. These functions will be used in the canceling login when a user is in queue.

    protected:
    void CancelQueue() const;
    void OnCancelQueueCompleted(const APlayerController* PC, const FOnlineError& Error) const;
  2. Still in the LoginQueueWidget_Starter Header file, add the following function declarations. These functions will handle the In Queue status.

    protected:
    void OnLoginQueued(const APlayerController* PC, const FAccelByteModelsLoginQueueTicketInfo& TicketInfo);
    void OnLoginStatusUpdated(
    const APlayerController* PC,
    const FAccelByteModelsLoginQueueTicketInfo& TicketInfo,
    const FOnlineError& Error) const;
  3. Open the LoginQueueWidget_Starter CPP file and implement the CancelQueue function. For now, this function will simply change state to its loading state.

    void ULoginQueueWidget_Starter::CancelQueue() const
    {
    Ws_Root->SetActiveWidget(W_Loading);
    // TODO: Later, you will have to call te cancel login.
    }
  4. Still in the CPP file, implement the OnCancelQueueCompleted which will be a callback when the game received a response the CancelQueue. This functionality updates the Login menu (its parent menu) with its state based on the response received, whether successful or failed.

    void ULoginQueueWidget_Starter::OnCancelQueueCompleted(const APlayerController* PC, const FOnlineError& Error) const
    {
    // Safety
    if (PC != GetOwningPlayer())
    {
    return;
    }

    if (Error.bSucceeded)
    {
    W_Parent->SetLoginState(ELoginState::Default);
    }
    else
    {
    W_Parent->OnLoginComplete(false, Error.ErrorRaw);
    }
    }
  5. Implement the OnLoginQueued to the CPP file. This function will be a callback when player tries to log in and the server is currently at certain capacity, configurable in Admin Portal, and player was put into a queue on backend. The game will show the In Queue state when this happens.

    void ULoginQueueWidget_Starter::OnLoginQueued(
    const APlayerController* PC,
    const FAccelByteModelsLoginQueueTicketInfo& TicketInfo)
    {
    // safety
    if (PC != GetOwningPlayer())
    {
    return;
    }

    W_Parent->Ws_LoginState->SetActiveWidget(this);
    Btn_CancelQueue->SetUserFocus(GetOwningPlayer());

    Tb_EstimatedWaitingTime->SetText(FText::AsNumber(TicketInfo.EstimatedWaitingTimeInSeconds));
    Tb_PositionInQueue->SetText(FText::AsNumber(TicketInfo.Position));
    Tb_UpdatedAt->SetText(FText::FromString(FDateTime::Now().ToString(TEXT("%H:%M:%S"))));
    Ws_Root->SetActiveWidget(W_InQueue);
    }
  6. Implement the OnLoginStatusUpdated function in the CPP file. This will be a callback when the game received an update on the queue. The game will update its information that it shows to the player.

    void ULoginQueueWidget_Starter::OnLoginStatusUpdated(
    const APlayerController* PC,
    const FAccelByteModelsLoginQueueTicketInfo& TicketInfo,
    const FOnlineError& Error) const
    {
    // safety
    if (PC != GetOwningPlayer())
    {
    return;
    }

    if (!Error.bSucceeded)
    {
    W_Parent->OnLoginComplete(false, Error.ErrorMessage.ToString());
    }

    Tb_EstimatedWaitingTime->SetText(FText::AsNumber(TicketInfo. EstimatedWaitingTimeInSeconds));
    Tb_PositionInQueue->SetText(FText::AsNumber(TicketInfo.Position));
    Tb_UpdatedAt->SetText(FText::FromString(FDateTime::Now().ToString(TEXT("%H:%M:%S"))));
    }
  7. Still in the CPP file, bind the CancelQueue function to the Cancel button in NativeOnActivated and unbind it in NativeOnDeactivated.

    void ULoginQueueWidget_Starter::NativeOnActivated()
    {
    ...
    if (!ensure(W_Parent))
    {
    UE_LOG_LOGIN_QUEUE(Warning, TEXT("Activate Auth Essentials's starter mode or deactivate this module's starter mode to make this widget work properly."))
    return;
    }

    Btn_CancelQueue->OnClicked().AddUObject(this, &ThisClass::CancelQueue);
    ...
    }
    void ULoginQueueWidget_Starter::NativeOnDeactivated()
    {
    Super::NativeOnDeactivated();

    Btn_CancelQueue->OnClicked().RemoveAll(this);
    }
  8. Build the project and open it with the Unreal Editor once it's done.

  9. Open Content\TutorialModules\Access\LoginQueue\DA_LoginQueue.uasset and enable the Is Starter Mode Active. Save the Data Asset.

    Data Asset changes preview Unreal Byte Wars joinable sessions dedicated server

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

Resources