Freigeben über


Verwenden der PlayFab-Party mit MPSD

Xbox Multiplayer-Szenarien basieren auf der Verwendung des Multiplayer Session Directory (MPSD)-Diensts und MPSD-Dokumente. MPSD-Dokumente dienen als Liste für Ihre aktuelle Spielsitzung und steuern Multiplayer-Erfahrungen wie Matchmaking, Plattformeinladungen, Aktuelle Spielerlisten und Join-in-Prgress.

In diesem Dokument wird beschrieben, wie Sie PlayFab Party in gängige Multiplayer-Flows integrieren können, die MPSD erfordern.

Dieses Dokument bietet keine ausführliche Erläuterung von MPSD und all seinen Funktionen. Weitere Informationen finden Sie in der MPSD-Dokumentation.

Spielersuche

Hier sehen Sie einen vereinfachten Ablauf für die Verwendung von Matchmaking und MPSD zusammen mit PlayFab Party:

  1. Die Spieler erstellen MPSD-Sitzungen, die die Gruppen darstellen, die sie über Matchmaking-Sitzungen hinweg gemeinsam spielen möchten. Spieler sammeln sich in diesen Sitzungen, indem sie die Einladungs- und Teilnahmefeatures von Xbox verwenden.

  2. Diese Spielergruppen übermitteln Tickets an den Matchmaking-Dienst, der kompatible Spielergruppen in einer Matchmaking-Sitzung sammelt. Diese Matchmaking-Sitzung selbst wird durch ein neues Sitzungsdokument dargestellt, dem die Spieler dann beitreten werden. Die Spieler müssen auch auf Änderungen an diesem Sitzungsdokument lauschen.

  3. Sobald die Matchmaking-Sitzung abgeschlossen und die Liste gesperrt ist, muss der Titel eines der Mitglieder der Matchmaking-Sitzung auswählen, um das PlayFab Party-Netzwerk einzurichten. Eine einfache Strategie für die Auswahl des Parteinetzwerkerstellers besteht darin, das erste Mitglied des MPSD-Sitzungsdokuments für die Zuordnung zu verwenden.

  4. Das ausgewählte Mitglied erstellt das Netzwerk mit einer initialen PartyInvitation , die den Netzwerkzugriff auf die Mitglieder der Matchmaking-Sitzung beschränkt. Nachdem die Erstellung des Netzwerks erfolgreich abgeschlossen wurde, sollte das ausgewählte Mitglied den resultierenden Netzwerkdeskriptor und die Party-Einladung als Sitzungseigenschaft an das Sitzungsdokument senden, die von anderen Mitgliedern verwendet werden kann.

    void
    OnMatchmakingSessionFinalized(
        uint32_t usersInSessionCount,
        const uint64_t* usersInSession
        )
    {
        PartyInvitationConfiguration initialInvite{};
        initialInvite.identifier = nullptr; // let Party select the invitation identifier for simplicity
        initialInvite.revocability = PartyInvitationRevocability::Anyone; // must be revocable by anyone
    
        // the updated invite should contain all users in the matchmaking session
        std::vector<PartyString> entityIdsInSession;
        for (uint32_t i = 0; i < usersInSessionCount; ++i)
        {
            uint64_t xboxUserId = usersInSession[i];
            // Call title-defined xuid->entityid mapping helper
            PartyString xboxUserEntityId = GetEntityIdFromXboxUserId(xboxUserId);
            if (xboxUserEntityId != nullptr)
            {
                entityIdsInSession.push_back(xboxUserEntityId);
            }
            else
            {
                DEBUGLOG("User %llu did not have a matching entity ID.", xboxUserId);
            }
        }
        initialInvite.entityIdCount = entityIdsInSession.size();
        initialInvite.entityIds = entityIdsInSession.data();
    
        // This is an asynchronous call. It will be completed when StartProcessingStateChanges generates a
        // PartyCreateNewNetworkCompletedStateChange struct
        PartyError error = PartyManager::GetSingleton().CreateNewNetwork(
            m_localPartyUser,
            &networkConfiguration,
            0,
            nullptr,
            &initialInvite,
            nullptr,
            nullptr,
            nullptr);
        if (FAILED(error))
        {
            DEBUGLOG("PartyManager::CreateNetwork failed! 0x%08x\n", error);
            return;
        }
    }
    
    void
    HandleCreateNewNetworkCompleted(
        const PartyCreateNewNetworkCompletedStateChange& createNewNetworkCompletedStateChange
        )
    {
        if (createNewNetworkCompletedStateChange.result == PartyStateChangeResult::Succeeded)
        {
            // The network was created successfully! Post the networks descriptor and invitation
    
            char serializedDescriptor[c_maxSerializedNetworkDescriptorStringLength + 1];
            PartyError error = PartyManager::SerializeNetworkDescriptor(
                &createNewNetworkCompletedStateChange.networkDescriptor,
                serializedDescriptor);
            if (PARTY_FAILED(error))
            {
                DEBUGLOG("PartyManager::SerializeNetworkDescriptor failed: 0x%08x\n", error);
                return;
            }
    
            UpdateSessionProperty(
                "PartyNetworkDescriptor", // arbitrary property name
                serializedDescriptor);
    
            UpdateSessionProperty(
                "PartyInitialInvitation", // arbitrary property name
                createNewNetworkCompletedStateChange.appliedInitialInvitationIdentifier);
        }
        else
        {
            // The network was not created successfully.
            // Please refer to CreateNewNetwork reference documentation for retry guidance
        }
    }
    
  5. Wenn jedem Mitglied das Aktualisierte des Sitzungsdokuments angezeigt wird, kann es den Netzwerkdeskriptor und die Einladung verwenden, um eine Verbindung mit dem Netzwerk herzustellen und dem Netzwerk beizutreten.

    void
    OnNetworkInformationPostedToSessionDocument(
        PartyString serializedNetworkDescriptor,
        PartyString invitationId
        )
    {
        PartyNetworkDescriptor networkDescriptor;
        PartyError error = PartyManager::DeserializeNetworkDescriptor(serializedNetworkDescriptor, &networkDescriptor);
        if (PARTY_FAILED(error))
        {
            DEBUGLOG("PartyManager::DeserializeNetworkDescriptor failed: 0x%08x\n", error);
            return;
        }
    
        // attempt to connect to the network
        PartyNetwork* network;
        error = PartyManager::GetSingleton().ConnectToNetwork(
            &networkDescriptor,
            nullptr,
            &network);
        if (PARTY_FAILED(error))
        {
            DEBUGLOG("PartyManager::ConnectToNetwork failed: 0x%08x\n", error);
            return;
        }
    
        // immediately queue an authentication on the network we've attempted to connect to.
        error = network->AuthenticateLocalUser(
            m_localUser,
            invitationId,
            nullptr);
        if (PARTY_FAILED(error))
        {
            DEBUGLOG("PartyNetwork::AuthenticateLocalUser failed: 0x%08x\n", error);
            return;
        }
    }
    

Notiz

Hier haben wir einen Flow für die Integration von Matchmaking und MPSD mit PlayFab Party vorgestellt. Die Kernideen dieses Flows können auf andere Flows erweitert werden, an denen Sie mit MPSD möglicherweise interessiert sind, aber die Darstellung aller möglichen Flows liegt außerhalb des Rahmens dieser Dokumentation. Weitere Informationen finden Sie in der vollständigen MPSD-Dokumentation.

Plattform-Einladungen

Hier ist ein Flow zum Integrieren von Xbox-Plattformeinladungen in playFab Party:

  1. PlayerA erstellt ein MPSD-Sitzungsdokument, lauscht auf Sitzungsänderungen und erstellt ein Party-Netzwerk. Wenn die Erstellung des Parteinetzwerks abgeschlossen ist, sendet *PlayerA * den Netzwerkdeskriptor und eine anfängliche Einladung (falls erforderlich) in das MPSD-Sitzungsdokument.

    void
    OnSessionDocumentCreated()
    {
        // This is an asynchronous call. It will be completed when StartProcessingStateChanges generates a
        // PartyCreateNewNetworkCompletedStateChange struct
        PartyError error = PartyManager::GetSingleton().CreateNewNetwork(
            m_localPartyUser,
            &networkConfiguration,
            0,
            nullptr,
            nullptr,
            nullptr,
            nullptr,
            nullptr);
        if (FAILED(error))
        {
            DEBUGLOG("PartyManager::CreateNetwork failed! 0x%08x\n", error);
            return;
        }
    }
    
    void
    HandleCreateNewNetworkCompleted(
        const PartyCreateNewNetworkCompletedStateChange& createNewNetworkCompletedStateChange
        )
    {
        if (createNewNetworkCompletedStateChange.result == PartyStateChangeResult::Succeeded)
        {
            // The network was created successfully! Post the networks descriptor and invitation
    
            char serializedDescriptor[c_maxSerializedNetworkDescriptorStringLength + 1];
            PartyError error = PartyManager::SerializeNetworkDescriptor(
                &createNewNetworkCompletedStateChange.networkDescriptor,
                serializedDescriptor);
            if (PARTY_FAILED(error))
            {
                DEBUGLOG("PartyManager::SerializeNetworkDescriptor failed: 0x%08x\n", error);
                return;
            }
    
            UpdateSessionProperty(
                "PartyNetworkDescriptor", // arbitrary property name
                serializedDescriptor);
        }
        else
        {
            // The network was not created successfully.
            // Please refer to CreateNewNetwork reference documentation for retry guidance
        }
    }
    
  2. Wenn PlayerAPlayerB zum Party-Netzwerk einladen möchte, initiiert PlayerA eine Plattformeinladung zu PlayerB über die Benutzeroberfläche im Spiel oder der Konsole.

  3. PlayerB empfängt die Plattformeinladung, die ein "Einladungshandle" enthält, mit dem PlayerB das MPSD-Sitzungsdokument von PlayerA suchen kann.

  4. PlayerB tritt dem Sitzungsdokument bei und lauscht auf Änderungen.

  5. PlayerA erkennt , dass PlayerB dem Sitzungsdokument beigetreten ist. PlayerA erstellt eine neue Einladung für PlayerB zur Verwendung und veröffentlicht diese Einladung zum Sitzungsdokument.

    void
    OnUserJoinedSessionDocument(
        PartyNetwork* network,
        uint64_t newSessionMemberXboxUserId
        )
    {
        std::string newMemberIdString = std::to_string(newSessionMemberXboxUserId);
    
        // Specify our own invitation id so we don't have to query for it after the invitation has been created.
        // Here we will specify the invite id with the format "InviterXboxUserID_InviteeXboxUserID" so that we can
        // ensure this invitation ID doesn't clash with the invitations other members might try and create for this user.
        std::string invitationId = std::to_string(m_localXboxUserId) + "_" + newMemberIdString;
    
        PartyInvitationConfiguration newInvite{};
        newInvite.identifier = invitationId.c_str();
        newInvite.revocability = PartyInvitationRevocability::Creator; // must be revocable by the creator only
    
        // Call title-defined xuid->entityid mapping helper
        PartyString newSessionMemberEntityId = GetEntityIdFromXboxUserId(newSessionMemberXboxUserId);
        newInvite.entityIdCount = 1;
        newInvite.entityIds = &newSessionMemberEntityId;
    
        // Create a new invitation which includes all of the users currently in the document
        PartyInvitation* newInvitation;
        PartyError error = network->CreateInvitation(
            m_localUser,
            &newInvite,
            nullptr,
            &newInvitation);
        if (PARTY_FAILED(error))
        {
            DEBUGLOG("PartyNetwork(0x%p)::CreateInvitation failed! (error=0x%x)", network, error);
            return;
        }
    
        // Post the invitation to the local user's member property store in the session document, key'd by the invitee's
        // xbox user id. This will let the invitee recognize when an invitation is intended for them.
        UpdateMemberProperty(
            newMemberIdString.c_str(),
            invitationId.c_str());
    }
    
  6. PlayerB sieht die Im Sitzungsdokument gepostete Einladung und verwendet sie, um dem Party-Netzwerk beizutreten.

    void
    OnRemoteMemberPropertyUpdated(
        PartyString memberPropertyKey,
        PartyString memberPropertyValue
        )
    {
        // The member property update signifies a new invitation, if the remote member updated a property that matches
        // our xbox user id.
        if (memberPropertyKey == std::to_string(m_localXboxUserId))
        {
            OnUserInvitationPostedToSessionDocument(memberPropertyValue);
        }
    
        // ...
    }
    
    void
    OnUserInvitationPostedToSessionDocument(
        PartyString invitationId
        )
    {
        // The network descriptor should have already been posted to the session document before the invitation.
        // Call title-defined function to pull it from the session document.
        PartyNetworkDescriptor networkDescriptor = QueryNetworkDescriptorFromSessionDocument();
    
        // attempt to connect to the network
        PartyNetwork* network;
        error = PartyManager::GetSingleton().ConnectToNetwork(
            &networkDescriptor,
            nullptr,
            &network);
        if (PARTY_FAILED(error))
        {
            DEBUGLOG("PartyManager::ConnectToNetwork failed: 0x%08x\n", error);
            return;
        }
    
        // immediately queue an authentication on the network we've attempted to connect to.
        error = network->AuthenticateLocalUser(
            m_localUser,
            invitationId,
            nullptr);
        if (PARTY_FAILED(error))
        {
            DEBUGLOG("PartyNetwork::AuthenticateLocalUser failed: 0x%08x\n", error);
            return;
        }
    }
    

    Wichtig

    Über PartyNetwork::CreateInvitation erstellte Einladungen werden ungültig, wenn der PartyLocalUser, der sie erstellt hat, das Netzwerk verlässt. Wenn ein neuer Benutzer sich selbst zu einem Sitzungsdokument hinzufügt, aber der Benutzer, der ihn eingeladen hat, verlässt, empfiehlt es sich, sich selbst aus dem Sitzungsdokument zu entfernen und darauf zu warten, dass er von einem anderen Benutzer erneut eingeladen wird.

Beitritt wird ausgeführt

Die Teilnahme an laufenden Spielsitzungen ist dem Szenario zum Einladen von Plattformen sehr ähnlich. Der Hauptunterschied besteht darin, dass PlayerB anstelle von PlayerAein " Einladungshandle" sendet, ein "Join-Handle" erhält, wenn er einen Join-In-Progress über die Plattformbenutzeroberfläche initiiert. Mithilfe dieses "Join-Handles" tritt der PlayerB dem Sitzungsdokument bei und lauscht auf Änderungen. PlayerA antwortet, indem er eine neue Partyeinladung für das Sitzungsdokument erstellt und veröffentlicht. PlayerB sieht diese neue Einladung zusammen mit dem Netzwerkdeskriptor und verwendet sie, um dem Party-Netzwerk beizutreten.

Wichtig

Über PartyNetwork::CreateInvitation erstellte Einladungen werden ungültig, wenn der PartyLocalUser, der sie erstellt hat, das Netzwerk verlässt. Wenn ein neuer Benutzer eine Parteieinladung aus dem Ablauf für den Beitritt erhält, diese jedoch nicht verwenden kann, wird empfohlen, dass der neue Benutzer, der ihn erstellt hat, sich selbst aus dem Sitzungsdokument entfernen und später erneut beitreten kann. Dadurch kann ein anderes Mitglied der Sitzung den Flow neu starten und eine neue Party-Einladung für diesen Benutzer generieren.

Trennen und Bereinigen

Wenn ein Spieler ein Partynetzwerk verlässt oder anderweitig von diesem getrennt ist, sollte er sich auch selbst aus allen MPSD-Sitzungen entfernen, die diesem Parteinetzwerk zugeordnet sind. Die Trennung des Parteinetzwerks, die nicht von einem PartyNetwork::LeaveNetwork-Vorgang initiiert wurde, wird als schwerwiegend angesehen. Nach einer schwerwiegenden Trennung kann ein Player versuchen, eine erneute Verbindung herzustellen und sich erneut im Netzwerk zu authentifizieren, muss aber auch erneut an der MPSD-Sitzung teilnehmen.

Wenn die Verbindung eines Players zu einer MPSD-Sitzung vorübergehend unterbrochen wird, wird er möglicherweise von dieser Sitzung getrennt. Spieler können versuchen, erneut an der Sitzung teilnehmen, sollten sich aber, wenn sie fehlschlagen, freiwillig aus dem Party-Netzwerk entfernen, indem sie PartyNetwork::LeaveNetwork aufrufen.

Notiz

Die Mechanismen und Heuristiken, die Trennungen für Partynetzwerke und MPSD-Sitzungen erkennen, sind unterschiedlich. Selbst in Szenarien, in denen ein Player sowohl vom Party-Netzwerk als auch vom MPSD-Sitzung getrennt wird, sind diese Trennungsereignisse unabhängig, und es ist nicht garantiert, dass sie in der Nähe zueinander auftreten. Titel sollten das Szenario behandeln, in dem ein Player nur vom Partynetzwerk oder der MPSD-Sitzung getrennt werden kann.

Wenn das Spiel heruntergefahren wird, wird der Spieler automatisch vom Partynetzwerk und MPSD-Dokument getrennt, und es ist keine weitere sauber erforderlich.