使用 C++ 集成
Use the Matchmaker Subsystems and API to add matchmaking functionality to your Unreal Engine game in C++.
阅读时间7 分钟最后更新于 2 个月前
以下部分展示如何使用 Unreal Engine 子系统与 Matchmaker SDK 集成。
Unity Gaming Services SDK 提供两个 Matchmaker 接口:
添加 Matchmaker SDK 作为依赖项
继续下一步前,请将 添加为模块的公共依赖项,然后将插件头文件包含到您的类中,如下所示。
MatchmakerSDK将 和 作为模块的依赖项添加到您的 Unreal 项目版本文件 ():
MatchmakerServerMatchmakerClientYourProjectName.Build.csPublicDependencyModuleNames.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 控制关于匹配和寻找匹配玩家的客户端部分。此部分包括创建、删除和轮询匹配工单。
您可以通过获取 子系统的引用来访问 Matchmaker Client Subsystem。 属于 ,可在 中检索。
UMatchmakerClientSubsystemUMatchmakerClientSubsystemUGameInstanceSubsystemUGameInstanceUWorld* 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)}));
您可以使用接受 的 THandler 来处理 SDK 的响应。
FCreateTicketResponseGetTicketStatus
使用 方法向 Matchmaker Service 轮询客户端的工单状态。
GetTicketStatus()您应该使用循环不断轮询,直到检索到表明匹配过程成功或失败的响应。
为了实现这一目标,请使用 启动计时器,如下例所示:
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()); } }));}
您可以使用接受 的 THandler 来处理 SDK 的响应。
FGetTicketStatusResponseDeleteTicket
使用 方法删除匹配工单并取消匹配。此操作通常是在完成玩家匹配(无论成功或失败)之后或当客户端不再希望参与匹配过程时进行的。
DeleteTicket()您可以在接受 的响应处理程序中处理 SDK 的响应。
FDeleteTicketResponseMatchmakerClientSubsystem->DeleteTicket(TicketId, Unity::Services::Core::THandler<FDeleteTicketResponse>::CreateLambda([](FDeleteTicketResponse Response){ // Your response logic here}));
您可以使用接受 的 THandler 来处理 SDK 的响应。
FDeleteTicketResponseMatchmaker Server Subsystem
Matchmaker Server Subsystem 控制关于匹配的服务器部分。此部分包括创建、审批、删除和更新回填工单。
使用 前,您必须在如下代码片段中检索它:
UMatchmakerServerSubsystemUWorld* GameWorld = GetWorld();UGameInstance* GameInstance = GameWorld->GetGameInstance();UMatchmakerServerSubsystem* MatchmakerServerSubsystem = GameInstance->GetSubsystem<UMatchmakerServerSubsystem>();
如需了解更多详细信息,请参阅分配有效负载(通过 Multiplay 子系统使用 进行访问)。这用于最初填充 MatchProperties。
GetPayloadAllocation()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}));
您可以使用接受 的 THandler 来处理 SDK 的响应。
FCreateBackfillTicketResponseApproveBackfillTicket
要在创建回填工单后审批回填工单,请使用 方法。审批回填工单可以让新玩家进入服务器。
ApproveBackfillTicket()建议审批回填工单的速度不要超过每秒一次。如果工单经过 20 秒仍未获得审批,Unity Matchmaker 将会删除工单。
以下代码片段展示了如何审批回填工单:
MatchmakerServerSubsystem->ApproveBackfillTicket(BackfillTicketId, Unity::Services::Core::THandler<FApproveBackfillTicketResponse>::CreateLambda([this](FApproveBackfillTicketResponse ApproveResponse){ // Your response logic here}));
您可以使用接受 的 THandler 来处理 SDK 的响应。
FApproveBackfillTicketResponseDeleteBackfillTicket
当匹配人数已满,不再需要服务器接受新玩家时,删除回填工单。当游戏匹配结束后,不再希望服务器接收新玩家时,也应该执行此操作。要停止服务器上的回填,请使用 方法。
DeleteBackfillTicket()以下代码片段展示了如何删除回填工单:
MatchmakerServerSubsystem->DeleteBackfillTicket(BackfillTicketId, Unity::Services::Core::THandler<FDeleteBackfillTicketResponse>::CreateLambda([this](FDeleteBackfillTicketResponse DeleteResponse){ // Handle response here}));
您可以使用接受 的 THandler 来处理 SDK 的响应。
FDeleteBackfillTicketResponseUpdateBackfillTicket
要更新服务器的当前回填工单,请使用 方法。
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 建议先调用 ,然后使用从 返回的 进行修改并传递到 中。
ApproveBackfillTicketApproveBackfillTicketBackfillTicketUpdateBackfillTicket您可以使用接受 的 THandler 来处理 SDK 的响应。
FUpdateBackfillTicketResponse使用 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); }));