> ## 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 クイックスタート

> PlayFab Game Saves のクイックスタートでは、初期セットアップ、SDK 呼び出し、クラウド セーブ データの読み取りと書き込みを行い、セーブを素早く統合できるようにします。

# Game Saves のクイックスタート

PlayFab Game Saves を使用すると、プレイヤーはセーブ データをクラウドに同期することで、デバイス間でシームレスに進行状況を続けることができます。このクイックスタート ガイドでは、XBOX および Windows プラットフォーム向けの完全なゲーム セーブ ソリューションを実装する方法を説明します。

## 前提条件

開始する前に、以下が満たされていることを確認してください。

* Game Saves の [オンボーディング](/services/playfab/player-progression/game-saves/onboarding) が完了している
* [概要](/services/playfab/player-progression/game-saves/overview) セクションの実装要件を確認している
* 下記のリストにある要件を満たしている
* (任意) GitHub の Windows 向けエンドツーエンド **Game Saves サンプル** をクローンまたは確認している: [PlayFabGameSaveSample-Windows](https://github.com/PlayFab/PlayFab-Samples/tree/master/Samples/All/PlayFabGameSaveSample-Windows)。このサンプルは、このクイックスタートで参照される初期化、同期、競合処理、およびアップロードのフローをデモンストレーションします。

## 学習内容

このガイドでは、以下の方法を学びます。

* Game Saves システムの初期化
* クラウドからの既存セーブ データのダウンロード
* ローカル セーブ データのクラウドへのアップロード
* 競合と UI コールバックの処理
* アクティブ デバイス シナリオの管理

## 開発要件

### ソフトウェア要件

* [PlayFab 開発者アカウント](https://developer.playfab.com)
* Gaming Runtime 開発には Visual Studio 2019 または Visual Studio 2022 が推奨されます。詳細は [https://learn.microsoft.com/en-us/gaming/gdk/docs/gdk-dev/get-started/overviews/sdk-and-tools#install-visual-studio](https://learn.microsoft.com/en-us/gaming/gdk/docs/gdk-dev/get-started/overviews/sdk-and-tools#install-visual-studio) を参照してください。
* 最新の [Microsoft Game Development Kit (GDK)](https://learn.microsoft.com/gaming/gdk/) へのアクセス

## Game Saves フローの概要

Game Saves システムは、デバイス間でシームレスに動作するシンプルなパターンに従います。

### 初期セットアップ (ゲーム セッションごとに 1 回)

1. **サービスの初期化**: PlayFab Core と Game Saves モジュールをセットアップします
2. **ユーザーの認証**: XBOX 認証を使用してプレイヤーをサインインします
3. **既存のセーブをダウンロード**: 他のデバイスからローカル デバイスにセーブ データを同期します
4. **セーブの場所を取得**: ゲームがセーブ ファイルを書き込むローカル セーブ ルート フォルダーを取得します

### ゲームプレイ中

5. **セーブ ファイルの書き込み**: ゲームは通常どおりローカル セーブ ルート フォルダーにセーブ データを書き込みます
6. **変更のアップロード**: 変更されたセーブ ファイルを定期的にクラウドにアップロードします
7. **プレイの継続**: ゲーム セッション中、必要に応じてステップ 5〜6 を繰り返します

### セッション終了

8. **最終アップロード**: プレイヤーが終了する前に最終的な変更をアップロードします
9. **バックグラウンド同期**: XBOX/Windows では、ゲームが閉じられるとシステムが最終アップロードを自動的に処理します

### 主な利点

* **オフライン サポート**: プレイヤーはインターネット接続なしでもプレイを開始できます
* **自動競合解決**: 組み込みの UI がデバイス間のセーブ競合を処理します
* **増分アップロード**: 変更されたファイルのみがアップロードされ、パフォーマンスが向上します
* **クロス デバイスの継続性**: デバイスを切り替える際のシームレスなエクスペリエンス

## 実装の詳細

以下のセクションでは、各手順の詳細なコード例を提供します。

## ステップ 1: Game Saves を初期化する

Game Saves は、オンラインとオフラインの両方で動作するように設計されており、他の PlayFab API とは異なります。デバイスがオフラインで起動しても機能する永続的なローカル ユーザー ID を保持します。

### 主な概念

* **PFLocalUserHandle**: オフラインで機能する永続的なユーザー識別子
* **PFServiceConfigHandle**: PlayFab タイトルの構成
* **オフラインファースト設計**: システムはインターネット接続がなくてもすぐに動作します

### 前提条件

Game Saves を初期化する前に、以下が満たされていることを確認してください。

* `XGameRuntimeInitialize()` を呼び出して XBOX ランタイムを初期化している
* `XUserAddAsync()` を呼び出してユーザーをサインインし、`XUserHandle` を取得している
* Game Manager からの PlayFab タイトル ID がある

### 実装

```cpp theme={null}
// Step 1: Initialize PlayFab Core
HRESULT hr = PFInitialize(nullptr);
if (FAILED(hr))
{
    // Handle initialization failure - log error and exit gracefully
    return hr;
}

// Step 2: Create service config handle with your title information
PFServiceConfigHandle serviceConfigHandle{ nullptr };
hr = PFServiceConfigCreateHandle(
    "https://<titleId>.playfabapi.com",    // Replace <titleId> with your actual PlayFab Title ID
    "<titleId>",                           // Replace <titleId> with your actual PlayFab Title ID
    &serviceConfigHandle);
if (FAILED(hr))
{
    // Handle service config creation failure
    return hr;
}

// Step 3: Initialize the Game Saves module
PFGameSaveInitArgs args = {};
// Set args.saveFolder here if you are targetting platforms such as Steam
// where you need to provide root of where the game saves are
hr = PFGameSaveFilesInitialize(&args);
if (FAILED(hr))
{
    // Handle Game Saves initialization failure
    return hr;
}

// Step 4: Create a local user handle
// NOTE: Assumes you have already obtained 'xuserHandle' from XUserAddAsync
PFLocalUserHandle localUserHandle;
hr = PFLocalUserCreateHandleWithXboxUser(serviceConfigHandle, xuserHandle, nullptr, &localUserHandle);
if (FAILED(hr))
{
    // Handle local user creation failure
    return hr;
}

// Success! The Game Saves system is now initialized and ready to use
```

<Info>
  `<titleId>` を Game Manager からの実際の PlayFab タイトル ID に置き換えてください。`xuserHandle` は `XUserAddAsync` の呼び出しが成功した結果から取得する必要があります。
</Info>

### 代替プラットフォーム

XBOX 認証がなくオフライン サポートもないプラットフォームでは、代わりに `PFLocalUserCreateHandle` または `PFLocalUserCreateHandleWithPersistedLocalId` の他のバージョンを使用してください。実装の詳細については、プラットフォーム固有のドキュメントを参照してください。

例:

```cpp theme={null}
PFLocalUserHandle localUserHandle;
hr = PFLocalUserCreateHandleWithSteamUser(serviceConfigHandle, nullptr, &localUserHandle);
if (FAILED(hr))
{
    // Handle local user creation failure
    return hr;
}
```

## ステップ 2: クラウドからセーブ データを同期する

初期化の後、Game Saves システムにユーザーを追加して、他のデバイスからの既存のセーブ データを同期します。この手順では、ゲームがセーブ ファイルの読み書きを行うローカル セーブ ルート フォルダーもセットアップされます。

### この呼び出しを行うタイミング

* ユーザー認証後、ゲーム セッションごとに 1 回
* ユーザーがゲームのメイン メニューに戻ったとき
* サスペンド/バックグラウンドから再開した後

### この手順で行われる処理

1. 他のデバイスから **既存のセーブをダウンロード** します (新しいまたは変更されたファイルのみ)
2. 可能な場合、適切なバージョン管理のために **ファイル タイムスタンプを保持** します
3. 組み込みの UI で **競合を自動的に処理** します
4. このユーザーの **アクティブ デバイスとして設定** します
5. ゲームがファイルを書き込む **セーブ フォルダー パスを提供** します

### 重要な制限事項

* Game Saves セッションごとに **1 回のみ** 成功して呼び出せます
* 再度呼び出すには Game Saves システムの再初期化が必要です
* 競合、ストレージの問題、デバイスの競合について UI プロンプトをトリガーします

### 実装

```cpp theme={null}
// Add user to Game Saves system and sync from cloud
HRESULT hr;
XAsyncBlock async{};
hr = PFGameSaveFilesAddUserWithUiAsync(localUserHandle, PFGameSaveFilesAddUserOptions::None, &async);
if (FAILED(hr))
{
    // Handle API call failure
    return hr;
}

// Wait for the operation to complete
// For production code, consider using a callback instead of blocking
hr = XAsyncGetStatus(&async, true); 
if (FAILED(hr))
{
    // Handle async operation failure (network issues, user cancellation, etc.)
    return hr;
}

hr = PFGameSaveFilesAddUserWithUiResult(&async);
if (FAILED(hr))
{
    // Handle specific operation failures (conflicts, storage issues, etc.)
    return hr;
}

// Get the local save root folder path for your game
char saveFolder[1024] = { 0 };
hr = PFGameSaveFilesGetFolder(localUserHandle, 1024, saveFolder, nullptr);
if (FAILED(hr))
{
    // Handle folder retrieval failure
    return hr;
}

// Check remaining cloud storage quota
int64_t remainingQuota{ 0 };
hr = PFGameSaveFilesGetRemainingQuota(localUserHandle, &remainingQuota);
if (FAILED(hr))
{
    // Handle quota retrieval failure
    return hr;
}

// Success! You can now read/write save files in the saveFolder directory
printf("Save folder: %s\n", saveFolder);
printf("Remaining quota: %lld bytes\n", remainingQuota);
```

### 次の手順

この呼び出しが正常に完了した後:

* ゲームは `saveFolder` ディレクトリから既存のセーブ ファイルを読み取ることができます
* 必要に応じて新しいセーブ ファイルを書き込み、サブディレクトリを作成できます
* デバイスは、このユーザーの「アクティブ」と見なされます
* ユーザーが他のデバイスで同期しようとすると、それらのデバイスに警告が表示されます

## ステップ 3: セーブ データをクラウドにアップロードする

ゲームがローカル セーブ ルート フォルダーにセーブ ファイルとサブフォルダーを書き込んだら、この手順を使用して変更をクラウドにアップロードします。システムは、最後のアップロード以降に変更されたファイルおよびサブフォルダーのみを自動的に検出してアップロードします。ファイルおよびフォルダーの削除もクラウドに自動的に同期されます。

### アップロードを推奨するタイミング

* **重要な進行の後**: プレイヤーがチェックポイントに到達したり、レベルを完了したとき
* **メニューの遷移前**: メイン メニューに戻ったり、ゲーム モードを切り替えたとき
* **ゲーム終了時**: プレイヤーがゲームを終了する前
* **定期的なセーブ**: 長時間のゲームプレイ セッション中、数分ごと

### アップロード オプション

* **`KeepDeviceActive`**: デバイスはアクティブなままで、後で追加のアップロードが可能
* **`ReleaseDeviceAsActive`**: デバイスをアクティブから解放し、他のデバイスでシームレスな同期を可能にする

### プラットフォームの動作

* **XBOX/Windows**: ゲームが閉じられた後もアップロードはバックグラウンドで続行されます
* **その他のプラットフォーム** (Steam Deck など): ゲームの終了前にアップロードが完了する必要があります。そうしないとセーブ データがクラウドに到達しません

### 実装

```cpp theme={null}
// Upload save files to cloud
XAsyncBlock async{};
HRESULT hr = PFGameSaveFilesUploadWithUiAsync(
    localUserHandle, 
    PFGameSaveFilesUploadOption::KeepDeviceActive,  // Use ReleaseDeviceAsActive when quitting
    &async);
if (FAILED(hr))
{
    // Handle API call failure
    return hr;
}

// Wait for upload to complete
// Consider using callbacks for better user experience
hr = XAsyncGetStatus(&async, true); 
if (FAILED(hr))
{
    // Handle async operation failure (network issues, storage full, etc.)
    return hr;
}

hr = PFGameSaveFilesUploadWithUiResult(&async);
if (FAILED(hr))
{
    // Handle upload failure
    return hr;
}

// Success! Save data is now safely stored in the cloud
```

### セーブ フォルダーに再び書き込めるのはいつですか?

アップロード中、システムはローカル セーブ ファイルを読み取り、圧縮してからアップロードします。同期状態が `Uploading` (`PFGameSaveFilesUiProgressCallback` を介して報告される) に移行すると、システムはファイルの読み取りを完了しており、セーブ フォルダーに再び書き込むことは安全になります。セーブの再開前にアップロードの完全な完了を待つ必要はありません。

進行状況コールバックを使用していない場合は、新しいセーブ データを書き込む前に `XAsyncBlock` の完了を待ってください。

### ベスト プラクティス

1. **障害を優雅に処理する**: ネットワークの問題でゲームがクラッシュしてはいけません
2. **適切なオプションを使用する**:
   * ゲームプレイ中の追加アップロードには `KeepDeviceActive` を使用します
   * プレイヤーが終了したりメニューに戻るときは `ReleaseDeviceAsActive` を使用します
3. **XBOX 以外のプラットフォームでユーザーに警告する**: アップロード中に終了しないようプレイヤーに通知します

### 頻度に関する考慮事項

* セッションあたり複数のアップロードがサポートされ、効率的です
* 変更されたファイルのみがアップロードされ、帯域幅の使用を最小化します
* 具体的なクォータと制限については、[制限のドキュメント](/services/playfab/player-progression/game-saves/limits) を参照してください

## ステップ 4: UI コールバックを処理する (任意)

Game Saves は XBOX および Windows プラットフォーム向けに組み込みの UI を提供します。他のプラットフォーム (Steam Deck など) では、ゲームがコールバックを処理して独自の UI を提供する必要があります。

UI コールバックは、`PFGameSaveFilesAddUserWithUiAsync` および `PFGameSaveFilesUploadWithUiAsync` の実行中に発火します。各コールバックは、ゲームが応答するまで非同期操作を一時停止します。すべての UI コールバックが解決されるまで、`XAsyncBlock` コールバックは発火しません。

```cpp theme={null}
// Set up custom UI callbacks (call this before AddUser or Upload operations)
// See sample for detailed examples of these callbacks.
PFGameSaveUICallbacks callbacks{};
callbacks.progressCallback = MyProgressCallback;
callbacks.syncFailedCallback = MySyncFailedCallback;
callbacks.activeDeviceContentionCallback = MyActiveDeviceContentionCallback;
callbacks.conflictCallback = MyConflictCallback;
callbacks.outOfStorageCallback = MyOutOfStorageCallback;

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

コールバックの種類、応答 API、ユーザー アクション、ステート マシンの仕組みの詳細な一覧については、[Game Saves の UI コールバック](/services/playfab/player-progression/game-saves/ui-callbacks) を参照してください。

## セーブ競合の理解

セーブ競合は、複数のデバイスで同じゲーム データが変更されたときに発生します。Game Saves は、競合解決のために各ルート レベルのサブフォルダーをアトミック ユニットとして扱います。競合が発生した場合、プレイヤーはローカルまたはクラウドのデータを保持するかを選択できます。

競合処理の詳細なシナリオとベスト プラクティスについては、[Game Saves の競合](/services/playfab/player-progression/game-saves/conflicts) を参照してください。

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

Game Saves はオンラインとオフラインの両方で動作します。クラウドに接続されているとき、すべての API は通常どおり機能します。オフラインまたは切断されている場合、ローカル セーブは引き続き機能しますが、クラウド操作は `E_PF_GAMESAVE_DISCONNECTED_FROM_CLOUD` を返します。

`PFGameSaveFilesIsConnectedToCloud()` を使用して接続状態を確認し、同期失敗コールバックを実装してネットワークの問題を優雅に処理してください。

オフライン動作とベスト プラクティスの詳細については、[Game Saves のオフライン モード](/services/playfab/player-progression/game-saves/offline) を参照してください。

## Game Saves のアクティブ デバイス変更の理解

プレイヤーがセッションの途中でデバイスを切り替える場合、複数のデバイスで同時にプレイして誤って進行状況を失うことを防ぐことが重要です。

ゲームが XBOX の **Single Point of Presence (SPOP)** 機能のみを使用してサインインする場合、このシナリオは自動的に防止されます。SPOP により、ユーザーは一度に 1 台の XBOX デバイスでのみサインインできるようになります。それ以外の場合は、プレイヤーがセッションの途中でデバイスを切り替えるシナリオを処理するために、アクティブ デバイス変更のコールバックも実装する必要があります。

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

## デバッグ

SDK の呼び出しの結果を確認し、デバッグする最も簡単な方法は、[デバッグ トレース](/services/playfab/sdks/c/tracing) を有効にすることです。デバッグ トレースを有効にすると、デバッガー出力ウィンドウで結果を確認したり、ゲーム独自のログに結果をフックしたりできます。


## Related topics

- [クイックスタート](/ja-jp/services/playfab/economy-monetization/economy-v2/quickstart.md)
- [クイックスタート GDK](/ja-jp/services/playfab/sdks/c/quickstart-gdk.md)
- [クイックスタート Win32](/ja-jp/services/playfab/sdks/c/quickstart-win32.md)
- [クイックスタート Linux](/ja-jp/services/playfab/sdks/c/quickstart-linux.md)
- [クイックスタート iOS](/ja-jp/services/playfab/sdks/c/quickstart-ios.md)
