C++ を使用した統合
以下のセクションでは、Unreal Engine のサブシステムを使用して Matchmaker SDK を統合する方法を示します。
Unity Gaming Services SDK では、次の 2 つの Matchmaker インターフェースを使用できます。
Matchmaker SDK を依存関係として追加する
先に進む前に、MatchmakerSDK
をモジュールのパブリック依存関係として追加し、以下に示すようにプラグインのヘッダーファイルをクラスに加えます。
MatchmakerServer
と MatchmakerClient
をモジュールの依存関係として Unreal プロジェクトのビルドファイル (YourProjectName.Build.cs
) に追加します。
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PublicDependencyModuleNames.AddRange(new string[] { "MatchmakerClient", "MatchmakerServer" });
PublicDependencyModuleNames.AddRange(new string[] { "Json", "JsonUtilities" });
アクセスしたいプラグインのヘッダーファイルをクラスに加えます。
#include "MatchmakerClientSubsystem.h"
#include "MatchmakerServerSubsystem.h"
Matchmaker クライアントサブシステム
ノート: Matchmaker クライアントサブシステムにアクセスする前に、必ず 認証 を設定しておいてください。
Matchmaker クライアントサブシステムが、マッチメイキングとマッチ検出のクライアント部分を制御します。これには、マッチメイキングチケットの作成、削除、ポーリングが含まれています。
Matchmaker クライアントサブシステムには、UMatchmakerClientSubsystem
サブシステムへの参照を取得することでアクセスできます。UMatchmakerClientSubsystem
は UGameInstanceSubsystem
の 1 つであり、UGameInstance
から取得できます。
UWorld* GameWorld = GetWorld();
UGameInstance* GameInstance = GameWorld->GetGameInstance();
UMatchmakerClientSubsystem* MatchmakerClientSubsystem = GameInstance->GetSubsystem<UMatchmakerClientSubsystem>();
CreateTicket
CreateTicket()
メソッドを使用してクライアントのマッチメイキングチケットを作成し、マッチメイキングプロセスを開始します。
このメソッドを呼び出すと、Players
配列内のすべての有効なプレイヤーが 1 つのグループとしてマッチメイキングキューに追加され、同じチームの一員としてマッチに参加します。
複数のパラメーターを渡すことができますが、必要なパラメーターは Players リストのみです (有効な ID を使用するプレイヤーが少なくとも 1 人いる必要があります)。その他に使用できるパラメーターとしては、Queue Name、Qos Results、プレイヤーのカスタムデータなどがあります。
// Create Players array
TArray<FMatchmakerPlayer> Players;
// Create player definition
FMatchmakerPlayer SamplePlayer;
SamplePlayer.Id = TEXT("SamplePlayer");
// Adding custom player data
TSharedPtr<FJsonObject> CustomData = MakeShared<FJsonObject>();
CustomData->SetNumberField("Skill", 100);
CustomData->SetStringField("PreferredMap", "Dune");
SamplePlayer.CustomData = CustomData;
Players.Add(SamplePlayer);
// Setup Ticket Options
FCreateTicketOptions Options;
Options.QueueName = TEXT("default-queue");
MatchmakerClientSubsystem->CreateTicket(Players, options, Unity::Services::Core::THandler<FCreateTicketResponse>::CreateLambda([this](FCreateTicketResponse Response)
{
// Your response logic here (response includes Ticket Id)
}));
FCreateTicketResponse
を受け取る THandler を使用して、SDK の応答を処理できます。
GetTicketStatus
GetTicketStatus()
メソッドを使用して、Matchmaker サービスに対してクライアントのチケットステータスをポーリングします。
マッチメイキングプロセスの成功または失敗を示す応答が取得されるまで、ループ内で継続的にポーリングを実行する必要があります。
そのためには以下の例のように、FTimerDelegate
を使用してタイマーを開始します。
// Create the Timer Delegate and set the function to call
FTimerDelegate PollTicketDelegate = FTimerDelegate::CreateUObject(this, &UMyCustomClass::PollTicket, Response.TicketId);
// Start the Timer that runs every 5 seconds, cache PollTicketTimerHandler to use for stopping the timer later GEngine->GameViewport->GetWorld()->GetTimerManager().SetTimer(PollTicketTimerHandle, PollTicketDelegate, 5, true);
使用するマッチポーリング関数は以下の例のようになります。
void UMyCustomClass::PollTicket(FGuid TicketId)
{
MatchmakerClientSubsystem->GetTicketStatus(TicketId, THandler<FGetTicketStatusResponse>::CreateLambda([this, TicketId](FGetTicketStatusResponse Response)
{
if (Response.bWasSuccessful)
{
FString TicketIdStr = *TicketId.ToString(EGuidFormats::DigitsWithHyphens).ToLower();
switch (Response.Status)
{
case StatusEnum::Failed:
UE_LOG(LogTemp, Log, TEXT("polling for ticket has failed, response was: %s"), *Response.ErrorMessage);
break;
case StatusEnum::Timeout:
UE_LOG(LogTemp, Log, TEXT("polling for ticket has timed out, response was: %s"), *Response.ErrorMessage);
break;
case StatusEnum::InProgress:
UE_LOG(LogTemp, Log, TEXT("polling for ticket %s is still in progress."), *TicketId.ToString(EGuidFormats::DigitsWithHyphens).ToLower());
return;
case StatusEnum::Found:
UE_LOG(LogTemp, Log, TEXT("polling for ticket has completed, match found with ip: %s"), *Response.Ip);
break;
default:
UE_LOG(LogTemp, Log, TEXT("unknown status received for ticket: %s), *TicketId.ToString(EGuidFormats::DigitsWithHyphens).ToLower());
break;
}
// If we made it this far, we got a status other than InProgress so we can end the polling timer.
GEngine->GameViewport->GetWorld()->GetTimerManager().ClearTimer(PollTicketTimerHandle);
// Delete ticket here
}
else
{
UE_LOG(LogTemp, Log, TEXT("Failed to poll Ticket status with ticket ID: %s"), *TicketId.ToString(EGuidFormats::DigitsWithHyphens).ToLower());
}
}));
}
FGetTicketStatusResponse
を受け取る THandler を使用して、SDK の応答を処理できます。
DeleteTicket
マッチメイキングチケットを削除してマッチメイキングをキャンセルするには、DeleteTicket()
メソッドを使用します。この処理を行うのは一般的に、マッチが見つかった後 (失敗した場合を含む)、またはマッチメイキングプロセスを必要とすると考えられるクライアントがなくなったときです。
FDeleteTicketResponse
を受け取る応答ハンドラーで、SDK の応答を処理できます。
MatchmakerClientSubsystem->DeleteTicket(TicketId, Unity::Services::Core::THandler<FDeleteTicketResponse>::CreateLambda([](FDeleteTicketResponse Response)
{
// Your response logic here
}));
FDeleteTicketResponse
を受け取る THandler を使用して、SDK の応答を処理できます。
Matchmaker サーバーサブシステム
Matchmaker サーバーサブシステムが、マッチメイキングのサーバー部分を制御します。これには、バックフィルチケットの作成、承認、削除、更新が含まれています。
UMatchmakerServerSubsystem
を使用するには、以下のコードスニペットに示す方法でこれを取得する必要があります。
UWorld* GameWorld = GetWorld();
UGameInstance* GameInstance = GameWorld->GetGameInstance();
UMatchmakerServerSubsystem* MatchmakerServerSubsystem = GameInstance->GetSubsystem<UMatchmakerServerSubsystem>();
ノート: 本稿の執筆時点では、Matchmaker は Multiplay サーバーのみで使用することが想定されています。そのため、以下のサーバー関数の一部は Multiplay SDK 関数と組み合わせて使用することが想定されていることに注意してください。
詳細については、割り当てペイロード を参照してください (GetPayloadAllocation()
による Multiplay サブシステムへのアクセス)。これは、最初に MatchProperties に入力するために使用されます。
CreateBackfillTicket
1 人または複数のプレイヤーが満員のマッチから退出したときに、新しいバックフィルチケットを作成する必要があります。また、サーバーは空のスロットを埋める必要があります。サーバーに新しいバックフィルチケットを作成するには、CreateBackfillTicket()
メソッドを使用します。
以下のコードスニペットに、新しいバックフィルチケットを作成する方法を示します。
// Setup Backfill Ticket Options
FCreateBackfillTicketOptions CreateBackfillTicketOptions;
CreateBackfillTicketOptions.Connection = TEXT("35.245.90.171:9000");
CreateBackfillTicketOptions.QueueName = TEXT("default-queue");
// Create Match Properties
FMatchProperties MatchProperties;
FGuid BackfillTicketId = FGuid::NewGuid();
MatchProperties.BackfillTicketId = BackfillTicket.Id;
MatchProperties.Region = TEXT("aaaaaaaa-1111-bbbb-2222-cccccccccccc");
// Create Player
FMatchmakerPlayer Player;
Player.Id = FGuid::NewGuid().ToString();
FQosResult QosResult;
QosResult.Latency = 20;
QosResult.PacketLoss = 5;
QosResult.Region = TEXT("aaaaaaaa-1111-bbbb-2222-cccccccccccc");
Player.QoSResults.Add(QosResult);
MatchProperties.Players.Add(Player);
// Create Team
FMatchmakerTeam Team;
Team.TeamName = TEXT("Red");
FGuid TeamId = FGuid::NewGuid();
Team.TeamId = TeamId.ToString(EGuidFormats::DigitsWithHyphens);
Team.PlayerIds.Add(Player.Id);
MatchProperties.Teams.Add(Team);
CreateBackfillTicketOptions.Properties.MatchProperties = MatchProperties;
MatchmakerServerSubsystem->CreateBackfillTicket(CreateBackfillTicketOptions, Unity::Services::Core::THandler<FCreateBackfillTicketResponse>::CreateLambda([this, Player, Team](FCreateBackfillTicketResponse CreateResponse)
{
// Your response logic here
}));
FCreateBackfillTicketResponse
を受け取る THandler を使用して、SDK の応答を処理できます。
ApproveBackfillTicket
作成後のバックフィルチケットを承認するには、ApproveBackfillTicket()
メソッドを使用します。バックフィルチケットを承認することで、新しいプレイヤーがサーバーに参加できるようになります。
バックフィルチケットの承認は、最速でも 1 秒に 1 回までにすることをお勧めします。20 秒以内に承認されなかったチケットは Unity Matchmaker により削除されます。
以下のコードスニペットに、新しいバックフィルチケットを承認する方法を示します。
MatchmakerServerSubsystem->ApproveBackfillTicket(BackfillTicketId, Unity::Services::Core::THandler<FApproveBackfillTicketResponse>::CreateLambda([this](FApproveBackfillTicketResponse ApproveResponse)
{
// Your response logic here
}));
FApproveBackfillTicketResponse
を受け取る THandler を使用して、SDK の応答を処理できます。
DeleteBackfillTicket
マッチが満員になり、サーバーで新しいプレイヤーを受け付ける必要がなくなった時点で、バックフィルチケットを削除します。マッチが終了し、サーバーに新しいプレイヤーを受け入れたくなくなった後も、同じ処理を行う必要があります。サーバーへのバックフィルを停止するには、DeleteBackfillTicket()
メソッドを使用します。
以下のコードスニペットに、バックフィルチケットを削除する方法を示します。
MatchmakerServerSubsystem->DeleteBackfillTicket(BackfillTicketId, Unity::Services::Core::THandler<FDeleteBackfillTicketResponse>::CreateLambda([this](FDeleteBackfillTicketResponse DeleteResponse)
{
// Handle response here
}));
FDeleteBackfillTicketResponse
を受け取る THandler を使用して、SDK の応答を処理できます。
UpdateBackfillTicket
サーバーの現在のバックフィルチケットを更新するには、UpdateBackfillTicket()
を使用します。
プレイヤーがサーバーを抜けたとき、またはプレイヤーが対戦相手探しのロジックの外部からサーバーに参加したときには、必ずバックフィルチケットを更新してください。これにはパーティの招待、直接接続、友人の招待などが該当しますが、それに限りません。
バックフィルチケットの更新頻度が 3 秒に 1 回を超えないようにします。また、承認済みのバックフィルチケットがそのバックフィルチケットの変更を認識した後に更新することで、マッチメイキングサイクルを確実に経過させる必要があります。バックフィルチケットの更新頻度が高すぎると、バックフィルによるマッチへのプレイヤー参加がまったくできなくなる可能性があります。詳細は、対戦相手探しのロジックのサンプル を参照してください。
// From Approve
FBackfillTicket BackfillTicket;
FGuid BackfillTicketId = FGuid::Parse(ApproveResponse.BackfillTicket.Id, BackfillTicketId);
FBackfillTicket BackfillTicket = ApproveResponse.BackfillTicket;
// Setup MatchProperties
FMatchProperties MatchProperties;
MatchProperties.BackfillTicketId = BackfillTicket.Id; // Could be retrieved in Payload allocation's MatchProperties
MatchProperties.Region = TEXT("aaaaaaaa-1111-bbbb-2222-cccccccccccc"); // Could be retrieved in Payload allocation's MatchProperties
// Add a new player to the backfill ticket
FMatchmakerPlayer NewPlayer;
NewPlayer.Id = TEXT("NewPlayer");
TSharedPtr<FJsonObject> CustomData = MakeShared<FJsonObject>();
CustomData->SetNumberField("Skill", 100);
CustomData->SetStringField("PreferredMap", "Dune");
NewPlayer.CustomData = CustomData;
BackfillTicket.Properties.Players.Add(NewPlayer);
BackfillTicket.Properties.[0].PlayerIds.Add(NewPlayer.Id);
// Remove a Player from the backfill ticket
FString PlayerIdToRemove = TEXT("SamplePlayer");
for (FMatchmakerPlayer Player : BackfillTicket.Properties.Players)
{
if (Player.Id == PlayerIdToRemove)
{
BackfillTicket.Properties.Players.Remove(Player);
break;
}
}
if (BackfillTicket.Properties.Teams[0].PlayerIds.Contains(PlayerIdToRemove))
{
BackfillTicket.Properties.Teams[0].PlayerIds.Remove(PlayerIdToRemove);
}
// Call to update backfill ticket
MatchmakerServerSubsystem->UpdateBackfillTicket(BackfillTicketId, BackfillTicket, Unity::Services::Core::THandler<FUpdateBackfillTicketResponse>::CreateLambda([this, BackfillTicketId](FUpdateBackfillTicketResponse UpdateResponse)
{
// Handle Response here
}));
Unity では、先に ApproveBackfillTicket
を呼び出し、ApproveBackfillTicket
から返された BackfillTicket
を使用することで、UpdateBackfillTicket
を変更して渡すことをお勧めします。
FUpdateBackfillTicketResponse
を受け取る THandler を使用して、SDK の応答を処理できます。
THandler の使用
この SDK には、ブループリントに対応するカスタムデリゲートが含まれます。THandler の使用方法は、通常の Unreal Engine デリゲートと似ています。
以下のコードスニペットに、インライン応答を使用して呼び出しを行う方法を示します。
Matchmaker::THandler<FCreateTicketResponse>::CreateLambda([ResponseDelegate](FCreateTicketResponse Response)
{
if (Response.bWasSuccessful)
{
UE_LOG(LogMatchmakerSDK, Log, TEXT("Successfully retrieved Ticket ID: %s"), *Response.TicketId);
}
else
{
UE_LOG(LogMatchmakerSDK, Error, TEXT("Failed to retrieve Ticket ID: %s"), *Response.ErrorMessage);
}
ResponseDelegate.ExecuteIfBound(Response);
}));