Add a Waiting Screen - Login Queue - (Unreal Engine module)
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
- Header file:
W_LoginQueue_Starter
, a Blueprint widget created through Unreal Motion Graphics (UMG) and is a descendant of theLoginQueueWidget_Starter
class.- Widget Blueprint file:
\Content\TutorialModules\Access\LoginQueue\UI\W_LoginQueue_Starter.uasset
- Widget Blueprint file:
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 cancelling 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_Starter* W_Parent;
The implementation to get that reference is in the OnActivated
function:
void ULoginQueueWidget_Starter::NativeOnActivated()
{
// ...
W_Parent = GetFirstOccurenceOuter<ULoginWidget_Starter>();
if (!ensure(W_Parent))
{
UE_LOG_LOGIN_QUEUE(Warning, TEXT("Deactivate Auth Essentials's starter mode or activate this module's starter mode to make this widget work properly."))
return;
}
// ...
}
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>();
// ...
}
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.
Those components are declared in the header file:
private:
// ...
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.
Ready the menu
Open the
LoginQueueWidget_Starter
Header file and add the following function declarations. These functions will be used to cancel login when a user is in queue.protected:
void CancelQueue() const;
void OnCancelQueueCompleted(const APlayerController* PC, const FOnlineError& Error) const;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;Open the
LoginQueueWidget_Starter
CPP file and implement theCancelQueue
function. For now, this function will simply change state to its loading state.void ULoginQueueWidget_Starter::CancelQueue() const
{
Ws_Root->SetActiveWidget(W_Loading);
// ...
}Still in the CPP file, implement the
OnCancelQueueCompleted
which will be a callback when the game received a response theCancelQueue
. 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
{
// Abort if Player Controller is not the current player.
if (PC != GetOwningPlayer())
{
return;
}
if (Error.bSucceeded)
{
W_Parent->SetLoginState(ELoginState::Default);
}
else
{
W_Parent->OnLoginComplete(false, Error.ErrorRaw);
}
}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)
{
// Abort if Player Controller is not the current player.
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);
}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
{
// Abort if Player Controller is not the current player.
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"))));
}Still in the CPP file, bind the
CancelQueue
function to the Cancel button inNativeOnActivated
and unbind it inNativeOnDeactivated
.void ULoginQueueWidget_Starter::NativeOnActivated()
{
// ...
if (!ensure(W_Parent))
{
UE_LOG_LOGIN_QUEUE(Warning, TEXT("Deactivate Auth Essentials's starter mode or activate 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);
// ...
}Build the project and open it with the Unreal Editor once it's done.
Open
Content\TutorialModules\Access\LoginQueue\DA_LoginQueue.uasset
and enable theIs Starter Mode Active
. Save the Data Asset.Click Play in the editor. Go to Online Play > Play Online > Create Match Session. The UI will appear if implemented correctly.
Resources
- The files used in this tutorial section are available in the Byte Wars GitHub repository.
- AccelByteWars/Content/TutorialModules/Access/LoginQueue/UI/W_LoginQueue_Starter.uasset
- AccelByteWars/Source/AccelByteWars/TutorialModules/Access/LoginQueue/UI/LoginQueueWidget_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Access/LoginQueue/UI/LoginQueueWidget_Starter.cpp
- AccelByteWars/Content/TutorialModules/Access/LoginQueue/UI/DA_LoginQueue.uasset