> ## 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 コールバックは、次の 2 つの非同期操作中にのみ発生します:

| 操作                                  | トリガーされる可能性のあるコールバック               |
| ----------------------------------- | --------------------------------- |
| `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 オフラインモード](/services/playfab/player-progression/game-saves/offline) を参照してください。

### アクティブデバイスの競合

別のデバイスがこのユーザーの既にアクティブデバイスになっている場合、`PFGameSaveFilesAddUserWithUiAsync` 中に発生します。コールバックは、ローカルとリモート両方の保存データの `PFGameSaveDescriptor` 構造体を受け取ります。これには、ユーザーが決定するのに役立つように表示できるデバイス名、タイムスタンプ、保存サイズが含まれます。

**コールバック**: `PFGameSaveFilesUiActiveDeviceContentionCallback`

**応答 API**: `PFGameSaveFilesSetUiActiveDeviceContentionResponse`

| アクション               | 効果                                                                            |
| ------------------- | ----------------------------------------------------------------------------- |
| `Cancel`            | 操作をキャンセルします。`XAsyncBlock` コールバックが `E_PF_GAMESAVE_USER_CANCELLED` で発生します。      |
| `Retry`             | 再試行します。他のデバイスがすぐに解放されるとユーザーが期待している場合に便利です。他のデバイスがまだアクティブな場合、このコールバックが再度発生します。 |
| `SyncLastSavedData` | ローカルデバイスをアクティブにして同期します。リモートデバイスはもうアップロードできなくなり、アクティブデバイス変更通知を受け取ります。          |

アクティブデバイスの動作の詳細については、[Game Saves のアクティブデバイスの変更](/services/playfab/player-progression/game-saves/activedevicechanges) を参照してください。

### 競合

ローカルとクラウドの保存データが分岐したときに、`PFGameSaveFilesAddUserWithUiAsync` 中に発生します。コールバックは、ローカルとリモート両方の保存データの `PFGameSaveDescriptor` 構造体を受け取ります。

**コールバック**: `PFGameSaveFilesUiConflictCallback`

**応答 API**: `PFGameSaveFilesSetUiConflictResponse`

| アクション        | 効果                                                                       |
| ------------ | ------------------------------------------------------------------------ |
| `Cancel`     | 操作をキャンセルします。`XAsyncBlock` コールバックが `E_PF_GAMESAVE_USER_CANCELLED` で発生します。 |
| `TakeLocal`  | ローカル保存データを保持し、クラウドにアップロードします。                                            |
| `TakeRemote` | ローカルの変更を破棄し、クラウドの保存データをダウンロードします。                                        |

<Info>
  競合の解決は、個々のファイルやフォルダーではなく、保存全体に適用されます。競合がアトミック単位レベルでどのように検出され、グローバルに解決されるかの詳細については、[Game Saves の競合](/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) を参照してください。

## 関連コンテンツ

* [Game Saves クイックスタート](/services/playfab/player-progression/game-saves/quickstart)
* [Game Saves オフラインモード](/services/playfab/player-progression/game-saves/offline)
* [Game Saves の競合](/services/playfab/player-progression/game-saves/conflicts)
* [Game Saves のアクティブデバイスの変更](/services/playfab/player-progression/game-saves/activedevicechanges)


## Related topics

- [Game Saves クイックスタート](/ja-jp/services/playfab/player-progression/game-saves/quickstart.md)
- [PlayFab Game Saves の Steam Deck 実装ガイド](/ja-jp/services/playfab/player-progression/game-saves/steam-deck-implementation.md)
- [Game Saves ロールバック](/ja-jp/services/playfab/player-progression/game-saves/rollback.md)
- [GameInput コールバック](/ja-jp/build/core-features/common/input/advanced/input-callbacks.md)
- [方法: コールバックの送信](/ja-jp/build/core-features/common/async/async-task-queue-design-howto/submitting-callbacks.md)
