다음을 통해 공유


비동기 작업 및 알림

느리거나 계산 비용이 많이 드는 작업의 경우 PlayFab 로비 및 매치 메이킹 SDK는 비동기 API를 노출합니다. 비동기식 API는 기본 스레드에서 비용이 많이 들거나 느린 작업을 시작하고 선택한 스레드에서 해당 작업이 완료될 때까지 폴링할 수 있는 기능을 제공합니다. 이와 동일한 폴링 메커니즘은 SDK 업데이트의 비동기 알림을 타이틀 코드에 전달하는 데에도 사용됩니다. 이 페이지에서는 PlayFab 로비 및 매치 메이킹 SDK의 비동기 API 패턴에 대한 개요와 이에 대한 프로그래밍 모범 사례를 제공합니다.

기본 API 패턴

PlayFab 로비 및 매치 메이킹 SDK에서 알아야 할 두 가지 유형의 비동기 API 패턴이 있습니다.

  1. 비동기 작업
  2. 비동기 알림

비동기 작업

SDK의 비동기 API를 사용하는 것은 간단합니다. 비동기 작업을 시작하고 완료하는 일반적인 패턴은 다음과 같습니다.

  1. 선택한 적절한 비동기 API에 대한 일반 메서드 호출을 만듭니다. 사용할 수 있는 일반적인 비동기 작업에는 다음이 포함됩니다.

  2. SUCCEEDED() 또는 FAILED() 매크로를 사용하여 API의 HRESULT 반환 값을 확인합니다. 동기적으로 반환된 이 값은 작업이 성공적으로 시작되었는지 여부를 알려줍니다.

Warning

비동기 API 호출의 동기 반환 값은 작업이 성공적으로 완료되었는지 여부를 알려주지 않습니다. 동기 및 비동기 오류에 대한 자세한 내용은 SDK의 오류 처리 문서를 확인하세요.

  1. PFMultiplayerStartProcessingLobbyStateChanges() 또는 PFMultiplayerStartProcessingMatchmakingStateChanges에서 제공하는 연결된 작업의 "완료 상태 변경"을 찾아 비동기 작업의 완료를 폴링합니다. PFMultiplayerCreateAndJoinLobby()에 대한 연결된 "완료 상태 변경"의 예는 PFLobbyCreateAndJoinLobbyCompletedStateChange입니다. "상태 변경"이 무엇이고 어떻게 작동하는지에 대한 자세한 내용은 상태 변경 섹션에서 확인할 수 있습니다.

  2. 완료 상태 변경의 result 값을 확인하여 작업의 성공 여부를 확인합니다. 이러한 오류 값에 대한 자세한 내용은 SDK의 오류 처리 문서에서 찾을 수 있습니다.

비동기 알림

일부 기능은 로비 및 매치 메이킹 SDK의 변경 사항에 대한 비동기 알림을 생성합니다.

일반적인 알림은 다음과 같습니다.

  1. 로비 업데이트 알림.
  2. 로비 연결 해제 알림.
  3. 매치 메이킹 티켓 상태 변경 알림.

이러한 비동기 알림은 SDK에서 PFMultiplayerStartProcessingLobbyStateChanges()PFMultiplayerStartProcessingMatchmakingStateChanges를 통해 "상태 변경"으로 제공됩니다.

"상태 변경"이 무엇이고 어떻게 작동하는지에 대한 자세한 내용은 상태 변경 섹션에서 확인할 수 있습니다.

상태 변경

로비 및 매치 메이킹 SDK의 비동기 API 모델은 PFLobbyStateChangePFMatchmakingStateChange 구조체를 중심으로 구축됩니다. PFLobbyStateChanges는 로비 하위 시스템의 변경 사항을 알려주고 PFMatchmakingStateChanges는 매치 메이킹 하위 시스템의 변경 사항을 알려줍니다.

이러한 "상태 변경"은 SDK의 이벤트에 대한 비동기 알림입니다. 이러한 알림은 내부적으로 대기하며 PFMultiplayerStartProcessingLobbyStateChanges()PFMultiplayerStartProcessingMatchmakingStateChanges를 호출하여 처리합니다. 이러한 함수는 각 API 하위 시스템에 대해 대기 중인 모든 상태 변경 사항을 반복하고 개별적으로 처리할 수 있는 목록으로 반환합니다. 각 상태 변경에는 알림을 받고 있는 특정 상태 변경을 확인하기 위해 검사할 수 있는 해당 stateChangeType 필드가 있습니다. 어떤 상태 변경이 주어졌는지 알게 되면 일반 PFLobbyStateChange 또는 PFMatchmakingStateChange 구조체를 보다 구체적인 유형의 상태 변경 구조체로 변환하여 해당 이벤트의 특정 데이터를 검사할 수 있습니다.

일반적으로는 상태 변경 처리는 각각의 상태 변화를 처리기에 위임하는 단순한 스위치 문으로 구현됩니다.

상태 변경 목록이 PFMultiplayerStartProcessingLobbyStateChanges 또는 PFMultiplayerStartProcessingMatchmakingStateChanges에서 처리되면 PFMultiplayerFinishProcessingMatchmakingStateChanges() 또는 PFMultiplayerFinishProcessingMatchmakingStateChanges()로 각각 반환되어야 합니다.

//
// Process Lobby state changes
//
uint32_t lobbyStateChangeCount;
const PFLobbyStateChange * const * lobbyStateChanges;
HRESULT hr = PFMultiplayerStartProcessingLobbyStateChanges(m_pfmHandle, &lobbyStateChangeCount, &lobbyStateChanges);
if (FAILED(hr))
{
    return hr;
}

for (uint32_t i = 0; i < lobbyStateChangeCount; ++i)
{
    const PFLobbyStateChange* stateChange = lobbyStateChanges[i];
    switch (stateChange->stateChangeType)
    {
        case PFLobbyStateChangeType::CreateAndJoinLobbyCompleted:
        {
            HandleCreateAndJoinLobbyCompleted(
                static_cast<const PFLobbyCreateAndJoinLobbyCompletedStateChange*>(stateChange));
            break;
        }
        // add other state change handlers here
    }
}

hr = PFMultiplayerFinishProcessingLobbyStateChanges(m_pfmHandle, lobbyStateChangeCount, lobbyStateChanges);
if (FAILED(hr))
{
    return hr;
}

//
// Process Match state changes
//
uint32_t matchStateChangeCount;
const PFMatchmakingStateChange * const * matchStateChanges;
hr = PFMultiplayerStartProcessingMatchmakingStateChanges(m_pfmHandle, &matchStateChangeCount, &matchStateChanges);
if (FAILED(hr))
{
    return hr;
}

for (uint32_t i = 0; i < matchStateChangeCount; ++i)
{
    const PFMatchmakingStateChange* stateChange = matchStateChanges[i];
    switch (stateChange->stateChangeType)
    {
        case PFMatchmakingStateChangeType::TicketStatusChanged:
        {
            HandleMatchmakingTicketStatusChanged(
                static_cast<const PFMatchmakingTicketStatusChangedStateChange*>(stateChange));
            break;
        }
        // add other state change handlers here
    }
}

hr = PFMultiplayerFinishProcessingMatchmakingStateChanges(m_pfmHandle, matchStateChangeCount, matchStateChanges);
if (FAILED(hr))
{
    return hr;
}

비동기 작업 컨텍스트

각각의 비동기 API에는 void* asyncContext 매개 변수가 포함됩니다. 이 값은 PFMultiplayerStartProcessingLobbyStateChanges() 또는 PFMultiplayerStartProcessingMatchmakingStateChanges()에 의해 제공되면 이 API 호출의 관련 완료 상태 변경에 설정되는 전달 매개 변수입니다.

이 값은 비동기 API 호출에 임의의 포인터 크기 컨텍스트를 연결하는 메커니즘을 제공합니다. 이러한 컨텍스트는 다음을 비롯한 여러 시나리오에서 사용할 수 있습니다.

  1. 타이틀별 데이터를 SDK 호출과 연결
  2. 공유 식별자로 다양한 비동기 작업을 한꺼번에 연결

이러한 비동기 컨텍스트는 SDK 사용에 필요하지 않지만 일부 타이틀 논리를 더 쉽게 작성할 수 있습니다.

작업 대기열

비동기 API로 작업할 때 여러 비동기 작업을 더 큰 비동기 흐름의 일부로 순차적으로 실행해야 하는 경우가 많습니다.

로비 및 매치 메이킹 SDK에서 로비를 생성하고 해당 로비에 대해 친구에게 초대장을 보내는 것이 한 가지 예입니다. 직렬화하면 이러한 흐름은 다음과 같은 모습입니다.

  1. PFMultiplayerCreateAndJoinLobby()를 호출하여 PlayFab 로비를 만들고 참여합니다.
  2. PFLobbyCreateAndJoinLobbyCompletedStateChange가 로비가 성공적으로 생성되고 참가했음을 반영할 때까지 기다립니다.
  3. 초대된 각 친구에 대해 PFLobbySendInvite()를 호출합니다.
  4. PFLobbySendInviteCompletedStateChange가 초대가 성공적으로 전송되었음을 반영할 때까지 기다립니다.

보다 복잡한 흐름과 타이틀 논리에도 이러한 직렬화 패턴이 적절할 수 있습니다. 그러나 간단한 흐름을 위해 SDK는 타이틀 코드를 단순화하려는 대안을 제공합니다.

SDK의 많은 비동기 API는 이전 작업이 완전히 완료되기 전에 종속 작업의 대기를 지원합니다. 이전 예에서 로비가 성공적으로 생성된 것을 확인하기 전에 로비에 대한 초대를 보낼 수 있습니다.

사실상 큐를 사용하면 비동기 작업 모음을 함께 묶고 한 번에 시작하고 오류 처리를 단일 실패 지점으로 통합할 수 있습니다.

PFLobbyHandle newLobby;
HRESULT hr = PFMultiplayerCreateAndJoinLobby(m_pfmHandle, myPlayerEntityId, newLobbyConfiguration, nullptr, nullptr, &newLobby);
if (SUCCEEDED(hr))
{
    for (size_t i = 0; SUCCEEDED(hr) && i < friends.size(); ++i)
    {
        hr = PFLobbySendInvite(m_pfmHandle, myPlayerEntityId, friends[i], nullptr);
    }

    if (SUCCEEDED(hr))
    {
        m_lobby = newLobby;
        Log("Created lobby and invited %zu friends!", friends.size());
    }
    else
    {
        // For the purposes of demonstration, we could have a policy that we shouldn't bother with any lobbies where
        // we couldn't invite all of our friends.
        (void) PFLobbyLeave(newLobby, myPlayerEntityId, nullptr);
    }
}

비동기 작업 제어

라이브러리와 타이틀의 핵심 CPU 워크로드 간의 CPU 매치를 피하기 위해 타이틀이 비동기 작업이 수행되는 위치를 제어해야 하는 경우가 있습니다.

로비 및 매치 메이킹 SDK를 사용하면 스레드 선호도 제어를 통해 비동기 작업이 실행되는 방식을 제어할 수 있습니다.

스레드 선호도 제어

기본적으로 비동기 SDK 작업은 신중하게 제어되는 백그라운드 스레드에서 수행됩니다. 일부 타이틀은 CPU 매치를 피하기 위해 이러한 백그라운드 스레드가 예약되는 위치에 대한 대략적인 제어가 필요합니다.

이러한 타이틀의 경우 로비 및 매치 메이킹 SDK는 PFMultiplayerSetThreadAffinityMask()를 제공합니다. 지원되는 플랫폼에서 이를 통해 SDK의 백그라운드 스레드에 사용할 CPU 코어를 제한할 수 있습니다. 이렇게 하면 매치 없이 특정 코어가 자체 CPU 워크로드용으로 예약되도록 보장할 수 있습니다.