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

# 游戏存档 UI 回调

> 通过注册回调、处理状态机以及为冲突和重试调用响应 API，为 PlayFab 游戏存档实现自定义同步 UI。

游戏存档提供了一组 UI 回调，让您的游戏可以响应同步操作期间的事件。在 XBOX 和 Windows 上，平台为这些事件提供了内置 UI。在其他平台（例如 Steam Deck）上，您的游戏必须通过处理这些回调来实现自己的 UI。

在 XBOX 和 Windows 上设置回调会用您的实现覆盖平台提供的 UI。如果您的游戏需要在所有平台上为玩家提供一致的体验，这将非常有用——在所有平台上注册相同的回调，内置 UI 就不会出现。

## 状态机的工作原理

游戏存档使用内部状态机来协调 UI 回调与异步操作生命周期。当 UI 回调触发时，异步操作会暂停——在回调被解决之前，`XAsyncBlock` 回调不会触发。在游戏调用相应的响应 API 或异步操作被取消之前，状态机不会前进。

这意味着：

* 每个回调类型都有一个相应的响应 API。调用响应 API 来告诉系统下一步做什么。
* 响应 API 可以在回调函数内部或外部调用。
* 如果响应操作是 `Retry`，操作会重试，并可能再次触发相同的回调。
* 只有当操作达到终止状态——成功、取消或离线回退——时，`XAsyncBlock` 回调才会触发。

例如，如果上传由于速率限制而失败：

1. `PFGameSaveFilesUiSyncFailedCallback` 触发并携带错误。
2. `XAsyncBlock` 回调尚未触发——状态机等待响应。
3. 如果用户选择 `Retry` 并且重试也失败，同步失败回调会再次触发。
4. 如果用户选择 `Cancel`，`XAsyncBlock` 回调将触发并携带 `E_PF_GAMESAVE_USER_CANCELLED`。
5. 如果重试成功，`XAsyncBlock` 回调将触发并携带 `S_OK`。

## 回调何时触发

UI 回调仅在两个异步操作期间触发：

| 操作                                  | 可能触发的回调                  |
| ----------------------------------- | ------------------------ |
| `PFGameSaveFilesAddUserWithUiAsync` | 进度、同步失败、活动设备争用、冲突、存储空间不足 |
| `PFGameSaveFilesUploadWithUiAsync`  | 进度、同步失败                  |

## 注册回调

在调用 `PFGameSaveFilesAddUserWithUiAsync` 或 `PFGameSaveFilesUploadWithUiAsync` 之前注册所有回调：

```cpp theme={null}
PFGameSaveUICallbacks callbacks{};
callbacks.progressCallback = MyProgressCallback;
callbacks.progressContext = nullptr;
callbacks.syncFailedCallback = MySyncFailedCallback;
callbacks.syncFailedContext = nullptr;
callbacks.activeDeviceContentionCallback = MyActiveDeviceContentionCallback;
callbacks.activeDeviceContentionContext = nullptr;
callbacks.conflictCallback = MyConflictCallback;
callbacks.conflictContext = nullptr;
callbacks.outOfStorageCallback = MyOutOfStorageCallback;
callbacks.outOfStorageContext = nullptr;

HRESULT hr = PFGameSaveFilesSetUiCallbacks(&callbacks);
```

## 回调参考

### 进度

报告上传或下载进度。在回调内使用 `PFGameSaveFilesUiProgressGetProgress` 检索当前的 `PFGameSaveFilesSyncState`、已完成的字节数和总字节数。

**回调**：`PFGameSaveFilesUiProgressCallback`

**响应 API**：`PFGameSaveFilesSetUiProgressResponse`

| 操作       | 效果                                                         |
| -------- | ---------------------------------------------------------- |
| `Cancel` | 取消操作。`XAsyncBlock` 回调触发并携带 `E_PF_GAMESAVE_USER_CANCELLED`。 |

<Note>
  进度回调不需要响应即可继续——操作会自行继续进行。仅在用户想要取消时才调用响应 API。
</Note>

#### 同步状态

`PFGameSaveFilesSyncState` 枚举指示操作处于哪个阶段：

| 状态                     | 描述               | 可安全写入存档文件夹？ |
| ---------------------- | ---------------- | ----------- |
| `NotStarted`           | 操作尚未开始           | 是           |
| `PreparingForDownload` | 准备从云端下载          | 是           |
| `Downloading`          | 正在从云端下载          | 否           |
| `PreparingForUpload`   | 正在读取和压缩本地文件      | 否           |
| `Uploading`            | 正在向云端上传（本地文件已捕获） | 是           |
| `SyncComplete`         | 操作已完成            | 是           |

### 同步失败

当同步操作失败时触发，例如由于网络问题或速率限制。

**回调**：`PFGameSaveFilesUiSyncFailedCallback`

**参数**：接收 `PFGameSaveFilesSyncState`（失败的阶段）和 `HRESULT`（错误代码）。

**响应 API**：`PFGameSaveFilesSetUiSyncFailedResponse`

| 操作           | 效果                                                                                                                                 |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| `Cancel`     | 取消操作。`XAsyncBlock` 回调触发并携带 `E_PF_GAMESAVE_USER_CANCELLED`。                                                                         |
| `Retry`      | 重试失败的操作。如果重试失败，此回调会再次触发。                                                                                                           |
| `UseOffline` | 仅在 `PFGameSaveFilesAddUserWithUiAsync` 期间有效。`XAsyncBlock` 回调触发并携带 `S_OK`，但系统进入离线模式。使用 `PFGameSaveFilesIsConnectedToCloud()` 检测此状态。 |

有关离线模式行为的更多详细信息，请参阅[游戏存档离线模式](/services/playfab/player-progression/game-saves/offline)。

### 活动设备争用

在 `PFGameSaveFilesAddUserWithUiAsync` 期间，当另一台设备已经是该用户的活动设备时触发。回调接收本地和远程存档数据的 `PFGameSaveDescriptor` 结构，其中包括可以显示以帮助用户做出决定的设备名称、时间戳和存档大小。

**回调**：`PFGameSaveFilesUiActiveDeviceContentionCallback`

**响应 API**：`PFGameSaveFilesSetUiActiveDeviceContentionResponse`

| 操作                  | 效果                                                         |
| ------------------- | ---------------------------------------------------------- |
| `Cancel`            | 取消操作。`XAsyncBlock` 回调触发并携带 `E_PF_GAMESAVE_USER_CANCELLED`。 |
| `Retry`             | 重试——如果用户预期另一台设备很快会释放，则很有用。如果另一台设备仍处于活动状态，此回调会再次触发。         |
| `SyncLastSavedData` | 将本地设备设为活动状态并同步。远程设备不能再上传，并会收到活动设备已更改的通知。                   |

有关活动设备行为的更多详细信息，请参阅[游戏存档活动设备变更](/services/playfab/player-progression/game-saves/activedevicechanges)。

### 冲突

在 `PFGameSaveFilesAddUserWithUiAsync` 期间，当本地和云端存档数据发生分歧时触发。回调接收本地和远程存档数据的 `PFGameSaveDescriptor` 结构。

**回调**：`PFGameSaveFilesUiConflictCallback`

**响应 API**：`PFGameSaveFilesSetUiConflictResponse`

| 操作           | 效果                                                         |
| ------------ | ---------------------------------------------------------- |
| `Cancel`     | 取消操作。`XAsyncBlock` 回调触发并携带 `E_PF_GAMESAVE_USER_CANCELLED`。 |
| `TakeLocal`  | 保留本地存档数据并上传到云端。                                            |
| `TakeRemote` | 丢弃本地更改并下载云端存档数据。                                           |

<Info>
  冲突解决适用于整个存档，而非单个文件或文件夹。有关如何在原子单元级别检测冲突并在全局范围内解决的详细信息，请参阅[游戏存档冲突](/services/playfab/player-progression/game-saves/conflicts)。
</Info>

### 存储空间不足

在 `PFGameSaveFilesAddUserWithUiAsync` 期间，当本地设备没有足够的磁盘空间从云端下载存档数据时触发。回调接收 `requiredBytes`，指示所需的空间量。

**回调**：`PFGameSaveFilesUiOutOfStorageCallback`

**响应 API**：`PFGameSaveFilesSetUiOutOfStorageResponse`

| 操作       | 效果                                                         |
| -------- | ---------------------------------------------------------- |
| `Cancel` | 取消操作。`XAsyncBlock` 回调触发并携带 `E_PF_GAMESAVE_USER_CANCELLED`。 |
| `Retry`  | 在用户释放本地存储空间后重试。如果空间仍然不足，此回调会再次触发。                          |

## 平台要求

| 平台                     | UI 回调                           |
| ---------------------- | ------------------------------- |
| **XBOX 和 Windows**     | 可选。设置回调可覆盖内置 UI。                |
| **其他平台**（Steam Deck 等） | **必需**。没有可用的内置 UI；您的游戏必须处理所有回调。 |

有关 Steam Deck 实现的详细信息，请参阅 [Steam Deck 实现指南](/services/playfab/player-progression/game-saves/steam-deck-implementation)。

## 相关内容

* [游戏存档快速入门](/services/playfab/player-progression/game-saves/quickstart)
* [游戏存档离线模式](/services/playfab/player-progression/game-saves/offline)
* [游戏存档冲突](/services/playfab/player-progression/game-saves/conflicts)
* [游戏存档活动设备变更](/services/playfab/player-progression/game-saves/activedevicechanges)


## Related topics

- [游戏存档快速入门](/zh-CN/services/playfab/player-progression/game-saves/quickstart.md)
- [PlayFab 游戏存档 Steam Deck 实现指南](/zh-CN/services/playfab/player-progression/game-saves/steam-deck-implementation.md)
- [游戏存档概述](/zh-CN/services/playfab/player-progression/game-saves/overview.md)
- [游戏存档回滚](/zh-CN/services/playfab/player-progression/game-saves/rollback.md)
- [游戏存档](/zh-CN/build/core-features/common/game-save/index.md)
