すべてを統合する - 専用サーバーでのクイックマッチ - (Unreal Engine モジュール)
The goal of the matchmaking UI is to show the exact state of the matchmaking, so the widget has many high-level states. To understand when each state should show up, refer to this diagram:
Connect the UI to start, cancel, and display the matchmaking status
Open the
MatchmakingDSWidget_Starter
CPP file and replace theStartMatchmaking()
function using the code below to trigger the start of matchmaking. TheOnlineSession
variable is a reference to the online session you created earlier, which is theMatchmakingDSOnlineSession_Starter
class.void UMatchmakingDSWidget_Starter::StartMatchmaking()
{
if (OnlineSession->ValidateToStartMatchmaking.IsBound() &&
!OnlineSession->ValidateToStartMatchmaking.Execute(SelectedGameModeType))
{
return;
}
// Reset stored invite
SessionInvite = nullptr;
// Reset auto join session countdown.
AutoJoinCurrentCountdown = AutoJoinDelay;
MatchFoundCurrentCountdown = MatchFoundDelay;
SessionJoinedCurrentCountdown = SessionJoinedDelay;
Tb_WaitingForPlayersCountdown->SetText(FText::FromString(FString::FromInt(AutoJoinCurrentCountdown)));
ChangeWidgetState(EWidgetState::REQUEST_SENT);
OnlineSession->StartMatchmaking(
GetOwningPlayer(),
OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession),
EGameModeNetworkType::DS,
SelectedGameModeType);
}Replace the
JoinSession()
function using the following code to trigger the join session to the invite that the game received when the matchmaking completed.void UMatchmakingDSWidget_Starter::JoinSession()
{
if (!SessionInvite)
{
ChangeWidgetState(EWidgetState::ERROR);
Tb_ErrorText->SetText(TEXT_FAILED_SESSION_INVITE_INVALID);
}
ChangeWidgetState(EWidgetState::JOINING_MATCH);
OnlineSession->JoinSession(
OnlineSession->GetLocalUserNumFromPlayerController(GetOwningPlayer()),
OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession),
SessionInvite->Session);
}Replace the
CancelMatchmaking()
function using the following code to trigger the canceling of matchmaking:void UMatchmakingDSWidget_Starter::CancelMatchmaking()
{
ChangeWidgetState(EWidgetState::CANCELING_MATCH);
OnlineSession->CancelMatchmaking(
GetOwningPlayer(),
OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession));
}Replace the
RejectSessionInvite()
function using the following code to trigger the reject match session invite:void UMatchmakingDSWidget_Starter::RejectSessionInvite()
{
if (!SessionInvite)
{
ChangeWidgetState(EWidgetState::ERROR);
Tb_ErrorText->SetText(TEXT_FAILED_SESSION_INVITE_INVALID);
}
ChangeWidgetState(EWidgetState::REJECTING_MATCH);
OnlineSession->RejectSessionInvite(
OnlineSession->GetLocalUserNumFromPlayerController(GetOwningPlayer()),
*SessionInvite.Get());
}Replace the
NativeTick()
function using the following code to trigger the join session once the auto join countdown hits zero.void UMatchmakingDSWidget_Starter::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
Super::NativeTick(MyGeometry, InDeltaTime);
MoveCameraToTargetLocation(InDeltaTime, FVector(60.0f, 800.0f, 160.0f));
// Manual "Auto" Join
if (WidgetState == EWidgetState::WAITING_FOR_PLAYER && AutoJoinCurrentCountdown > 0)
{
AutoJoinCurrentCountdown -= InDeltaTime;
Tb_WaitingForPlayersCountdown->SetText(FText::FromString(FString::FromInt(AutoJoinCurrentCountdown)));
if (AutoJoinCurrentCountdown <= 0)
{
JoinSession();
}
}
// Match found delay
if (WidgetState == EWidgetState::MATCH_FOUND && MatchFoundCurrentCountdown > 0)
{
MatchFoundCurrentCountdown -= InDeltaTime;
if (MatchFoundCurrentCountdown <= 0 && SessionInvite)
{
// Check if auto join is enabled or not
const TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(
SessionInvite->Session.Session.SessionInfo);
check(SessionInfo.IsValid());
const bool bAutoJoin = SessionInfo->GetBackendSessionData()->Configuration.AutoJoin;
ChangeWidgetState(bAutoJoin ? EWidgetState::JOINING_MATCH : EWidgetState::WAITING_FOR_PLAYER);
}
}
// Session joined delay
if (WidgetState == EWidgetState::SESSION_JOINED && SessionJoinedCurrentCountdown > 0)
{
SessionJoinedCurrentCountdown -= InDeltaTime;
if (SessionJoinedCurrentCountdown <= 0)
{
ChangeWidgetState(EWidgetState::REQUESTING_SERVER);
}
}
}Bind the callback functions to show the relevant user interface when certain matchmaking events occur. This function is also responsible for triggering the
StartMatchmaking()
immediately. To do this, replace theNativeOnActivated()
function with the following code:void UMatchmakingDSWidget_Starter::NativeOnActivated()
{
Super::NativeOnActivated();
UOnlineSession* BaseOnlineSession = GetWorld()->GetGameInstance()->GetOnlineSession();
if (!ensure(BaseOnlineSession))
{
return;
}
OnlineSession = Cast<UAccelByteWarsOnlineSessionBase>(BaseOnlineSession);
ensure(OnlineSession);
// Get selected game mode type from the previous widget
UAccelByteWarsBaseUI* BaseUIWidget = Cast<UAccelByteWarsGameInstance>(GetGameInstance())->GetBaseUIWidget();
for (const UCommonActivatableWidget* Widget : BaseUIWidget->Stacks[EBaseUIStackType::Menu]->GetWidgetList())
{
if (const UQuickPlayWidget* QuickPlayWidget = Cast<UQuickPlayWidget>(Widget))
{
SelectedGameModeType = QuickPlayWidget->GetSelectedGameModeType();
}
}
Btn_Join->OnClicked().AddUObject(this, &ThisClass::JoinSession);
Btn_Cancel->OnClicked().AddUObject(this, &ThisClass::CancelMatchmaking);
Btn_Reject->OnClicked().AddUObject(this, &ThisClass::RejectSessionInvite);
Btn_Retry->OnClicked().AddUObject(this, &ThisClass::StartMatchmaking);
OnlineSession->GetOnStartMatchmakingCompleteDelegates()->AddUObject(this, &ThisClass::OnStartMatchmakingComplete);
OnlineSession->GetOnMatchmakingCompleteDelegates()->AddUObject(this, &ThisClass::OnMatchmakingComplete);
OnlineSession->GetOnSessionInviteReceivedDelegates()->AddUObject(this, &ThisClass::OnSessionInviteReceived);
OnlineSession->GetOnJoinSessionCompleteDelegates()->AddUObject(this, &ThisClass::OnJoinSessionComplete);
OnlineSession->GetOnSessionServerUpdateReceivedDelegates()->AddUObject(this, &ThisClass::OnSessionServerUpdateReceived);
OnlineSession->GetOnCancelMatchmakingCompleteDelegates()->AddUObject(this, &ThisClass::OnCancelMatchmakingComplete);
OnlineSession->GetOnRejectSessionInviteCompleteDelegate()->AddUObject(this, &ThisClass::OnRejectSessionInviteComplete);
// Start matchmaking immediately
StartMatchmaking();
}You need to unbind those callbacks when the widget is not active. Replace the
NativeOnDeactivated()
with the following code:void UMatchmakingDSWidget_Starter::NativeOnDeactivated()
{
Btn_Join->OnClicked().RemoveAll(this);
Btn_Cancel->OnClicked().RemoveAll(this);
Btn_Reject->OnClicked().RemoveAll(this);
Btn_Retry->OnClicked().RemoveAll(this);
OnlineSession->GetOnStartMatchmakingCompleteDelegates()->RemoveAll(this);
OnlineSession->GetOnMatchmakingCompleteDelegates()->RemoveAll(this);
OnlineSession->GetOnSessionInviteReceivedDelegates()->RemoveAll(this);
OnlineSession->GetOnJoinSessionCompleteDelegates()->RemoveAll(this);
OnlineSession->GetOnSessionServerUpdateReceivedDelegates()->RemoveAll(this);
OnlineSession->GetOnCancelMatchmakingCompleteDelegates()->RemoveAll(this);
OnlineSession->GetOnRejectSessionInviteCompleteDelegate()->RemoveAll(this);
Super::NativeOnDeactivated();
}There are several buttons you need to bind to let the player leave the game session: the leave button in the Match Lobby and the quit buttons in the Pause and Game Over widgets. To do this, you can assign a delegate to leave the session. Open the
MatchmakingDSOnlineSession_Starter
CPP file and add the following code toRegisterOnlineDelegates()
:void UMatchmakingDSOnlineSession_Starter::RegisterOnlineDelegates()
{
// ...
const TDelegate<void(APlayerController*)> LeaveSessionDelegate = TDelegate<void(APlayerController*)>::CreateWeakLambda(
this, [this](APlayerController*)
{
LeaveSession(GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession));
});
UPauseWidget::OnQuitGameDelegate.Add(LeaveSessionDelegate);
UMatchLobbyWidget::OnQuitLobbyDelegate.Add(LeaveSessionDelegate);
UGameOverWidget::OnQuitGameDelegate.Add(LeaveSessionDelegate);
// ...
}When the online session is deinitialized, you need to unbind it to stop listening for the event. You can do this by adding the following code to the
ClearOnlineDelegates()
function:void UMatchmakingDSOnlineSession_Starter::ClearOnlineDelegates()
{
// ...
UPauseWidget::OnQuitGameDelegate.RemoveAll(this);
UMatchLobbyWidget::OnQuitLobbyDelegate.RemoveAll(this);
UGameOverWidget::OnQuitGameDelegate.RemoveAll(this);
// ...
}
Upload dedicated server
To complete and play-test this tutorial, you need to upload a new dedicated server image to the Admin Portal. You can redo the steps from the Dedicated servers with AccelByte Multiplayer Servers (AMS) module to do this.
Resources
The files used in this tutorial section are available in the Unreal Byte Wars GitHub repository.
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingDS/UI/MatchmakingDSWidget_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingDS/UI/MatchmakingDSWidget_Starter.cpp
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingDS/MatchmakingDSOnlineSession_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingDS/MatchmakingDSOnlineSession_Starter.cpp