文档

支持

Matchmaker for the Unreal Engine

Matchmaker overview

Matchmaker for the Unreal Engine

使用 C++ 集成

Use the Matchmaker Subsystems and API to add matchmaking functionality to your Unreal Engine game in C++.
阅读时间7 分钟最后更新于 4 天前

以下部分展示如何使用 Unreal Engine 子系统与 Matchmaker SDK 集成。 Unity Gaming Services SDK 提供两个 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 Client Subsystem

Matchmaker Client Subsystem 控制关于匹配和寻找匹配玩家的客户端部分。此部分包括创建、删除和轮询匹配工单。 您可以通过获取
UMatchmakerClientSubsystem
子系统的引用来访问 Matchmaker Client Subsystem。
UMatchmakerClientSubsystem
属于
UGameInstanceSubsystem
,可在
UGameInstance
中检索。
UWorld* GameWorld = GetWorld();UGameInstance* GameInstance = GameWorld->GetGameInstance();UMatchmakerClientSubsystem* MatchmakerClientSubsystem = GameInstance->GetSubsystem<UMatchmakerClientSubsystem>();

CreateTicket

使用
CreateTicket()
方法可为客户端创建匹配工单以启动匹配过程。
调用此方法会将
Players
数组中所有有效玩家以一个组的形式添加到匹配队列中,并作为同一个团队的成员加入游戏匹配。
您可以传递多个参数,但唯一必需的参数是 **Players(玩家)**列表(至少一名使用有效 ID 的玩家)。其他可选参数包括 Queue Name(队列名称)、**Qos Results(Qos 结果)**和自定义玩家数据。
// Create Players arrayTArray<FMatchmakerPlayer> Players;// Create player definitionFMatchmakerPlayer SamplePlayer;SamplePlayer.Id = TEXT("SamplePlayer");// Adding custom player dataTSharedPtr<FJsonObject> CustomData = MakeShared<FJsonObject>();CustomData->SetNumberField("Skill", 100);CustomData->SetStringField("PreferredMap", "Dune");SamplePlayer.CustomData = CustomData;Players.Add(SamplePlayer);// Setup Ticket OptionsFCreateTicketOptions 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 Service 轮询客户端的工单状态。
您应该使用循环不断轮询,直到检索到表明匹配过程成功或失败的响应。 为了实现这一目标,请使用
FTimerDelegate
启动计时器,如下例所示:
// Create the Timer Delegate and set the function to callFTimerDelegate 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 Server Subsystem

Matchmaker Server Subsystem 控制关于匹配的服务器部分。此部分包括创建、审批、删除和更新回填工单。 使用
UMatchmakerServerSubsystem
前,您必须在如下代码片段中检索它:
UWorld* GameWorld = GetWorld();UGameInstance* GameInstance = GameWorld->GetGameInstance();UMatchmakerServerSubsystem* MatchmakerServerSubsystem = GameInstance->GetSubsystem<UMatchmakerServerSubsystem>();
如需了解更多详细信息,请参阅分配有效负载(通过 Multiplay 子系统使用
GetPayloadAllocation()
进行访问)。这用于最初填充 MatchProperties。

CreateBackfillTicket

当一名或多名玩家离开完整匹配,因此服务器需要填补空缺时,您需要创建新的回填工单。要为服务器创建新的回填工单,请使用
CreateBackfillTicket()
方法。
以下代码片段展示了如何创建新的回填工单:
// Setup Backfill Ticket OptionsFCreateBackfillTicketOptions CreateBackfillTicketOptions;CreateBackfillTicketOptions.Connection = TEXT("35.245.90.171:9000");CreateBackfillTicketOptions.QueueName = TEXT("default-queue");// Create Match PropertiesFMatchProperties MatchProperties;FGuid BackfillTicketId = FGuid::NewGuid();MatchProperties.BackfillTicketId = BackfillTicket.Id;MatchProperties.Region = TEXT("aaaaaaaa-1111-bbbb-2222-cccccccccccc");// Create PlayerFMatchmakerPlayer 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 TeamFMatchmakerTeam 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()
方法。审批回填工单可以让新玩家进入服务器。
建议审批回填工单的速度不要超过每秒一次。如果工单经过 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()
方法。
每当玩家离开服务器或每当玩家从匹配逻辑之外加入服务器时,需要更新回填工单。这些情况可能包括(但不限于)派对邀请、直接连接和好友邀请。 更新回填工单的频率应该不超过每三秒一次,或者在已审批的回填工单发生变化后更新回填工单,以确保至少经过一个匹配周期。过于频繁地更新回填工单可能会导致玩家无法回填到匹配中。请参阅匹配逻辑样本以了解更多信息。
// From ApproveFBackfillTicket BackfillTicket;FGuid BackfillTicketId = FGuid::Parse(ApproveResponse.BackfillTicket.Id, BackfillTicketId);FBackfillTicket BackfillTicket = ApproveResponse.BackfillTicket;// Setup MatchPropertiesFMatchProperties MatchProperties;MatchProperties.BackfillTicketId = BackfillTicket.Id; // Could be retrieved in Payload allocation's MatchPropertiesMatchProperties.Region = TEXT("aaaaaaaa-1111-bbbb-2222-cccccccccccc"); // Could be retrieved in Payload allocation's MatchProperties// Add a new player to the backfill ticketFMatchmakerPlayer 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 ticketFString 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 ticketMatchmakerServerSubsystem->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 中包括与 Blueprint 兼容的自定义委托。使用 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);}));