Party 快速入门

本快速入门介绍 PlayFab Party 的核心功能以及代码片段。 PlayFab Party 的设计初衷就是跨平台。 我们以相同方式构建了这些快速入门,其中大多数信息适用于所有平台,链接的文档中介绍了特定于平台的先决条件和步骤。

若要深入了解,请参阅链接的参考和概念文档以及每个平台的示例应用程序。

注意

本快速入门指南介绍如何使用 C++ Party SDK

先决条件

你需要一个 PlayFab 帐户,并且必须启用 Party 功能才能开始使用 Party。

  1. 创建或登录到 PlayFab 帐户。 有关说明,请参阅快速入门:Game Manager
  2. 从 PlayFab 帐户通过 Game Manager 启用 Party 功能

平台先决条件

在开始本快速入门之前,请执行以下主题中指定的任何特定于平台的必要设置:

  1. Android 先决条件

  2. iOS 和 MacOS 先决条件

  1. Linux 先决条件

完成特定于平台的步骤后,请继续执行本主题中的其余步骤以设置 PlayFab Party。

下载并设置 Party SDK

有适用于不同平台和游戏引擎的 Party SDK。 选择并下载所需的文件。 有关下载链接,请参阅 Party SDK

安装 SDK 后,在开始编写代码之前,你可能需要运行示例以了解 Party 的工作原理。 若要下载示例,请转到 Party 示例

如果你在 Xbox 和电脑游戏中使用 Party,建议使用 Party Xbox Live帮助程序库来确保一致的功能和行为。 此库可帮助你的游戏满足 Xbox Live 要求。 若要了解详细信息,请参阅 Xbox 要求

登录 PlayFab 游戏并获取实体令牌和实体 ID

若要初始化和使用 Party,必须登录 PlayFab。 可以使用 PlayFabClientAPI::LoginWithCustomID 或特定于平台的登录方法。

执行登录后,PlayFab 将作为 LoginResult 的一部分返回实体 ID 和实体令牌。 这两个关键信息将用于初始化 PlayFab Party 的本地用户实例。

以下代码片段显示了使用在 PlayFabManager.cpp 中实现的自定义 ID 登录的示例:

PlayFabClientAPI::LoginWithCustomID(
    loginRequest,
    [this, callback, userId](const LoginResult& loginResult, void*)
    {
        // Sign in was successful.
        DEBUGLOG("PlayFab::signin -- Login with custom id callback\n");

        // Save the PlayFab id and entity data for Party authentication.
        m_playfabId = loginResult.PlayFabId;
        if (loginResult.EntityToken.notNull() && loginResult.EntityToken->Entity.notNull())
        {
            m_entityKey = loginResult.EntityToken->Entity;
            m_entityToken = loginResult.EntityToken->EntityToken;
        }

从 PlayFab 成功获取实体 ID 和实体令牌后,便可以继续启用并初始化 Party。

注意

如果使用的是 Xbox Live,还可以使用 Party Xbox Live 帮助程序库登录。

初始化 PlayFab Party

在高级别,初始化 Party 涉及以下步骤:

  1. 获取对 PartyManager 的单一实例引用并对其进行初始化。
    这是用于与群库交互的主要管理类。
    auto& partyManager = PartyManager::GetSingleton();
    PartyError err;

    //Only initialize the party manager once.
    if (m_partyInitialized == false)
    {
        // Initialize PlayFab Party
        err = partyManager.Initialize(titleId);
        if (PARTY_FAILED(err))
        {
            DEBUGLOG("Initialize failed: %s\n", GetErrorMessage(err));
            return;
        }

        m_partyInitialized = true;
    }
  1. 创建本地用户对象。
    执行网络和聊天操作时用于在设备(电脑、主机、电话……)上代表本地用户的本地用户对象。 本地用户对象使用 PlayFab 实体 ID 进行初始化。
    //Only create a local user object if it doesn't exist.
    if (m_localUser == nullptr)
    {
        PartyString entityId = Managers::Get<PlayFabManager>()->EntityId().c_str();
        PartyString entityToken = Managers::Get<PlayFabManager>()->EntityToken().c_str();

        // Create a local user object
        err = partyManager.CreateLocalUser(
            entityId,                                   // User id
            entityToken,                                // User entity token
            &m_localUser                                // OUT local user object
        );

        if (PARTY_FAILED(err))
        {
            DEBUGLOG("CreateLocalUser failed: %s\n", GetErrorMessage(err));
            return;
        }
    }
  1. 创建聊天控件并设置音频输入和输出通道,Party 将在其中接收或转发数据。
    聊天控件对象管理用户在特定设备上的聊天操作。
    // Only create local chat controls if they don't exist.
    if (m_localChatControl == nullptr)
    {
        PartyLocalDevice* localDevice = nullptr;

        // Retrieve the local device
        err = partyManager.GetLocalDevice(&localDevice);

        if (PARTY_FAILED(err))
        {
            DEBUGLOG("GetLocalDevice failed: %s\n", GetErrorMessage(err));
            return;
        }

        // Create a chat control for the local user on the local device
        err = localDevice->CreateChatControl(
            m_localUser,                                // Local user object
            m_languageCode,                             // Language id
            nullptr,                                    // Async identifier
            &m_localChatControl                         // OUT local chat control
        );

        if (PARTY_FAILED(err))
        {
            DEBUGLOG("CreateChatControl failed: %s\n", GetErrorMessage(err));
            return;
        }

        // Use system default settings for the audio input device
        err = m_localChatControl->SetAudioInput(
            PartyAudioDeviceSelectionType::SystemDefault,   // Selection type
            nullptr,                                        // Device id
            nullptr                                         // Async identifier
        );

        if (PARTY_FAILED(err))
        {
            DEBUGLOG("SetAudioInput failed: %s\n", GetErrorMessage(err));
            return;
        }

        // Use system default settings for the audio output device
        err = m_localChatControl->SetAudioOutput(
            PartyAudioDeviceSelectionType::SystemDefault,   // Selection type
            nullptr,                                        // Device id
            nullptr                                         // Async identifier
        );

        if (PARTY_FAILED(err))
        {
            DEBUGLOG("SetAudioOutput failed: %s\n", GetErrorMessage(err));
        }
  1. 设置听录和翻译选项。
    听录和翻译是可选聊天功能,可以显著提高游戏的辅助功能。 有关这些功能的详细信息,请参阅聊天概述
        // Get the available list of text to speech profiles
        err = m_localChatControl->PopulateAvailableTextToSpeechProfiles(nullptr);

        if (PARTY_FAILED(err))
        {
            DEBUGLOG("Populating available TextToSpeechProfiles failed: %s \n", GetErrorMessage(err));
        }

        // Set transcription options for transcribing other users regardless of language, and ourselves.
        PartyVoiceChatTranscriptionOptions transcriptionOptions =
            PartyVoiceChatTranscriptionOptions::TranscribeOtherChatControlsWithMatchingLanguages |
            PartyVoiceChatTranscriptionOptions::TranscribeOtherChatControlsWithNonMatchingLanguages |
            PartyVoiceChatTranscriptionOptions::TranslateToLocalLanguage |
            PartyVoiceChatTranscriptionOptions::TranscribeSelf;

        // Set the transcription options on our chat control.
        err = m_localChatControl->SetTranscriptionOptions(
            transcriptionOptions,                       // Transcription options
            nullptr                                     // Async identifier
        );

        if (PARTY_FAILED(err))
        {
            DEBUGLOG("SetTranscriptionOptions failed: %s\n", GetErrorMessage(err));
        }

        // Enable translation to local language in chat controls.
        err = m_localChatControl->SetTextChatOptions(
            PartyTextChatOptions::TranslateToLocalLanguage,
            nullptr
        );

此时,你已在应用程序或游戏中初始化了 PlayFab Party。

有关完整示例,请参阅演示应用中的 NetworkManager.cpp 中的 NetworkManager::Initialize() 代码。

下一步是创建 Party 网络并连接到该网络。

创建 Party 网络

Party 网络是游戏为交换聊天或数据通信而创建的一个或多个设备及其授权用户的安全集合。 Party 网络通常与游戏的多人游戏会话或聊天“大厅”概念一致。 你只能向自己网络中的玩家发送消息。

以下代码片段演示了如何创建 Party 网络。

    // Initialize an empty network descriptor to hold the result of the following call.
    PartyNetworkDescriptor networkDescriptor = {};

    // Create a new network descriptor
    err = PartyManager::GetSingleton().CreateNewNetwork(
        m_localUser,                                // Local User
        &cfg,                                       // Network Config
        0,                                          // Region List Count
        nullptr,                                    // Region List
        &invitationConfiguration,                   // Invitation configuration
        nullptr,                                    // Async Identifier
        &networkDescriptor,                         // OUT network descriptor
        nullptr                                     // applied initialinvitationidentifier.
    );

CreateNewNetwork() 的函数调用成功后,将返回/填充网络描述符 PartyNetworkDescriptor 对象。 描述符包含其他玩家连接到网络所需的数据。

有关其他函数参数的信息,请参阅 API 参考文档

创建 Party 网络后,使用邀请来控制哪些用户可以加入网络。 PlayFab 匹配、PlayFab 大厅、平台邀请或自定义游戏服务可用于与其他玩家共享连接详细信息。

最简单的邀请类型是包含网络描述符的开放邀请。 有关所有邀请类型和安全模型的详细信息,请参阅邀请和安全模型

共享群网络描述符

此时,你有一个群网络描述符,并且已准备好与其他玩家共享它。 有许多同步机制可用于共享此信息,但为了快速测试,你可以手动将群网络描述符从主机群会话复制并粘贴到来宾群会话。 我们建议使用 PlayFab 大厅在多人游戏中共享网络描述符,但你也可以根据游戏的需求使用自己的大厅服务、邀请或其他共享机制。

手动共享群网络描述符

  1. 在主机会话中,使用 PartyManager::SerializeNetworkDescriptor() 将网络描述符序列化为字符串,并将其打印到控制台。

  2. 在本地或远程复制网络描述符字符串并将其粘贴到另一个游戏。

  3. 在来宾会话中,使用 PartyManager::DeserializeNetworkDescriptor() 从网络描述符字符串反序列化网络描述符。

  4. 连接到 Party 网络。

使用 PlayFab 大厅共享群网络描述符

PlayFab 大厅可用于在玩家进入和退出比赛时暂时分组,并可用于同步网络描述符,以便玩家可以加入同一网络。 PlayFab 大厅可高度自定义,以支持所有受支持平台和跨平台的各种游戏需求。 有关在实时通知中使用 PlayFab 大厅的更多详细信息,请参阅 多人游戏 SDK 快速入门

有关将 PlayFab 大厅与 PlayFab Party 结合使用的详细信息,请参阅 使用 PlayFab 多人游戏 SDK 创建大厅

连接到 Party 网络

在获取群网络描述符后,按照以下步骤加入群网络:

  1. 使用 PartyManager::DeserializeNetworkDescriptor() 从网络描述符字符串反序列化网络描述符。

  2. 连接到 Party 网络。

  3. 对网络的本地用户进行身份验证。

  4. 将本地聊天控件连接到网络,以便我们可以使用 VoIP。

  5. 为游戏消息流量建立 Party 网络终结点

    PartyNetworkDescriptor networkDescriptor = {};

    // Deserialize the remote network's descriptor
    PartyError err = PartyManager::DeserializeNetworkDescriptor(descriptor, &networkDescriptor);

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("ConnectToNetwork failed to deserialize descriptor: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return;
    }

    // This portion of connecting to the network is the same for
    // both creating a new and joining an existing network.

    PartyError err = PartyManager::GetSingleton().ConnectToNetwork(
        &descriptor,                                // Network descriptor
        nullptr,                                    // Async identifier
        &m_network                                  // OUT network
    );

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("ConnectToNetwork failed: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return false;
    }

    // Authenticate the local user on the network so we can participate in it
    err = m_network->AuthenticateLocalUser(
        m_localUser,                                // Local user
        networkId,                                  // Invitation Id
        nullptr                                     // Async identifier
    );

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("AuthenticateLocalUser failed: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return false;
    }

    // Connect the local user chat control to the network so we can use VOIP
    err = m_network->ConnectChatControl(
        m_localChatControl,                         // Local chat control
        nullptr                                     // Async identifier
    );

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("ConnectChatControl failed: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return false;
    }

    // Establish a network endoint for game message traffic
    err = m_network->CreateEndpoint(
        m_localUser,                                // Local user
        0,                                          // Property Count
        nullptr,                                    // Property name keys
        nullptr,                                    // Property Values
        nullptr,                                    // Async identifier
        &m_localEndpoint                            // OUT local endpoint
    );

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("Failed to CreateEndpoint: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return false;
    }

将消息发送到另一个网络设备或终结点

连接到 Party 网络后,你可以使用本地终结点对象发送消息。

    if (m_localEndpoint && m_state == NetworkManagerState::NetworkConnected)
    {
        auto packet = message.Serialize();

        // Form the data packet into a data buffer structure
        PartyDataBuffer data[] = {
            {
                static_cast<const void*>(packet.data()),
                static_cast<uint32_t>(packet.size())
            },
        };

        // Set delivery options for guaranteed and sequential delivery.
        PartySendMessageOptions deliveryOptions =
            PartySendMessageOptions::GuaranteedDelivery |
            PartySendMessageOptions::SequentialDelivery;

        // Send out the message to all other peers
        PartyError err = m_localEndpoint->SendMessage(
            0,                                      // endpoint count; 0 = broadcast
            nullptr,                                // endpoint list
            deliveryOptions,                        // send message options
            nullptr,                                // configuration
            1,                                      // buffer count
            data,                                   // buffer
            nullptr                                 // async identifier
        );

        if (PARTY_FAILED(err))
        {
            DEBUGLOG("Failed to SendMessage: %s\n", GetErrorMessage(err));
        }
    }

NetworkManager.cpp 中提供了完整代码。

接收消息并在本地设备上呈现

最后一步是接收远程 Party 成员发送的消息并在设备上呈现(播放)它们。

重要

在前面的某个步骤中创建聊天控件时,你已设置了音频输入和输出设备,供群用于发送、接收和呈现音频数据。 若要接收音频消息,如果要流式传输音频,还需要在每个聊天控件之间设置适当的聊天权限。 默认情况下,聊天权限设置为“无”。 有关详细信息,请参阅聊天权限一文。

来自 Party 层的其他消息的处理最好在专用更新线程或高频游戏循环中中完成。 游戏循环应设置为运行每个帧并通过 StartProcessingStateChanges() 函数从 Party Manager 接收消息。

有关所有状态更改的完整说明,请参阅 Party 参考文档。 或者,你可以参考 NetworkManager.cpp,获取如何处理每个状态更改的示例。

处理游戏暂停

某些平台支持暂时暂停游戏执行:iOS、Switch 和 GDK。 当游戏暂停时,网络堆栈将失效,PlayFab Party 无法保持与 PlayFab Party 网络的连接。 使用 PlayFab Party 时,需要特别注意如何处理游戏暂停和恢复执行。

iOS

在 iOS 上,必须离开并重新连接到 PlayFab Party 网络

若要退出 Party 网络,请调用 LeaveNetwork()。 重新激活网络后,使用以前的 Party 网络描述符调用 ConnectToNetwork()

Switch 和 GDK

在 Nintendo Switch 和 Microsoft GDK 上,必须清理 PlayFab Party 并等待游戏执行继续,然后重新初始化 PlayFab Party 并重新连接到网络。

若要关闭 Party,请调用 Cleanup()

重要

调用 Cleanup() 可回收所有库资源并销毁所有库对象。 重新初始化 Party 后,需要重新创建任何库对象(如本地用户和聊天控件),并通过重新验证本地用户身份、重新连接聊天控件和重新创建终结点来重新建立任何以前的网络状态。

重新激活网络后,调用 Initialize()。 成功初始化 Party 后,需要执行以下步骤才能再次成功加入以前的 PlayFab Party 网络:

  1. 使用以前的 Party 网络描述符连接到 Party 网络。

  2. 重新创建任何本地用户对象,并将这些本地用户重新身份验证到网络中。

  3. 重新创建任何本地聊天控件,并将这些聊天控件重新连接到网络以启用 VOIP

  4. 为游戏消息流量重新创建任何 Party 网络终结点

    PartyError err = PartyManager::GetSingleton().ConnectToNetwork(
        &descriptor,                                // Network descriptor
        nullptr,                                    // Async identifier
        &m_network                                  // OUT network
    );

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("ConnectToNetwork failed: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return false;
    }

    // Authenticate the local user on the network so we can participate in it
    err = m_network->AuthenticateLocalUser(
        m_localUser,                                // Local user
        networkId,                                  // Invitation Id
        nullptr                                     // Async identifier
    );

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("AuthenticateLocalUser failed: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return false;
    }

    // Connect the local user chat control to the network so we can use VOIP
    err = m_network->ConnectChatControl(
        m_localChatControl,                         // Local chat control
        nullptr                                     // Async identifier
    );

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("ConnectChatControl failed: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return false;
    }

    // Establish a network endoint for game message traffic
    err = m_network->CreateEndpoint(
        m_localUser,                                // Local user
        0,                                          // Property Count
        nullptr,                                    // Property name keys
        nullptr,                                    // Property Values
        nullptr,                                    // Async identifier
        &m_localEndpoint                            // OUT local endpoint
    );

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("Failed to CreateEndpoint: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return false;
    }

重要

如果重新连接成功完成,该参与方现在将能够与其他对等方通信,但如果以前的网络不再存在,则重新连接将失败。 在这种情况下,应处理适当的连接错误。

后续步骤

详细了解 PlayFab Party 对象及其关系,并参阅 Party API 参考文档,以便游戏能够充分利用这些功能。

有关更多特定于 Xbox 的指南,请尽早并经常参阅 Xbox 要求

另请参阅