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

# Game Saves のオフライン モード

> PlayFab Game Saves のオフライン モードを使用して、接続がなくてもプレイヤーの進行状況を継続させ、ネットワーク回復後にクラウド セーブを同期します。

Game Saves は、オンラインとオフラインの両方で動作するように設計されており、ネットワーク接続が利用できない場合でもプレイヤーがゲームを続けられるようになっています。システムは、ネットワークの可用性とユーザーの選択に基づいて 2 つの異なるモードで動作します。

## 接続モード

### クラウド接続モード

ネットワークが利用可能で `PFGameSaveFilesAddUserWithUiAsync()` が正常に完了すると、システムはクラウド接続モードで動作します。このモードでは:

* すべての API がクラウド同期を完全に伴って正常に機能します
* セーブ データのアップロードは期待どおりに動作します
* ストレージ クォータの情報が利用可能です
* アクティブ デバイスの監視が正しく機能します

### オフライン モード (クラウドに未接続)

ネットワークが利用できないか、ユーザーがオフラインでプレイすることを選択した場合、システムは限られた機能でオフライン モードに入ります。`PFGameSaveFilesIsConnectedToCloud()` を使用して現在の接続状態を確認し、システムがどのモードで動作しているかを判断できます。

## 初期同期中のネットワーク障害の処理

`PFGameSaveFilesAddUserWithUiAsync()` がネットワーク接続なしで呼び出されると、`PFGameSaveFilesUiSyncFailedCallback` がトリガーされます。システムがユーザーの応答を待つ間、`XAsyncBlock` コールバックは発火しません。ユーザーが終端アクションを選択するまで、非同期操作は一時停止されます。

```cpp theme={null}
// Handle sync failure callback
void MyPFGameSaveFilesUiSyncFailedCallback(PFLocalUserHandle localUserHandle, PFGameSaveFilesSyncState syncState, HRESULT error, void* context)
{
    // Tell the user something like this:
    std::cout << "We couldn't sync your data with the cloud just now" << std::endl;
    std::cout << "Try syncing again or use this game offline" << std::endl;
    std::cout << "[Try Again]" << std::endl;
    std::cout << "[Use Offline]" << std::endl;

    // if user chooses [Try Again], call PFGameSaveFilesSetUiSyncFailedResponse(localUserHandle, PFGameSaveFilesUiSyncFailedUserAction::Retry);
    // if user chooses [Use Offline], call PFGameSaveFilesSetUiSyncFailedResponse(localUserHandle, PFGameSaveFilesUiSyncFailedUserAction::UseOffline);

    // These API calls can happen inside or outside of this callback
}
```

**ユーザー応答オプション:**

* **Try Again (`Retry`)**: ネットワーク呼び出しを再試行します。再試行も失敗した場合、このコールバックが再度発火し、ユーザーが再度応答する必要があります。`XAsyncBlock` コールバックは、各再試行ループを通じて延期されたままです。
* **Use Offline (`UseOffline`)**: `XAsyncBlock` コールバックが `S_OK` で発火しますが、システムはオフライン モードに入ります (`PFGameSaveFilesIsConnectedToCloud()` で検出できます)。
* **Cancel**: `XAsyncBlock` コールバックが `E_PF_GAMESAVE_USER_CANCELLED` で発火します。

## オフライン モードでの API 動作

オフライン モードでは、API は異なる動作をします。

### 通常に動作する API

* `PFGameSaveFilesGetFolder()` - ローカル セーブ フォルダー パスを返します

### 機能が制限される API

* `PFGameSaveFilesUploadWithUiAsync()` - すぐに `S_OK` を返しますが、非同期の完了は `E_PF_GAMESAVE_DISCONNECTED_FROM_CLOUD` を返します
* `PFGameSaveFilesGetRemainingQuota()` - `E_PF_GAMESAVE_DISCONNECTED_FROM_CLOUD` を返します
* `PFGameSaveFilesSetActiveDeviceChangedCallback()` - 設定できますがトリガーされることはありません

### オンライン モードに戻る

* 再接続を試みるために `PFGameSaveFilesAddUserWithUiAsync()` を再度呼び出します
* Game Saves システムを完全に再初期化する必要はありません
* ネットワークがまだ利用できない場合、再度失敗 UI が表示されます
* 再試行後に接続状態を検証するには `PFGameSaveFilesIsConnectedToCloud()` を使用します

## Game Saves がオフライン モードに入る場合とエラーを返す場合

統合に関するよくある質問は、*初期同期 (`PFGameSaveFilesAddUserWithUiAsync`) はどのような場合にプレイヤーをオフライン モードにし、どのような場合にエラー コードで失敗するのか* というものです。終端の結果は接続、オフライン、キャンセルの 3 つで、キャンセルはプレイヤーとゲームのどちらからも発生する可能性があります:

| 結果 | 到達方法 | 非同期の結果 | `IsConnectedToCloud()` | セーブ フォルダーの利用可否 | 推奨される処理 |
| - | - | - | - | - | - |
| **接続** | 同期が正常に完了した | `S_OK` | `true` | はい | プレイを許可します。セーブはクラウドに同期されます。 |
| **オフライン** | ユーザーが同期失敗のプロンプトで **Use Offline** を選択した (または別のデバイスがアクティブ デバイスになった) | `S_OK` | `false` | はい | ローカル セーブでのプレイを許可します。セーブが同期されないことをプレイヤーに伝えます。 |
| **プレイヤーによるキャンセル** | ユーザーがいずれかのプロンプトで **Cancel** を選択した | `E_PF_GAMESAVE_USER_CANCELLED` (`0x800704C7`) | 該当なし | **いいえ** | **プレイをブロック**するか、安全なメニューに戻ります。セーブまたはロードするフォルダーはありません。 |
| **ゲームによるキャンセル** | ゲームが `XAsyncBlock` に対して `XAsyncCancel` を呼び出した | `E_ABORT` (`0x80004004`) | 該当なし | **いいえ** | プレイヤーによるキャンセルと同じです。セーブまたはロードするフォルダーはありません。 |

重要なポイント:

* **オフライン モードはエラーではなく、成功の結果です。** オフライン モードには明示的に **Use Offline** を選択した場合にのみ入り、非同期操作は `S_OK` で完了します。`PFGameSaveFilesIsConnectedToCloud()` で検出してください。
* **一時的/技術的な障害は同期失敗 UI を通じて通知され**、`PFGameSaveFilesAddUserWithUiAsync` から直接返されることはありません。その後、ユーザー (または自動応答) が `Retry`、`UseOffline`、または `Cancel` を選択し、上記の 3 つの結果のいずれかに解決されます。
* **キャンセルは終端であり、セーブ フォルダーは生成されません。** 「キャンセル」(またはフォルダーが残らない失敗) は *プレイを許可しない* として扱ってください。
* **プレイヤーによるキャンセルとゲームによるキャンセルは異なるコードを返します。** `E_PF_GAMESAVE_USER_CANCELLED` が生成されるのは、プレイヤーがプロンプトで **Cancel** を選択した場合のみです。ゲーム自体が `XAsyncCancel` で操作をキャンセルした場合は、`E_ABORT` で完了します。両者を同じように扱いたい場合は、両方をチェックしてください。

> [!NOTE]
>
> **競合**のプロンプトをキャンセルした場合も終端となり、`E_PF_GAMESAVE_USER_CANCELLED` で完了します。同期失敗の「Use Offline」プロンプトに自動的に移行することはありません。「競合を拒否してもオフラインでプレイを続ける」エクスペリエンスが必要な場合は、明示的に設計してください (たとえば、`PFGameSaveFilesAddUserWithUiAsync` を再実行し、その結果発生する失敗で Use Offline を選択します)。[Game Saves の競合](https://docs.xbox.com/ja-jp/services/playfab/player-progression/game-saves/conflicts.md)を参照してください。

## Game Saves のエラー コード

次の HRESULT は Game Saves SDK によって定義されています。`0x8923xxxx` の範囲のコードは Game Saves 固有のものです。`0x800704C7` は `HRESULT_FROM_WIN32(ERROR_CANCELLED)` です。

| コード | 値 | 返される場合 |
| - | - | - |
| `E_PF_GAMESAVE_USER_CANCELLED` | `0x800704C7` | ユーザーがいずれかの UI プロンプトで **Cancel** を選択しました。終端であり、セーブ フォルダーはありません。(ゲームが `XAsyncCancel` で `XAsyncBlock` をキャンセルした場合、操作は代わりに標準の `E_ABORT` (`0x80004004`) で完了します。) |
| `E_PF_GAMESAVE_DISCONNECTED_FROM_CLOUD` | `0x89237004` | セッションがオフライン モードの間に `PFGameSaveFilesUploadWithUiAsync()` と `PFGameSaveFilesGetRemainingQuota()` によって返されます。 |
| `E_PF_GAMESAVE_NETWORK_FAILURE` | `0x89237005` | クラウドに接続したまま一時的なネットワーク障害が発生した後に、`PFGameSaveFilesUploadWithUiAsync()` によって返されます。後で安全に再試行できます。 |
| `E_PF_GAMESAVE_DEVICE_NO_LONGER_ACTIVE` | `0x89237007` | このデバイスがアクティブ デバイスではなくなった (別のデバイスが引き継いだ) 場合に、`PFGameSaveFilesUploadWithUiAsync()` によって返されます。 |
| `E_PF_GAMESAVE_DISK_FULL` | `0x89237008` | セーブ データをダウンロードするためのローカル ディスク領域が不足しています。領域を解放して再試行するようユーザーに促してください。 |
| `E_PF_GAMESAVE_OPERATION_IN_PROGRESS` | `0x89237009` | このユーザーに対して競合する操作が既に実行中です。別のアップロードまたはクラウドのリセットの進行中に `PFGameSaveFilesUploadWithUiAsync()` が呼び出された場合、クラウドのリセットの進行中に `PFGameSaveFilesAddUserWithUiAsync()` が呼び出された場合、または別のリセット、アップロード、ダウンロードの進行中に `PFGameSaveFilesResetCloudAsync()` が呼び出された場合です。何も開始または変更されていません。実行中の操作が完了するのを待ってから再試行してください。October 2026 GDK (2610) 以降で利用できます。 |
| `E_PF_GAMESAVE_LOCAL_FILE_UNAVAILABLE` | `0x8923700A` | アップロード中にローカル セーブ ファイルを読み取れない場合 (たとえば、タイトルがまだ書き込み用に開いている場合) に、`PFGameSaveFilesUploadWithUiAsync()` によって返されます。クラウドには何もコミットされていません。一時的なエラーです。タイトルがそのファイルへの書き込みを停止したら再試行してください。October 2025 GDK (2510) QFE5、April 2026 GDK (2604) QFE6、および October 2026 GDK (2610) で利用できます。 |
| `E_PF_GAMESAVE_DOWNLOAD_IN_PROGRESS` | `0x89237006` | `PFGameSaveFilesAddUserWithUiAsync()` が初期同期を完了する前に `PFGameSaveFilesUploadWithUiAsync()` が呼び出されました。 |
| `E_PF_GAMESAVE_USER_NOT_ADDED` | `0x89237003` | そのユーザーに対する `PFGameSaveFilesAddUserWithUiAsync()` が完了する前に API が呼び出されました。 |
| `E_PF_GAMESAVE_USER_ALREADY_ADDED` | `0x89237002` | 既に追加されているユーザーに対して `PFGameSaveFilesAddUserWithUiAsync()` が再度呼び出されました。 |
| `E_PF_GAMESAVE_ALREADY_INITIALIZED` | `0x89237001` | 間に `PFGameSaveFilesUninitializeAsync()` を挟まずに `PFGameSaveFilesInitialize()` が 2 回呼び出されました。 |
| `E_PF_GAMESAVE_NOT_INITIALIZED` | `0x89237000` | `PFGameSaveFilesInitialize()` の前に API が呼び出されました。 |

これらの結果が組み込みの (アウトオブプロセスの) システム UI と独自のコールバックでどのように生成されるかについては、[Game Saves の UI コールバック](https://docs.xbox.com/ja-jp/services/playfab/player-progression/game-saves/ui-callbacks.md#in-process-vs-out-of-process-system-ui)を参照してください。

## その他の接続状態シナリオ

`PFGameSaveFilesIsConnectedToCloud()` API は特に有用です。切断は複数の方法で発生する可能性があるためです。

* **同期中のネットワーク利用不可**: ユーザーが明示的にオフラインでのプレイを選択する
* **アクティブ デバイスが変更された**: 別のデバイスがアクティブ デバイスとして引き継ぎ、このデバイスは自動的にオフライン モードになる

適切なユーザー フィードバックを提供するには、クラウド操作を試みる前にこの API を使用してください。

## オフライン サポートのベスト プラクティス

1. ネットワークの問題を適切に処理するために **常に同期失敗コールバックを実装** する
2. クラウド操作を試みる前に `PFGameSaveFilesIsConnectedToCloud()` を使用して **定期的に接続状態を確認** する
3. セーブが同期されないことをプレイヤーが理解できるように、オフライン モードで動作しているときに **プレイヤーに通知** する
4. ネットワーク接続が復元されたときに **再試行オプションを提供** する
5. **ローカル セーブは常に機能する** - プレイヤーはネットワーク状態に関係なくプレイを続けることができる
6. **切断を監視する** - 別のデバイスがアクティブになるとデバイスが切断される可能性があることを覚えておく

## 接続モードでのアップロード動作

接続モードでも、ネットワークの問題やレート制限によってアップロードが失敗する場合があります。この場合、`XAsyncBlock` コールバックはすぐには発火しません。システムが [UI コールバック ステート マシン](https://docs.xbox.com/ja-jp/services/playfab/player-progression/game-saves/ui-callbacks.md#how-the-state-machine-works) を通じてユーザーの応答を待つ間、非同期操作は一時停止されます。

1. エラーの詳細と共に `PFGameSaveFilesUiSyncFailedCallback` が発火します。
2. `XAsyncBlock` コールバックはまだ発火しません。システムが応答を待つ間、操作が一時停止されます。
3. ユーザーが `Retry` を選択すると、アップロードが再試行されます。再度失敗すると、コールバックが再度発火し、ユーザーが再度応答する必要があります。
4. ユーザーが `Cancel` を選択すると、`XAsyncBlock` コールバックが `E_PF_GAMESAVE_USER_CANCELLED` で発火します。
5. 再試行が成功すると、`XAsyncBlock` コールバックが `S_OK` で発火します。

ゲームは、ネットワークが復元されたら後で `PFGameSaveFilesUploadWithUiAsync()` を再度呼び出すことができます。

> [!NOTE]
>
> **インプロセスでは、アップロードの実行中に同期失敗のプロンプトで `Use Offline` を提示しないでください。** アップロードは初期同期と同じ `PFGameSaveFilesUiSyncFailedCallback` を発火するため、SDK は選択肢を制限しません。しかし、ゲームがアップロードの失敗に対して `UseOffline` で応答すると、アップロードは `E_ABORT` で失敗します (デバッグ ビルドではアサートされます)。その場合は `Retry` と `Cancel` のみを提示してください。

## アップロードによってセッションがオフラインになる場合

アップロードによって通常は接続モードが変わることはありませんが、次の場合にはセッションがオフラインの状態で終了する可能性があります。いずれの場合も、アップロードは `E_PF_GAMESAVE_DISCONNECTED_FROM_CLOUD` で完了し、その後 `PFGameSaveFilesIsConnectedToCloud()` は `false` を返します。

* **セッションが既にオフラインだった。** ネットワークが復元されていても、アップロードは実行されず、`E_PF_GAMESAVE_DISCONNECTED_FROM_CLOUD` で完了します。
* **クラウドに新しいセーブがある。** アップロードの最終処理時に、別のデバイスから新しいセーブがコミットされたことをサービスが報告した場合、Game Saves はセッションをオフラインにし、アクティブ デバイス変更コールバックを発火して、アップロードを `E_PF_GAMESAVE_DISCONNECTED_FROM_CLOUD` で完了します。
* **プレイヤーが再ロックのプロンプトで `Use Offline` を選択した。** 以前のアップロードがデータをコミットした後に失敗した場合、次のアップロードではまずセーブのロックを再取得する必要があります。このステップ中の同期失敗のプロンプトに `UseOffline` で応答すると、セッションがオフラインになり、アップロードは `E_PF_GAMESAVE_DISCONNECTED_FROM_CLOUD` で完了します。

再接続するには、`PFGameSaveFilesAddUserWithUiAsync()` を再度呼び出します。

## アップロードのキャンセル

アップロードは初期同期と同じ方法でキャンセルできます。ユーザーは、アップロードの実行中に**進行状況** UI を `Cancel` するか、アップロードでエラーが発生した場合に**同期失敗**のプロンプトを `Cancel` できます。どちらの場合も、`PFGameSaveFilesUploadWithUiAsync()` は `E_PF_GAMESAVE_USER_CANCELLED` (`0x800704C7`) で完了し、セーブはアップロードされません。終端の結果は**成功**、**キャンセル**、または**失敗**です (`E_PF_GAMESAVE_DISCONNECTED_FROM_CLOUD` はセッションがオフラインになったことを意味します。[アップロードによってセッションがオフラインになる場合](#when-an-upload-takes-the-session-offline)を参照してください)。「プレイヤーが中止した」ことと「アップロードでエラーが発生した」ことを区別できるように、`E_PF_GAMESAVE_USER_CANCELLED` は他の障害とは別に処理してください。ゲーム自体が `XAsyncCancel` でアップロードをキャンセルした場合は、`E_PF_GAMESAVE_USER_CANCELLED` ではなく `E_ABORT` で完了します。


## Related topics

- [Game Saves クイックスタート](https://docs.xbox.com/ja-jp/services/playfab/player-progression/game-saves/quickstart.md)
- [Game Saves のエラー処理に関する FAQ](https://docs.xbox.com/ja-jp/services/playfab/player-progression/game-saves/error-handling-faq.md)
- [オフラインプレイの処理に関するベストプラクティス](https://docs.xbox.com/ja-jp/services/xbox-services/develop/best-practices/live-best-practices-offline-play.md)
- [XBOX services ユーザー特権のクライアント側での使用](https://docs.xbox.com/ja-jp/services/xbox-services/fundamentals/identity/privileges/concepts/live-user-privileges-client.md)
- [Game Saves の同期フローについて](https://docs.xbox.com/ja-jp/build/core-features/common/game-save/game-saves-syncing.md)
