> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# GDK 快速入门

> 将 PlayFab Services C SDK 扩展库添加到 Microsoft GDK 游戏中，并从 XBOX 或 Windows GDK 代码进行第一次 PlayFab API 调用。

# 快速入门：GDK

开始使用适用于 Microsoft 游戏开发工具包（GDK）的 PlayFab Services SDK。按以下步骤将库包含到你的项目中，并试用基本 PlayFab 功能的示例代码。

本快速入门帮助你使用 GDK 进行第一次 PlayFab API 调用。在继续之前，请确保已完成 [快速入门：Game Manager](/services/playfab/live-service-management/gamemanager/quickstart) 中的步骤，以确保你拥有 PlayFab 账户并熟悉 PlayFab Game Manager。

## 要求

* 一个 [PlayFab 开发者账户](https://developer.playfab.com)。
* 已安装 [Visual Studio 2019 或 2022](https://visualstudio.microsoft.com/)。
  * 有关 GDK 开发对 Visual Studio 要求的更多信息，请参阅 [SDK 和工具要求](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/getstarted/overviews/sdk-and-tools#install-visual-studio)。

## 项目设置

与其他 GDK 扩展库类似，通过项目属性添加 PlayFab Services SDK。在你项目的 Configuration Properties 中，**Gaming Desktop** > **General** 下选择 **Gaming Extension Libraries**。在提示中，勾选 **PlayFab.Services.C**。

<img src="https://mintcdn.com/microsoft-4404708b/N3T1ucKV7zIMBudj/images/playfab/sdks/c/gdk1.png?fit=max&auto=format&n=N3T1ucKV7zIMBudj&q=85&s=7fef311a1c51b1ef7ed3c6b651ca7c67" alt="选择 PlayFab.Services.C 扩展库" width="624" height="288" data-path="images/playfab/sdks/c/gdk1.png" />

## 初始化和登录

### 头文件

包含 **PFServices.h** 以访问所有内置的 PlayFab 功能：

```cpp theme={null}
#include <playfab/services/PFServices.h>
```

### 初始化

PlayFab 初始化需要两个函数调用：**PFServicesInitialize** 和 **PFServiceConfigCreateHandle**。此初始化的结果是一个 **PFServiceConfigHandle**。你将此句柄提供给后续的登录调用，将调用指向 PlayFab 后端中正确的 title。

```cpp theme={null}
    HRESULT hr = PFServicesInitialize(nullptr); // Add your own error handling when FAILED(hr) == true

    PFServiceConfigHandle serviceConfigHandle{ nullptr };

    hr = PFServiceConfigCreateHandle(
            "https://ABCDEF.playfabapi.com",    // PlayFab API endpoint - obtained in the Game Manager
            "ABCDEF",                           // PlayFab Title id - obtained in the Game Manager
            &serviceConfigHandle);
```

### 登录

一旦你有了 **PFServiceConfigHandle**，就可以用它进行玩家登录调用。在 GDK 中，使用 **PFAuthenticationLoginWithXUserAsync**。此函数允许你使用 **XUserHandle** 将玩家登录到 PlayFab。要了解如何获取和管理 **XUserHandle**，请参阅 [用户身份与 XUser](/build/core-features/common/user/player-identity-xuser)。

进行登录调用后，可以使用 **XAsyncGetStatus** 检查调用状态。状态开始为 **E\_PENDING**，调用成功完成后变为 **S\_OK**。如果调用因某种原因失败，状态会反映该失败。所有 PlayFab Services 调用的错误处理方式都是这样。

与 **S\_OK** 结果一起，你会得到一个 **PFEntityHandle**。你使用此句柄以登录玩家的身份进行后续 PlayFab 调用。它包含以该玩家身份对 PlayFab 服务进行身份验证所需的任何材料。

```cpp theme={null}
    PFAuthenticationLoginWithXUserRequest request{};
    request.createAccount = true;
    request.user = userHandle; // An XUserHandle obtained from XUserAddAsync

    XAsyncBlock async{};
    HRESULT hr = PFAuthenticationLoginWithXUserAsync(serviceConfigHandle, &request, &async); // Add your own error handling when FAILED(hr) == true
    hr = XAsyncGetStatus(&async, true); // This is doing a blocking wait for completion, but you can use the XAsyncBlock to set a callback instead for async style usage

    std::vector<char> loginResultBuffer;
    PFAuthenticationLoginResult const* loginResult;
    size_t bufferSize;
    hr = PFAuthenticationLoginWithXUserGetResultSize(&async, &bufferSize);
    loginResultBuffer.resize(bufferSize);

    PFEntityHandle entityHandle{ nullptr };
    hr = PFAuthenticationLoginWithXUserGetResult(&async, &entityHandle, loginResultBuffer.size(), loginResultBuffer.data(), &loginResult, nullptr);
```

## 处理挂起和恢复

GDK 游戏可能被长时间挂起（例如，通过 Quick Resume）。如果实体令牌在挂起期间过期，SDK 会在恢复时检测到这一点并通知你的游戏。你应该在游戏生命周期的早期注册 **TokenExpiredHandler**，以便在需要时重新进行身份验证并重新连接服务。

有关完整详细信息，请参阅 [处理令牌过期](/services/playfab/sdks/c/relogin)。

## 服务调用

玩家登录后，你现在可以对 PlayFab 后端进行调用。以下是一个获取存储在 PlayFab 中当前玩家文件的调用示例。

### 获取 EntityKey

对于某些 PlayFab 调用来说，知道玩家的 **PFEntityKey** 会很有用。一旦你有了 **PFEntityToken**，就可以使用 **PFEntityGetEntityKey** 检索 **PFEntityKey**。

```cpp theme={null}
    PFEntityKey const* pEntityKey{};
    std::vector<char> entityKeyBuffer;
    size_t size{};
    HRESULT hr = PFEntityGetEntityKeySize(entityHandle, &size); // Add your own error handling when FAILED(hr) == true

    entityKeyBuffer.resize(size);
    hr = PFEntityGetEntityKey(entityHandle, entityKeyBuffer.size(), entityKeyBuffer.data(), &pEntityKey, nullptr);
```

### 调用 GetFiles

所有 PlayFab 调用都遵循类似的模式：准备请求对象、进行调用（使用登录得到的 **PFEntityHandle**）、创建接收响应的对象，然后调用 **GetResult** 函数以填充新创建的容器。

```cpp theme={null}
    XAsyncBlock async{};
    PFDataGetFilesRequest requestFiles{};
    requestFiles.entity = pEntityKey;

    HRESULT hr = PFDataGetFilesAsync(entityHandle, &requestFiles, &async); // Add your own error handling when FAILED(hr) == true
    hr = XAsyncGetStatus(&async, true); // This is doing a blocking wait for completion, but you can use the XAsyncBlock to set a callback instead for async style usage

    size_t resultSize;
    hr = PFDataGetFilesGetResultSize(&async, &resultSize);

    std::vector<char> getFilesResultBuffer(resultSize);
    PFDataGetFilesResponse* getFilesResponseResult{ nullptr };
    hr = PFDataGetFilesGetResult(&async, getFilesResultBuffer.size(), getFilesResultBuffer.data(), &getFilesResponseResult, nullptr);
```

## 清理

当你的游戏准备关闭或你出于其他原因需要清理 PlayFab 时，请确保关闭所有已打开的句柄并调用 **PFServicesUninitializeAsync**。

```cpp theme={null}
    PFEntityCloseHandle(entityHandle);
    entityHandle = nullptr;

    PFServiceConfigCloseHandle(serviceConfigHandle);
    serviceConfigHandle = nullptr;

    XAsyncBlock async{};
    HRESULT hr = PFServicesUninitializeAsync(&async); // Add your own error handling when FAILED(hr) == true
    hr = XAsyncGetStatus(&async, true); // This is doing a blocking wait for completion, but you can use the XAsyncBlock to set a callback instead for async style usage
```

## 异步 API 模式

适用于 GDK 的 PlayFab Services SDK 遵循 GDK 中实现的[异步编程模型](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/system/overviews/async-programming-model)。此编程模型涉及使用由 [XAsync 库](/build/core-features/common/async/async-libraries/async-library-xasync)提供的任务和任务队列。此模型与其他 GDK 函数和扩展（如 XBOX Services API）保持一致。虽然它引入了一些复杂性，但也带来了对异步操作的高度控制。

以下示例展示了如何对 **PFDataGetFilesAsync** 进行异步调用。

```cpp theme={null}
    auto async = std::make_unique<XAsyncBlock>();
    async->callback = [](XAsyncBlock* async)
    {
        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // take ownership of XAsyncBlock

        size_t resultSize;
        HRESULT hr = PFDataGetFilesGetResultSize(async, &resultSize);
        if (SUCCEEDED(hr))
        {
            std::vector<char> getFilesResultBuffer(resultSize);
            PFDataGetFilesResponse* getFilesResponseResult{ nullptr };
            PFDataGetFilesGetResult(async, getFilesResultBuffer.size(), getFilesResultBuffer.data(), &getFilesResponseResult, nullptr);
        }
    };

    PFDataGetFilesRequest requestFiles{};
    requestFiles.entity = m_pEntityKey;
    HRESULT hr = PFDataGetFilesAsync(m_entityHandle, &requestFiles, async.get());
    if (SUCCEEDED(hr))
    {
        async.release(); // at this point, the callback will be called so release the unique ptr
    }

```

## 错误处理

已完成的 **XAsync** 操作返回 HTTP 状态代码。错误状态代码在调用 **XAsyncGetStatus()** 或某个 **PF\*Get()** API 时表现为失败的 **HRESULT**，例如 **HTTP\_E\_STATUS\_NOT\_FOUND**。

要查看服务返回的详细错误消息，请参阅下一节关于调试的内容。这些详细的错误消息在开发期间可用于更好地理解 PlayFab 服务对客户端请求的反应。

## 调试

查看结果并调试 PlayFab Services SDK 中任何调用的最简单方法是启用 [调试跟踪](/services/playfab/sdks/c/tracing)。启用调试跟踪后，你既可以在调试器输出窗口中看到结果，也可以将结果挂接到自己游戏的日志中。

## 参考

[API 参考文档](/services/playfab/api-references/c/pfauthentication/pfauthentication_members)
