> ## 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.

# 游戏存档演练与示例

> 游戏存档演练与示例

本文提供了在使用游戏存档（Game Saves）时常见开发与迁移场景的分步指南。内容涵盖 Microsoft Partner Center 中的关键设置、安全写入数据的最佳实践、平台特定的存档管理，以及推荐的测试流程。

## Partner Center 配置

### 为你的游戏启用 XBOX 服务与游戏存档

若要使用游戏存档 API，请在 Partner Center 中完成以下步骤。

* 启用 XBOX 服务。
  1. 登录 [Partner Center](https://partner.microsoft.com/dashboard/home)。
  2. 前往你的游戏，然后在设置中启用 XBOX 服务。有关此步骤的更多信息，请参阅 [Setting up an app or game at Partner Center, for Managed Partners](/services/xbox-services/fundamentals/portal-config/live-setup-partner-center-partners#2-contact-your-microsoft-representative-to-enable-your-app-or-game)。
* 获取服务配置标识符（SCID）。所有读写操作都必须与 SCID 关联。SCID 同时也用于游戏存档的初始化。
  * 在 Partner Center 中，可在游戏的 **XBOX services** > **XBOX settings** 选项卡下找到 SCID。你也可以在此页面上找到 Microsoft 帐户（MSA）App ID（MSAAppID）。
    <img src="https://mintcdn.com/microsoft-4404708b/UZTRJSf0emX1fheE/images/gdk/features/common/partner-center-xbox-services-view.png?fit=max&auto=format&n=UZTRJSf0emX1fheE&q=85&s=7ba30f0150039b4e968e6915ad0eb4dd" alt="Partner Center XBOX services view." width="622" height="293" data-path="images/gdk/features/common/partner-center-xbox-services-view.png" />

获取 SCID 和 MSAAppID 后，请将此 App ID 添加到游戏的配置（.mgc）文件中。

有关游戏配置文件的更多信息，请参阅 [Creating the Microsoft Game Config .mgc](/build/core-features/common/game-config/MicrosoftGameConfig-Overview)。

## 开发场景

### 应该在代码中的什么位置集成游戏存档？

游戏存档逻辑依赖于用户登录。请将游戏存档代码添加到用户登录流程附近。

### 如何确保游戏存档数据不会损坏？

要安全地保存数据并避免损坏，请遵循以下步骤。此指南适用于所有保存操作。

1. 先写入临时文件。
   * 将存档数据序列化到一个新文件中（例如 `save.tmp`），而不是直接覆盖当前存档。此步骤可在写入过程被中断时保护现有存档。
2. 在写入完全提交到磁盘后再关闭写入句柄。
3. 使用 Win32 [ReplaceFile](https://learn.microsoft.com/windows/win32/api/winbase/nf-winbase-replacefilea) 以原子方式将旧存档文件替换为新的临时文件。

### 如何支持离线设备？

你需要负责决定游戏在初始化游戏存档前后发生连接断开时的行为。

有关离线行为的更多信息，请参阅 [Understanding the Game Saves sync flow](/build/core-features/common/game-save/game-saves-syncing#connection-check)。

### 需要注意哪些用户交互？

当某个操作需要用户输入时，操作系统会显示系统提示。有关这些提示的信息，请参阅 [Game Saves dialogs](/build/core-features/common/game-save/game-saves-dialogues)。

### 有没有仅将数据保存到本地设备的方法？

如果你在游戏存档初始化过程中传入 `null` 用户句柄，系统会创建一个仅限本机的提供程序（machine-only provider）。数据将存储在本地并保留在设备上，最大限制为 256 MB。数据不会同步到云端。

有关游戏存档存储的更多信息，请参阅 [Game Saves storage systems](/build/core-features/common/game-save/game-saves-storage-systems)。

### 通过设备管理游戏存档

#### 使用文件资源管理器在 PC 上访问本地游戏存档

如果你的游戏运行在 PC 上，你可以直接访问这些文件。根据所使用的游戏存档 API，可在以下位置访问本地游戏存档。

| 游戏存档 API       | 文件路径                                                                          |
| :------------- | :---------------------------------------------------------------------------- |
| XGameSaveFiles | `%AppData%\Local\Packages\<PACKAGE_NAME>\SystemAppData\xgs\<HexXuid>_<Scid>\` |
| XGameSave      | `%AppData%\Local\Packages\<PACKAGE_NAME>\SystemAppData\wgs\<HexXuid>_<Scid>\` |

当你在 PC 上操作数据时，同步逻辑仍然有效。例如，在游戏未持有锁的情况下修改数据会导致冲突。

#### 在主机上访问本地游戏存档

通过 XBOX UI 管理主机存档数据。使用以下步骤进行访问。

1. 按 XBOX 控制器上的 **主页（Home）** 按钮。
2. 选择 **我的游戏和应用（My games & apps）** > **查看全部（See all）**。
3. 将光标悬停在你的游戏上，然后按 **查看（View）** 按钮。
4. 选择 **保存的数据（Saved data）**。

<img src="https://mintcdn.com/microsoft-4404708b/sIrPFR_ir_sNKVEv/images/gdk/features/common/console-storage-management.png?fit=max&auto=format&n=sIrPFR_ir_sNKVEv&q=85&s=1440050534d3c4d168d1e964d3638afe" alt="Console storage Game Saves management view." width="1314" height="377" data-path="images/gdk/features/common/console-storage-management.png" />

在主机上直接操作数据时，请注意以下事项。

* 通过系统 UI 在主机上删除数据不会移除云端存储的副本。当你再次启动游戏时，它会从云端同步这些数据。
* 机器提供程序（machine-provider）数据显示为一个没有名字的用户。此数据保留在设备上，不会同步到云端，并且绑定到该设备。

有关机器提供程序的更多信息，请参阅 [Game Saves storage systems](/build/core-features/common/game-save/game-saves-storage-systems#game-saves-storage-systems)。

如需更精细地控制游戏存档，请使用 [Game Saves tools](/build/core-features/common/game-save/game-saves-tools#manipulating-game-saves)。

## 测试场景

在创建测试用例时，请将数据验证与游戏存档逻辑分离。

### 测试游戏存档能否正确地在云端进行同步

使用以下步骤测试同步是否正确。测试流程将验证相关行为。

`XGameSaveFiles`：

1. 确认 SCID 是否正确。
2. 确认你使用的是正确的用户句柄。
3. 确认游戏在当前游戏会话期间调用了 `XGameSaveFilesGetFolderWithUIAsync`。如果游戏从挂起状态恢复，请再次调用该函数。
   1. 使用 Fiddler 确认锁已被获取。
   2. 保存此路径，稍后用它来确认数据是否已上传。
4. 向 `XGameSaveFilesGetFolderWithUIAsync` 提供的文件路径写入一些数据。
5. 终止或挂起游戏。
6. 等待 10–30 秒，让操作系统自动将数据上传到云端并释放锁。
   1. 使用 Fiddler 确认数据已上传且锁已释放。
7. 手动删除 `XGameSaveFilesGetFolderWithUIAsync` 提供的文件夹中的数据。
   1. 在主机上，可通过玩家设置访问此数据。
8. 再次启动游戏，然后尝试让用户登录。
9. 将出现同步对话框，显示正在从云端进行下载同步。

为帮助测试同步是否成功，请参阅以下资源：

* [Game Saves tools to inspect traffic and manipulate saves](/build/core-features/common/game-save/game-saves-tools)
* [Understanding the Game Saves sync flow](/build/core-features/common/game-save/game-saves-syncing)

### 测试游戏存档能否正确漫游

关于确认数据能否漫游的测试计划，请参阅 [XR-052-06 Test Plan](https://learn.microsoft.com/build/store/policies/XR/XR052#052-06-cloud-storage-roaming)。

## 迁移场景

### 在多款游戏之间共享游戏存档

若要在一款游戏与另一款游戏之间传输或访问数据，需要完成两个步骤。

1. 在 Partner Center 中修改你想访问的游戏的访问策略。
2. 在源代码中为两款游戏初始化游戏存档提供程序。

#### 修改访问策略

游戏通过配置访问策略来控制哪些游戏可以访问它的游戏存档数据。

1. 前往 [Partner Center](https://partner.microsoft.com/dashboard)。
2. 选择 **Apps and games** > **\<your title>** > **Gameplay settings**。
3. 在 **Gameplay Settings** 中，选择 **Access Policies**，然后展开 **Connected Storage**。
4. 选择 **Add app/service**，然后添加你希望授予访问权限的游戏。
5. 添加完游戏后，选择 **Save**，然后选择 **Publish**。更改将在一小时内生效。

以下屏幕截图展示了一个示例，将 GameSaveFilesCombo 游戏对 GameSaveSample 游戏设置为完全可访问。

<img src="https://mintcdn.com/microsoft-4404708b/UZTRJSf0emX1fheE/images/gdk/features/common/partner-center-access-policy.png?fit=max&auto=format&n=UZTRJSf0emX1fheE&q=85&s=25eae43c7e7d88b824558596d849cbfa" alt="Partner Center view for modifying a title's access policy." width="1280" height="598" data-path="images/gdk/features/common/partner-center-access-policy.png" />

#### 初始化游戏存档提供程序

现在你已经获得了访问第一款游戏的权限，可以从另一款游戏中读取其 `XGameSave` 数据。

* 如果你使用 `XGameSave`，请为每款游戏调用 `XGameSaveInitializeProvider` 或 `XGameSaveInitializeProviderAsync`。
* 如果你使用 `XGameSaveFiles`，提供程序会隐式初始化。请为每款游戏调用 `XGameSaveFilesGetFolderWithUiAsync`。

### XGameSave 与 XGameSaveFiles 之间的互操作

某款游戏可能需要将 `XGameSave` 与 `XGameSaveFiles` 结合使用。典型原因可能包括：

* 发行商在主机上已有使用 `XGameSave` 的现有游戏。
* 发行商不希望将该现有游戏更新为使用 `XGameSaveFiles`。
* 发行商认为在 PC 游戏中添加 `XGameSaveFiles` 比使用 `XGameSave` 更简单，但仍希望支持 PC、主机和 XBOX 游戏串流之间的跨存档。

在 `XGameSave` 和 `XGameSaveFiles` 之间切换相对简单。当游戏调用 [XGameSaveFilesGetFolderWithUiAsync](/reference/system/xgamesavefiles/functions/xgamesavefilesgetfolderwithuiasync) 时，会按以下规则将容器和 blob 映射到目录和文件：

* 容器名中的任何正斜杠（/）都会创建文件所在的目录结构。
* 以下字符对 `XGameSaveFiles` 无效。如果系统遇到这些字符，会将其映射为下划线（\_）：
  * 从 \0 到 \001f（含）之间的字符。
* 以下字符对 `XGameSaveFiles` 无效。如果系统遇到这些字符，会将其映射为句点（.）：
  * 引号（"）
  * 小于号（\<）
  * 大于号（>）
  * 竖线（|）
  * 星号（\*）
  * 问号（?）
  * 反斜杠（\）
* blob 名称中的斜杠（/）会映射为文件名中的句点（.）。
* 单个文件的大小限制为 16 MB。`XGameSave` 支持的最大上传大小为 16 MB。

当游戏从 `XGameSaveFiles` 切换回 `XGameSave` 时，如果文件名保持不变或未被移动，则会恢复原始的容器和 blob 名称。

### 使用无代码云存档将旧游戏移植到 PC 游戏存档

一些移植到 PC Game Pass 的游戏可能需要无代码云存档解决方案。这种需求可能出现在以下场景中：

* 游戏以 x86 应用程序运行。它仅以打包形式使用 Microsoft Game Development Kit（GDK）。
* 游戏在创建时未使用自定义代码，例如使用 Unreal Engine 中的 Blueprint 或 Unity 中的 Bolt 等工具。

使用无代码云存档的游戏通过标准的 Win32 文件 I/O API 对其指定的存档目录进行读写。系统会自动同步数据。你无需编写特殊代码来处理同步和上传。同步会在游戏启动之前完成。

无代码云存档会在游戏在 PC 上不再运行时上传。上传发生在满足以下任一条件时：

* 游戏被终止。
* 被跟踪的用户注销。
* PC 电源状态发生变化。
* 自游戏最后一次向指定存档区域写入以来已经过了 30 分钟。

无代码云存档解决方案构建在 `XGameSaveFiles` 之上，并共享其在文件大小和单用户存储限制方面的所有限制。单个文件限制为 64 MB（如果需要与 `XGameSave` 或 Connected Storage 进行互操作，则限制为 16 MB）。默认情况下，单用户存储限制为 256 MB。需要更大的单用户存储限制的游戏，可以与其开发者合作伙伴经理（DPM）联系以申请例外。

<Note>
  目录和文件名有特定的命名规则和字符限制。有关更多信息，请参阅 [XGameSaveFiles path logic](/build/core-features/common/game-save/xgamesavefiles#xgamesavefiles-path-logic)。
</Note>

无代码云存档仅在 PC 上受支持。游戏需要使用 [Simplified User Model](/build/core-features/common/user/users-opting-into-simplified-model)。它可确保用户在游戏启动前已登录。如果无法让用户登录该游戏，则游戏不会启动。如果用户在游戏过程中被注销，游戏将被终止。

<Info>
  无代码云存档要求游戏以使用 `wdapp install` 部署的打包版本方式启动。直接启动 `.exe` 不会激活云存档重定向。

  当运行打包版本时，通过 `NoCodePCRoot` 写入的存档会被重定向到由 `XGameSaveFiles` 管理的存储。之后如果直接启动 `.exe`，则会读取物理的 `NoCodePCRoot` 文件夹，该文件夹可能为空，导致存档看起来丢失。为避免此问题，请始终使用 `wdapp install` 部署的打包版本来测试无代码云存档。
</Info>

### 启用无代码云存档

若要启用无代码云存档，请完成以下步骤：

1. 修改你的 `MicrosoftGame.config` 文件。
2. 启用简化用户模型（simplified user model）。
3. 指定存档文件的根文件夹。
4. 提供游戏对应的 SCID。

以下代码示例展示了此过程。

```xml theme={null}
<Game configVersion="1">
   <Identity Name="SampleNameOne" Publisher="CN=NoPublisher"/>
   <SaveGameStorage>
      <NoCodePCRoot RelativeTo="SavedGames">test\path</NoCodePCRoot>
      <SCID>DF9D8061-4790-4B84-86B4-CD060B00B4DD</SCID>
      <MaxUserQuota>256</MaxUserQuota>
   </SaveGameStorage>
   <!-- Content removed for brevity -->
   
   <!-- Must also opt into requiring a default user at launch -->
   <AdvancedUserModel>false</AdvancedUserModel>
</Game>
```

你为 `NoCodePCRoot` 指定的根文件夹必须相对于以下一小组可选项之一。

| RelativeTo        | PC 上的文件夹位置                         |
| ----------------- | ---------------------------------- |
| `AppData`         | 映射到环境变量 %APPDATA%                  |
| `Public`          | 映射到环境变量 %PUBLIC%                   |
| `LocalAppData`    | 映射到环境变量 %LOCALAPPDATA%             |
| `LocalAppDataLow` | 映射到 %USERPROFILE%\AppData\LocalLow |
| `ProgramData`     | 映射到环境变量 %PROGAMDATA%               |
| `SavedGames`      | 映射到 %USERPROFILE%\Saved Games      |
| `UserProfile`     | 映射到环境变量 %USERPROFILE%              |

<Info>
  请使用 `SavedGames` 作为 `RelativeTo` 的值。Saved Games 文件夹（`%USERPROFILE%\Saved Games`）对应 Windows 已知文件夹 ID `FOLDERID_SavedGames`。OneDrive 默认不会同步该文件夹。

  避免使用其他位置，例如 `AppData`（`%APPDATA%`）。OneDrive 可能会同步这些位置，从而与云存档同步产生冲突。

  有关 `FOLDERID_SavedGames` 的更多信息，请参阅 [SHGetKnownFolderPath](https://learn.microsoft.com/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath)。
</Info>

*不能将文件直接放置在根目录中*。请将它们至少嵌套在根文件夹下的一个子文件夹中。例如，直接使用文件名（如 `<NoCodePCRoot RelativeTo="SavedGames">savegame1.sav</NoCodePCRoot>`）是无效的，因为 savegame1.sav 会被忽略。`<NoCodePCRoot>` 用于定义目录路径，而不是具体的文件。

## 代码示例

* [GameSaveCombo](https://learn.microsoft.com/samples/microsoft/xbox-gdk-samples/gamesavecombo/)
* [GameSaveFilesCombo](https://learn.microsoft.com/samples/microsoft/xbox-gdk-samples/gamesavefilescombo/)

## 参考 API 文档

* [XGameSaveFiles (API contents)](/reference/system/xgamesavefiles/xgamesavefiles_members)
  * Functions
    * [XGameSaveFilesGetFolderWithUiAsync](/reference/system/xgamesavefiles/functions/xgamesavefilesgetfolderwithuiasync)

## 另请参阅

[Game Saves TOC](/build/core-features/common/game-save/game-saves-toc)
