> ## 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 UI 回呼

> 註冊回呼、處理狀態機，並針對衝突和重試呼叫回應 API，以實作 PlayFab Game Saves 的自訂同步 UI。

Game Saves 提供一組 UI 回呼，讓您的遊戲能夠回應同步作業期間的事件。在 XBOX 和 Windows 上，平台會為這些事件提供內建 UI。在其他平台上 (例如 Steam Deck)，您的遊戲必須透過處理這些回呼來實作自己的 UI。

在 XBOX 和 Windows 上設定回呼，會以您的實作覆寫平台提供的 UI。如果您的遊戲需要在所有平台上提供一致的玩家體驗，這會很有用。在所有平台上註冊相同的回呼，內建 UI 就不會出現。

## 狀態機的運作方式

Game Saves 使用內部狀態機來協調 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()` 偵測此狀態。 |

如需離線模式行為的詳細資訊，請參閱 [Game Saves 離線模式](/zh-TW/services/playfab/player-progression/game-saves/offline)。

### 作用中裝置爭用

在 `PFGameSaveFilesAddUserWithUiAsync` 期間，當另一部裝置已是此使用者的作用中裝置時觸發。回呼會接收本機和遠端存檔資料的 `PFGameSaveDescriptor` 結構，其中包含裝置名稱、時間戳記和存檔大小，您可以顯示這些資訊以協助使用者做出決定。

**回呼**：`PFGameSaveFilesUiActiveDeviceContentionCallback`

**回應 API**：`PFGameSaveFilesSetUiActiveDeviceContentionResponse`

| 動作 | 效果 |
| - | - |
| `Cancel` | 取消作業。`XAsyncBlock` 回呼會以 `E_PF_GAMESAVE_USER_CANCELLED` 觸發。 |
| `Retry` | 重試——如果使用者預期另一部裝置很快就會釋放，這會很有用。如果另一部裝置仍處於作用中，此回呼會再次觸發。 |
| `SyncLastSavedData` | 將本機裝置設為作用中並進行同步。遠端裝置將無法再上傳，並會收到作用中裝置變更通知。 |

如需作用中裝置行為的詳細資訊，請參閱 [Game Saves 作用中裝置變更](/zh-TW/services/playfab/player-progression/game-saves/activedevicechanges)。

### 衝突

在 `PFGameSaveFilesAddUserWithUiAsync` 期間，當本機和雲端存檔資料出現分歧時觸發。回呼會接收本機和遠端存檔資料的 `PFGameSaveDescriptor` 結構。

**回呼**：`PFGameSaveFilesUiConflictCallback`

**回應 API**：`PFGameSaveFilesSetUiConflictResponse`

| 動作 | 效果 |
| - | - |
| `Cancel` | 取消作業。`XAsyncBlock` 回呼會以 `E_PF_GAMESAVE_USER_CANCELLED` 觸發。 |
| `TakeLocal` | 保留本機存檔資料並上傳至雲端。 |
| `TakeRemote` | 捨棄本機變更並下載雲端存檔資料。 |

<Info>
  衝突解決會套用至整個存檔，而不是個別檔案或資料夾。如需了解如何在不可部分完成的單位層級偵測衝突並進行全域解決，請參閱 [Game Saves 衝突](/zh-TW/services/playfab/player-progression/game-saves/conflicts)。
</Info>

### 儲存空間不足

在 `PFGameSaveFilesAddUserWithUiAsync` 期間，當本機裝置沒有足夠的磁碟空間從雲端下載存檔資料時觸發。回呼會接收 `requiredBytes`，指出所需的空間大小。

**回呼**：`PFGameSaveFilesUiOutOfStorageCallback`

**回應 API**：`PFGameSaveFilesSetUiOutOfStorageResponse`

| 動作 | 效果 |
| - | - |
| `Cancel` | 取消作業。`XAsyncBlock` 回呼會以 `E_PF_GAMESAVE_USER_CANCELLED` 觸發。 |
| `Retry` | 在使用者釋放本機儲存空間之後重試。如果空間仍然不足，此回呼會再次觸發。 |

## 處理程序內與處理程序外 (系統 UI)

Game Saves 的執行位置取決於平台，這會影響 UI 事件的處理方式：

* **處理程序外 (XBOX 和 Windows)**：在 XBOX 和 Windows 上，Game Saves 一律以處理程序外方式執行。平台 (Connected Storage / GRTS) 會執行同步，並針對同步失敗、衝突、作用中裝置爭用和儲存空間不足提供內建的系統 UI 對話方塊。玩家直接與這些對話方塊互動，平台會將結果轉譯回您的遊戲在處理程序內收到的相同非同步完成碼。您仍可註冊回呼來取代內建 UI。
* **處理程序內 (其他平台，例如 Steam Deck)**：在無法使用平台服務的情況下，您的遊戲會裝載 Game Saves 同步引擎，並透過上述回呼處理 UI 事件。您的遊戲會使用回應 API 完全驅動狀態機。

### 取消一律是可能的結果

無論採用哪種路徑，**每個** UI 流程都可能以使用者退出且未成功同步作為結束，因此您的遊戲必須一律處理最終的取消：

| 使用者意圖 | 非同步完成 | `IsConnectedToCloud()` | 存檔資料夾？ |
| - | - | - | - |
| 繼續線上 (成功) | `S_OK` | `true` | 是 |
| 離線遊玩 | `S_OK` | `false` | 是 |
| 取消 / 結束 (玩家) | `E_PF_GAMESAVE_USER_CANCELLED` (`0x800704C7`) | 不適用 | **否** |
| 取消 (遊戲呼叫了 `XAsyncCancel`) | `E_ABORT` (`0x80004004`) | 不適用 | **否** |

唯一仍允許玩家繼續的「退出」動作是同步失敗提示中的 **Use Offline** (成功的結果)。其他所有 Cancel 都是最終結果，且不會留下存檔資料夾。請將其視為*不允許遊玩*。請參閱 [Game Saves 離線模式](/zh-TW/services/playfab/player-progression/game-saves/offline#when-game-saves-enters-offline-mode-or-returns-an-error)。

在內建 (處理程序外) 系統 UI 中，這些選項會以平台的用語顯示。例如，同步失敗對話方塊提供 **"Try again"** / **"Play offline"**，而爭用對話方塊提供 **"Stop sync & continue"** / **"Quit game"**。"Play offline" 對應至離線模式 (`S_OK`，未連線)；"Quit game" 對應至 `E_PF_GAMESAVE_USER_CANCELLED`。

在兩種路徑上，取消**衝突**提示都是最終結果。它會以 `E_PF_GAMESAVE_USER_CANCELLED` 完成，且不會連帶出現同步失敗提示。

若要使用自訂的跨平台 UI (例如，與您的 Steam Deck 實作一致)，請在所有平台上註冊回呼，並在目標硬體上驗證處理程序外流程。無論採用哪種路徑，都請依完成結果決定是否允許遊玩：`S_OK` + 已連線 → 線上遊玩；`S_OK` + 未連線 → 離線遊玩 (警告玩家)；取消/失敗且沒有資料夾 → 封鎖遊玩。

## 平台需求

| 平台 | UI 回呼 |
| - | - |
| **XBOX 和 Windows** | 選用。設定回呼以覆寫內建 UI。 |
| **其他平台** (例如 Steam Deck) | **必要**。沒有可用的內建 UI；您的遊戲必須處理所有回呼。 |

如需 Steam Deck 實作的詳細資訊，請參閱 [Steam Deck 實作指南](/zh-TW/services/playfab/player-progression/game-saves/steam-deck-implementation)。

## 相關內容

* [Game Saves 快速入門](/zh-TW/services/playfab/player-progression/game-saves/quickstart)
* [Game Saves 離線模式](/zh-TW/services/playfab/player-progression/game-saves/offline)
* [Game Saves 衝突](/zh-TW/services/playfab/player-progression/game-saves/conflicts)
* [Game Saves 作用中裝置變更](/zh-TW/services/playfab/player-progression/game-saves/activedevicechanges)


## Related topics

- [Game Saves 快速入門](/zh-TW/services/playfab/player-progression/game-saves/quickstart.md)
- [Game Saves 錯誤處理常見問題集](/zh-TW/services/playfab/player-progression/game-saves/error-handling-faq.md)
- [PlayFab Game Saves 的 Steam Deck 實作指南](/zh-TW/services/playfab/player-progression/game-saves/steam-deck-implementation.md)
- [Game Saves 離線模式](/zh-TW/services/playfab/player-progression/game-saves/offline.md)
- [PFGameSaveFilesSetUiCallbacks](/zh-TW/services/playfab/api-references/c/pfgamesavefilesui/functions/pfgamesavefilessetuicallbacks.md)
