Freigeben über


Asynchrone Vorgänge und Benachrichtigungen

Für Vorgänge, die langsam oder rechenintensiv sein können, macht das PlayFab Lobby and Matchmaking SDK asynchrone APIs verfügbar. Asynchrone APIs bieten Ihnen die Möglichkeit, teure oder langsame Vorgänge von Ihren Standard Threads aus zu starten und den Abschluss dieser Vorgänge in einem Thread Ihrer Wahl abzufragen. Derselbe Abrufmechanismus wird auch verwendet, um asynchrone Benachrichtigungen über SDK-Updates an Ihren Titelcode zu übermitteln. Diese Seite bietet eine Übersicht über die asynchronen API-Muster und bewährten Methoden für die Programmierung des PlayFab Lobby and Matchmaking SDK.

Grundlegende API-Muster

Es gibt zwei Arten von asynchronen API-Mustern, die im PlayFab-Lobby- und Matchmaking SDK beachtet werden müssen:

  1. Asynchrone Vorgänge
  2. Asynchrone Benachrichtigungen

Asynchrone Vorgänge

Es ist einfach, die asynchronen APIs des SDK zu verwenden. Das allgemeine Muster zum Starten und Abschließen asynchroner Vorgänge sieht wie folgt aus:

  1. Führen Sie einen regulären Methodenaufruf an die entsprechende asynchrone API Ihrer Wahl aus. Zu den gängigen asynchronen Vorgängen, die Sie wahrscheinlich verwenden werden, gehören:

  2. Überprüfen Sie den HRESULT-Rückgabewert der API mit den Makros SUCCEEDED() oder FAILED(). Dieser synchron zurückgegebene Wert gibt An, ob der Vorgang erfolgreich gestartet wurde.

Warnung

Der synchrone Rückgabewert eines asynchronen API-Aufrufs informiert Sie NICHT darüber, ob der Vorgang erfolgreich abgeschlossen wurde. Weitere Informationen zu synchronen und asynchronen Fehlern finden Sie in der Dokumentation zur Fehlerbehandlung des SDK.

  1. Rufen Sie den Abschluss des asynchronen Vorgangs ab, indem Sie nach der "Abschlusszustandsänderung" des zugehörigen Vorgangs suchen, die von PFMultiplayerStartProcessingLobbyStateChanges() oder PFMultiplayerStartProcessingMatchmakingStateChanges bereitgestellt wird. Ein Beispiel für die zugeordnete "Änderung des Abschlusszustands" für PFMultiplayerCreateAndJoinLobby() ist PFLobbyCreateAndJoinLobbyCompletedStateChange. Ausführlichere Informationen dazu, was "Zustandsänderungen" sind und wie sie funktionieren, finden Sie im Abschnitt Zustandsänderungen .

  2. Überprüfen Sie den Ergebniswert der Änderung des Abschlusszustands, um zu ermitteln, ob der Vorgang erfolgreich war oder fehlgeschlagen ist. Ausführlichere Informationen zu diesen Fehlerwerten finden Sie in der Dokumentation zur Fehlerbehandlung des SDK.

Asynchrone Benachrichtigungen

Einige Features generieren asynchrone Benachrichtigungen über Änderungen am Lobby- und Matchmaking-SDK.

Zu den gängigen Benachrichtigungen gehören:

  1. Benachrichtigungen zum Aktualisieren des Wartebereichs.
  2. Benachrichtigungen zum Trennen des Wartebereichs.
  3. Matchmaking Ticket status Änderungsbenachrichtigungen.

Diese asynchronen Benachrichtigungen werden Ihnen vom SDK als "Zustandsänderungen" über PFMultiplayerStartProcessingLobbyStateChanges() und PFMultiplayerStartProcessingMatchmakingStateChanges bereitgestellt.

Ausführlichere Informationen dazu, was "Zustandsänderungen" sind und wie sie funktionieren, finden Sie im Abschnitt Zustandsänderungen .

Zustandsänderungen

Das asynchrone API-Modell des Lobby and Matchmaking SDK basiert auf den Strukturen PFLobbyStateChange und PFMatchmakingStateChange . PFLobbyStateChanges benachrichtigt Sie über Änderungen am Wartebereichssubsystem, und PFMatchmakingStateChanges benachrichtigt Sie über Änderungen am Matchmaking-Subsystem.

Diese "Zustandsänderungen" sind asynchrone Benachrichtigungen über Ereignisse vom SDK. Diese Benachrichtigungen werden intern in die Warteschlange eingereiht und verarbeitet, indem Sie PFMultiplayerStartProcessingLobbyStateChanges() und PFMultiplayerStartProcessingMatchmakingStateChanges aufrufen. Diese Funktionen geben alle Statusänderungen in der Warteschlange (für das jeweilige API-Subsystem) als Listen zurück, die Sie durchlaufen und einzeln verarbeiten können. Jede Zustandsänderung verfügt über ein entsprechendes stateChangeType-Feld , das überprüft werden kann, um zu bestimmen, über welche bestimmte Zustandsänderung Sie benachrichtigt werden. Sobald Sie wissen, welche Zustandsänderung Sie erhalten haben, können Sie die generische PFLobbyStateChange - oder PFMatchmakingStateChange-Struktur in einen spezifischeren Typ von Zustandsänderungsstruktur umwandeln, um die spezifischen Daten dieses Ereignisses zu überprüfen.

In der Regel wird die Verarbeitung von Zustandsänderungen als einfache Switch-Anweisung implementiert, die jede Zustandsänderung an einen Handler delegiert.

Nachdem die Liste der Zustandsänderungen von PFMultiplayerStartProcessingLobbyStateChanges oder PFMultiplayerStartProcessingMatchmakingStateChanges verarbeitet wurde, muss sie an PFMultiplayerFinishProcessingMatchmakingStateChanges() bzw . PFMultiplayerFinishProcessingMatchmakingStateChanges() zurückgegeben werden.

//
// 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;
}

Kontexte für asynchrone Vorgänge

Jede asynchrone API enthält einen void* asyncContext Parameter. Bei diesem Wert handelt es sich um einen Passthrough-Parameter, der bei der zugehörigen Vervollständigungsstatusänderung dieses API-Aufrufs festgelegt wird, sobald er von PFMultiplayerStartProcessingLobbyStateChanges() oder PFMultiplayerStartProcessingMatchmakingStateChanges() bereitgestellt wird.

Dieser Wert bietet Ihnen einen Mechanismus zum Anfügen beliebiger Kontexte in Zeigergröße an Ihre asynchronen API-Aufrufe. Diese Kontexte können in vielen Szenarien verwendet werden, darunter:

  1. Zuordnen von titelspezifischen Daten zu einem SDK-Aufruf
  2. Verknüpfen mehrerer asynchroner Vorgänge mit einem freigegebenen Bezeichner

Diese asynchronen Kontexte sind für die Verwendung des SDK nicht erforderlich, können aber das Schreiben von Titellogik vereinfachen.

Vorgangswarteschlange

Häufig müssen bei der Arbeit mit asynchronen APIs mehrere asynchrone Vorgänge sequenziell als Teil eines größeren asynchronen Flows ausgeführt werden.

Im Lobby and Matchmaking SDK wäre ein Beispiel das Erstellen einer Lobby und das Senden von Einladungen an Ihre Freunde für diese Lobby. Serialisiert, würde dieser Flow wie folgt aussehen:

  1. Rufen Sie PFMultiplayerCreateAndJoinLobby() auf, um eine PlayFab-Lobby zu erstellen und daran teilzunehmen.
  2. Warten Sie, bis PFLobbyCreateAndJoinLobbyCompletedStateChange angezeigt wird , dass der Wartebereich erfolgreich erstellt und hinzugefügt wurde.
  3. Rufen Sie PFLobbySendInvite() für jeden eingeladenen Freund an.
  4. Warten Sie, bis PFLobbySendInviteCompletedStateChange angezeigt wird, dass die Einladung erfolgreich gesendet wurde.

Für komplexere Flows und Titellogik kann dieses serialisierte Muster geeignet sein. Für einfachere Flows bietet das SDK jedoch eine Alternative, die den Titelcode vereinfachen soll:

Viele asynchrone APIs im SDK unterstützen das Warteschlangen von abhängigen Vorgängen, bevor ein vorheriger Vorgang vollständig abgeschlossen wurde. Im vorherigen Beispiel können Sie eine Einladung für einen Wartebereich senden, bevor Sie sehen, dass der Wartebereich erfolgreich erstellt wurde.

Durch Warteschlangen können Sie effektiv eine Sammlung asynchroner Vorgänge bündeln, alle gleichzeitig starten und die Fehlerbehandlung zu einem einzelnen Fehlerpunkt zusammenfassen.

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

Steuern asynchroner Arbeit

Es ist manchmal erforderlich, dass Titel steuern, wo asynchrone Arbeiten ausgeführt werden, um CPU-Konflikte zwischen Bibliotheken und den CPU-Kernworkloads des Titels zu vermeiden.

Mit dem Lobby and Matchmaking SDK können Sie steuern, wie asynchrone Arbeit ausgeführt wird, indem Sie die Threadaffinität steuern.

Steuern der Threadaffinität

Standardmäßig erfolgt die asynchrone SDK-Arbeit in sorgfältig kontrollierten Hintergrundthreads. Einige Titel benötigen eine grobkörnige Kontrolle darüber , wo diese Hintergrundthreads geplant werden, um CPU-Konflikte zu vermeiden.

Für diese Titel stellt das Lobby and Matchmaking SDK PFMultiplayerSetThreadAffinityMask() bereit. Auf unterstützten Plattformen können Sie so einschränken, welche CPU-Kerne für die Hintergrundthreads des SDK verwendet werden. Auf diese Weise können Sie ohne Konflikte sicherstellen, dass bestimmte Kerne für Ihre eigenen CPU-Workloads reserviert sind.