# C++를 사용하여 연동

> Use the Matchmaker Subsystems and API to add matchmaking functionality to your Unreal Engine game in C++.

다음 섹션에서는 [Unreal Engine 시스템의 보조 시스템](https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/Subsystems/)을 사용하여 Matchmaker SDK와 연동하는 방법을 설명합니다.

Unity Gaming Services SDK는 두 가지 매치메이커 인터페이스를 제공합니다.

* [Matchmaker 클라이언트 시스템의 보조 시스템](#matchmaker-client-subsystem)

* [Matchmaker 서버 시스템의 보조 시스템](#matchmaker-server-subsystem)

### Matchmaker SDK를 종속성으로 추가##add-the-matchmaker-sdk-as-a-dependency

계속하기 전에 아래와 같이 모듈의 공개 종속성으로 `MatchmakerSDK`를 추가한 다음, include 문으로 클래스에 플러그인 헤더 파일을 가져옵니다.

Unreal 프로젝트 빌드 파일(`YourProjectName.Build.cs`)의 모듈 종속성에 `MatchmakerServer`와 `MatchmakerClient`를 추가합니다.

```cpp
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PublicDependencyModuleNames.AddRange(new string[] { "MatchmakerClient", "MatchmakerServer" });
PublicDependencyModuleNames.AddRange(new string[] { "Json", "JsonUtilities" });

```

include 문으로 클래스에서 액세스하려는 플러그인 헤더 파일을 가져옵니다.

```cpp
#include "MatchmakerClientSubsystem.h"
#include "MatchmakerServerSubsystem.h"
```

### Matchmaker 클라이언트 시스템의 보조 시스템##matchmaker-client-subsystem

> **Note:**
>
> **참고**: 먼저 [Authentication](/authentication-unreal.md)을 설정한 다음 Matchmaking 클라이언트 시스템의 보조 시스템에 액세스해야 합니다.

Matchmaker 클라이언트 시스템의 보조 시스템은 매치메이킹과 매치 찾기의 클라이언트 부분을 제어합니다. 여기에는 매치메이킹 티켓 생성, 삭제, 폴링이 포함됩니다.

`UMatchmakerClientSubsystem` 보조 시스템에 대한 레퍼런스를 확보하면 Matchmaker 클라이언트 시스템의 보조 시스템에 액세스할 수 있습니다. `UMatchmakerClientSubsystem`은 `UGameInstance`에서 검색할 수 있는 `UGameInstanceSubsystem`입니다.

```cpp
UWorld* GameWorld = GetWorld();
UGameInstance* GameInstance = GameWorld->GetGameInstance();
UMatchmakerClientSubsystem* MatchmakerClientSubsystem = GameInstance->GetSubsystem<UMatchmakerClientSubsystem>();
```

#### CreateTicket##createticket

`CreateTicket()` 메서드를 사용해 클라이언트용 매치메이킹 티켓을 생성하여 매치메이킹 프로세스를 시작합니다.

이 메서드를 호출하면 `Players` 배열에 있는 모든 유효한 플레이어가 그룹으로 매치메이킹 대기열에 추가되고 같은 팀의 일원으로 매치에 참여합니다.

전달할 수 있는 여러 파라미터가 있지만, 필수 파라미터는 **플레이어** 목록(유효한 ID를 사용하는 최소 한 명의 플레이어가 있어야 함)입니다. 기타 선택적 파라미터에는 **대기열 이름**, **Qos 결과**, 플레이어용 커스텀 데이터가 포함됩니다.

```cpp
// 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)
}));
```

SDK의 응답은 `FCreateTicketResponse`를 허용하는 [THandler](/authentication-unreal/sdk-api/services-core/utils/services-utils.md#thandler)를 사용하여 처리할 수 있습니다.

#### GetTicketStatus##getticketstatus

`GetTicketStatus()` 메서드를 사용하여 매치메이커 서비스에 대한 클라이언트의 티켓 상태를 폴링합니다.

매치메이킹 프로세스의 성공 또는 실패를 나타내는 응답을 검색할 때까지 반복적으로 폴링을 계속해야 합니다.

이를 위해 다음 예제와 같이 `FTimerDelegate`를 사용하여 타이머를 시작합니다.

```cpp
// 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);
```

그러면 폴링 매치 함수가 다음 예제와 유사하게 나타납니다.

```cpp
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());
		}
	}));
}

```

SDK의 응답은 `FGetTicketStatusResponse`를 허용하는 [THandler](/authentication-unreal/sdk-api/services-core/utils/services-utils.md#thandler)를 사용하여 처리할 수 있습니다.

#### DeleteTicket##deleteticket

`DeleteTicket()` 메서드를 사용하여 매치메이킹 티켓을 삭제하고 매치메이킹을 취소합니다. 이는 일반적으로 매치를 찾은 후(성공 여부와 상관없이) 또는 클라이언트가 더 이상 매치메이킹 프로세스를 원하지 않을 때 수행됩니다.

SDK의 응답은 `FDeleteTicketResponse`를 허용하는 응답 핸들러에서 처리할 수 있습니다.

```cpp
MatchmakerClientSubsystem->DeleteTicket(TicketId, Unity::Services::Core::THandler<FDeleteTicketResponse>::CreateLambda([](FDeleteTicketResponse Response)
{
	// Your response logic here
}));

```

SDK의 응답은 `FDeleteTicketResponse`를 허용하는 [THandler](/authentication-unreal/sdk-api/services-core/utils/services-utils.md#thandler)를 사용하여 처리할 수 있습니다.

### Matchmaker 서버 시스템의 보조 시스템##matchmaker-server-subsystem

Matchmaker 서버 시스템의 보조 시스템은 매치메이킹의 서버 부분을 제어합니다. 여기에는 Backfill 티켓 생성, 승인, 삭제, 업데이트가 포함됩니다.

다음 코드 스니핏에서 보여 주는 것처럼 보조 시스템을 먼저 가져온 후 `UMatchmakerServerSubsystem`을 사용해야 합니다.

```cpp
UWorld* GameWorld = GetWorld();
UGameInstance* GameInstance = GameWorld->GetGameInstance();
UMatchmakerServerSubsystem* MatchmakerServerSubsystem = GameInstance->GetSubsystem<UMatchmakerServerSubsystem>();
```

> **Note:**
>
> **참고**: Matchmaker는 작성 시점을 기준으로 Multiplay 서버와 함께 사용될 예정이므로, 다음 서버 기능은 일부 Multiplay SDK 기능과 함께 사용될 것으로 예상됩니다.

자세한 내용은 [할당 페이로드](https://www.rocketscience.gg/multiplay/)를 참조하십시오(Multiplay 시스템의 보조 시스템을 사용하여 `GetPayloadAllocation()`으로 액세스). 이는 MatchProperties를 처음 채우는 데 사용됩니다.

#### CreateBackfillTicket##createbackfillticket

플레이어(또는 플레이어들)가 인원이 모두 채워진 매치를 나가는 경우 새 Backfill 티켓을 생성해야 하고, 서버는 빈 슬롯을 채워야 합니다. 서버용 새 Backfill 티켓을 생성하려면 `CreateBackfillTicket()` 메서드를 사용합니다.

다음 코드 스니핏은 새 Backfill 티켓을 생성하는 방법을 보여 줍니다.

```cpp
// 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
}));

```

SDK의 응답은 `FCreateBackfillTicketResponse`를 허용하는 [THandler](/authentication-unreal/sdk-api/services-core/utils/services-utils.md#thandler)를 사용하여 처리할 수 있습니다.

#### ApproveBackfillTicket##approvebackfillticket

Backfill 티켓을 생성한 후 승인하려면 `ApproveBackfillTicket()` 메서드를 사용합니다. Backfill 티켓을 승인하면 새 플레이어가 서버에 참여할 수 있습니다.

Backfill 티켓은 1초에 한 번 이하로 승인하는 것이 좋습니다. Unity Matchmaker는 20초 이내에 승인되지 않은 티켓을 삭제합니다.

다음 코드 스니핏은 새 Backfill 티켓을 승인하는 방법을 보여 줍니다.

```cpp
MatchmakerServerSubsystem->ApproveBackfillTicket(BackfillTicketId, Unity::Services::Core::THandler<FApproveBackfillTicketResponse>::CreateLambda([this](FApproveBackfillTicketResponse ApproveResponse)
{
	// Your response logic here
}));
```

SDK의 응답은 `FApproveBackfillTicketResponse`를 허용하는 [THandler](/authentication-unreal/sdk-api/services-core/utils/services-utils.md#thandler)를 사용하여 처리할 수 있습니다.

#### DeleteBackfillTicket##deletebackfillticket

매치가 전부 채워진 경우 Backfill 티켓을 삭제하고, 서버는 더 이상 새 플레이어를 받지 않아야 합니다. 또한 매치가 종료된 후 새 플레이어가 서버에 더 이상 들어오지 않도록 이 작업을 수행해야 합니다. 서버에서 Backfill을 중지하려면 `DeleteBackfillTicket()` 메서드를 사용합니다.

다음 코드 스니핏은 Backfill 티켓을 삭제하는 방법을 보여 줍니다.

```cpp
MatchmakerServerSubsystem->DeleteBackfillTicket(BackfillTicketId, Unity::Services::Core::THandler<FDeleteBackfillTicketResponse>::CreateLambda([this](FDeleteBackfillTicketResponse DeleteResponse)
{
    // Handle response here
}));
```

SDK의 응답은 `FDeleteBackfillTicketResponse`를 허용하는 [THandler](/authentication-unreal/sdk-api/services-core/utils/services-utils.md#thandler)를 사용하여 처리할 수 있습니다.

#### UpdateBackfillTicket##updatebackfillticket

서버의 현재 Backfill 티켓을 업데이트하려면 `UpdateBackfillTicket()` 메서드를 사용합니다.

매치메이킹 로직 외부에서 플레이어가 서버에 참여하거나 서버를 나갈 때마다 Backfill 티켓을 업데이트해야 합니다. 여기에는 파티 초대, 직접 연결, 친구 초대 등이 포함될 수 있으나 이에 국한되지는 않습니다.

Backfill 티켓은 3초에 한 번 이하로 업데이트해야 하며, 승인된 Backfill 티켓에서 Backfill 티켓의 변경 사항을 감지한 경우 매치메이킹 주기가 완료되었는지 확인하기 위해 업데이트해야 합니다. Backfill 티켓을 너무 자주 업데이트하면 플레이어가 매치에 다시 Backfill되지 않을 수 있습니다. 자세한 내용은 [매치메이킹 로직 샘플](/matchmaker/rules-sample.md)을 참조하십시오.

```cpp
// 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
}));

```

먼저 `ApproveBackfillTicket`을 호출하고 `ApproveBackfillTicket`에서 반환된 `BackfillTicket`를 사용하여 수정한 후 `UpdateBackfillTicket`에 전달하는 것이 좋습니다.

SDK의 응답은 `FUpdateBackfillTicketResponse`를 허용하는 [THandler](/authentication-unreal/sdk-api/services-core/utils/services-utils.md#thandler)를 사용하여 처리할 수 있습니다.

### THandler 사용

SDK에는 커스텀 블루프린트 호환 델리게이트가 포함되어 있습니다. [THandler](/authentication-unreal/sdk-api/services-core/utils/services-utils.md#thandler)를 사용하는 것은 일반 Unreal Engine 델리게이트를 사용하는 것과 유사합니다.

다음은 인라인 응답으로 호출하는 방법을 보여 주는 코드 스니핏입니다.

```cpp
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);
	}));
```
