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

# Steam Cloud ストレージを XBOX GDK に移植する

> Steam Cloud と ISteamRemoteStorage を XBOX GDK の XGameSaves ラッパーに置き換え、セーブの読み取り、書き込み、同期に関するコードサンプルを並べて比較します。

Steam は、次の 2 つの方法でクラウドストレージを有効化します。1 つ目は、`ISteamRemoteStorage` API メソッドを使用してすべての読み取り/書き込みを行う方法です。これらのメソッドは、ローカルハードドライブ上のゲームのストレージフォルダーにファイルを書き込み、クラウドに同期します。もう 1 つは、コンピューターのファイルシステムに対して直接すべての読み取り/書き込みを行い、Steam Auto-Cloud を使用して、ゲームデータが含まれるローカルフォルダーをクラウドに自動同期する方法です。

XBOX Game Development Kit (GDK) は、両方のアプローチをサポートしています。

* コードベースのクラウドセーブでは、GDK はより複雑な `XGameSaves` API の[シンプル化されたラッパー](/reference/system/Wrappers/xgamesave_wrapper_members)を提供し、`ISteamRemoteStorage` のメソッドと類似した機能を提供します。
* Steam Auto-Cloud に類似したアプローチでは、GDK は[ノーコードクラウドセーブによる以前のタイトルの PC Game Saves への移植](/build/core-features/common/game-save/game-saves-walkthroughs-and-samples#porting-previous-titles-to-pc-game-saves-with-no-code-cloud-saves)をサポートしています。これは、ファイル I/O コードを変更することなく、指定されたローカルフォルダーをクラウドに同期します。

<Warning>
  ノーコードクラウドセーブは、XBOX コンソールまたは XBOX Cloud Gaming ではサポートされていません。タイトルが Windows PC に加えてコンソールまたはクラウドを対象としている場合は、代わりに `XGameSaves` ラッパーまたは完全な `XGameSaves` API を使用してください。
</Warning>

コードベースのラッパーは、コンソールまたはクラウドで出荷されるタイトルにとって推奨されるパスであり、ローカルへのファイル書き込みや Steam Remote Storage API に近い形でマッピングされるため、このトピックではシンプル化されたラッパーの使用に焦点を当てています。

<Note>
  ラップされていない完全な `XGameSaves` API は、このシンプルなラッパーよりも多くの機能と柔軟性を提供します。ゲームは、決して一方から他方へ切り替えたり、API 呼び出しを混在させたりしてはいけないため、その API の機能を使用したい場合は、ラッパーを使用しないでください。`XGameSaves` API の詳細については、[Game saves](/build/core-features/common/game-save/game-saves-overview) を参照してください。
</Note>

次のコード例は、基本的なファイル操作が Steamworks SDK と XBOX Game Development Kit (GDK) でどのように動作するかを、2 つの API 間の微妙な違いとともに示しています。

## ファイル操作の比較

次のコード例は、Steamworks Remote Storage API と GDK 相当で、基本的なファイル操作を実行する方法を示しています。これらは、`provider` 変数が初期化された `Microsoft::Xbox::Wrappers::GameSave::Provider` オブジェクトへのポインターを保持していると想定しています。

Steam Remote Storage API を使用せず、代わりに Steam Auto-Cloud を選択している場合は、Remote Storage API 呼び出しをファイルシステム API 相当に置き換えてください。

### ファイルを読み取る

#### Steamworks

```cpp theme={null}
int32 size = SteamRemoteStorage()->GetFileSize("MyFile.json");
if (size > 0) 
{
    char *buffer = new char[size];
    bool result = SteamRemoteStorage()->FileRead("MyFile.json", buffer, size);
}           
```

または

```cpp theme={null}
int32 size = GetFileSize("MyFile.json");
if (size > 0)
{
    m_readResult = SteamRemoteStorage()->FileReadAsync("MyFile.json", 0, size);
    // Check the value of m_readResult in callback for error handling.
    STEAM_CALLBACK(MyGameClass, OnFileReadCompleted, RemoteStorageFileReadAsyncComplete_t);
}
```

#### GDK

```cpp theme={null}
BlobData data = provider->Load("SaveSlot1", "MyData");
if(!data.empty())
{
    // Iterate over the data to read bytes from the file.
}
else
{
    // Couldn't find the container/blob name.
}
```

#### リファレンスドキュメント

[Microsoft.Xbox.Wrappers.XGameSave.Provider.Load](/reference/system/Wrappers/xgamesave_wrapper_members)

### ファイルを書き込む

#### Steamworks

```cpp theme={null}
std::string saveData = "{progress: 25}";
SteamRemoteStorage()->FileWrite("MyFile.json", saveData.c_str(), saveData.size());
```

または

```cpp theme={null}
std::string saveData = "{progress: 25}";
m_writeResult = SteamRemoteStorage()->FileWriteAsync("MyFile.json", saveData.c_str(), saveData.size());
STEAM_CALLBACK(MyGameClass, OnFileWriteCompleted, RemoteStorageFileWriteAsyncComplete_t);
```

#### XBOX Game Development Kit (GDK)

```cpp theme={null}
std::vector<uint8_t> saveData; // Contains the player's data.
HRESULT hr = provider->Save("SaveSlot1", "MyData", saveData.size(), saveData.data());
if(FAILED(hr))
{
  if(hr == E_GS_QUOTA_EXCEEDED)
  {
     // Message that the user must clear out saves for this game.
  }
  else if(hr == E_GS_OUT_OF_LOCAL_STORAGE)
  {
     // Message to the user that they have run out of save space on the local device.
  }
  else if(hr == E_GS_UPDATE_TOO_BIG)
  {
     // Your save size was over 16 MB (GS_MAX_BLOB_SIZE).
  }
  else if(hr == E_GS_HANDLE_EXPIRED)
  {
     // Need to re-create the provider and try again.
     // This can happen if your game was suspended and, during that time, another
     // device initialized a provider for the same user.
  }
  else
  {
     // Log error.
  }
}
```

#### リファレンスドキュメント

[Microsoft.Xbox.Wrappers.XGameSave.Provider.Save](/reference/system/Wrappers/xgamesave_wrapper_members)

### ファイルの削除

Steam では、クラウド内のファイルを削除してローカルコピーは保持する (`FileForget`)、あるいは両方の場所からファイルを削除する (`FileDelete`) のどちらかを行うことができます。`XGameSave` ラッパー API には `FileForget` に相当する機能はありません。その `Delete` 関数は、Steamworks の `FileDelete` と同様に動作します。

#### Steamworks

```cpp theme={null}
// Delete a file from the cloud but keep it locally.
bool result = SteamRemoteStorage()->FileForget("MyFile.json");
```

または

```cpp theme={null}
// Delete a file locally AND from the cloud.
bool result = SteamRemoteStorage()->FileDelete("MyFile.json");
```

#### XBOX Game Development Kit (GDK)

```cpp theme={null}
// Delete a specific file.
HRESULT hr = provider->Delete("MyContainer", "MyData");
```

または

```cpp theme={null}
// Delete a set of files in a container. 
std::vector<std::string> toDelete = { "blob1", "blob2", "blob3" };
HRESULT hr = provider->Delete("MyContainer", toDelete);
```

または

```cpp theme={null}
// Delete all the files in a container.
HRESULT hr = provider->Delete("MyContainer");
```

#### リファレンスドキュメント

* [Microsoft.Xbox.Wrappers.XGameSave.Provider.Delete(std::string)](/reference/system/Wrappers/xgamesave_wrapper_members)
* [Microsoft.Xbox.Wrappers.XGameSave.Provider.Delete(std::string, std::string)](/reference/system/Wrappers/xgamesave_wrapper_members)
* [Microsoft.Xbox.Wrappers.XGameSave.Provider.Delete(std::string, BlobNames)](/reference/system/Wrappers/xgamesave_wrapper_members)

### すべてのファイルを取得する

#### Steamworks

```cpp theme={null}
int32 fileCount = SteamRemoteStorage()->GetFileCount();
for ( int i = 0; i < fileCount; ++i ) {
    int32 fileSize;
    const char *fileName = SteamRemoteStorage()->GetFileNameAndSize( i, &fileSize );
    // Do something with fileSize and fileName.
}
```

#### XBOX Game Development Kit (GDK)

```cpp theme={null}
// To get all the files across all containers for the game, make this = ""
// Otherwise, make it a prefix of whichever container's files you'd like.
std::string containerQuery = "";
std::vector<std::string> containers = provider->QueryContainers(containerQuery);

for (auto&& container : containers)
{
    BlobInfoSet blobs = provider->QueryContainerBlobs(container);
    for (auto&& blob : blobs)
    {
        uint32_t blobSize = blob.size;
        std::string blobName = blob.name;
        // Do something with blobSize and blobName.
    }
}
```

#### リファレンスドキュメント

* [Microsoft.Xbox.Wrappers.XGameSave.Provider.QueryContainers](/reference/system/Wrappers/xgamesave_wrapper_members)
* [Microsoft.Xbox.Wrappers.XGameSave.Provider.QueryContainerBlobs](/reference/system/Wrappers/xgamesave_wrapper_members)

### 利用可能な容量を確認する

次の例では、`totalBytes` はクラウドストレージプロバイダーがゲームに割り当てた容量、`availableBytes` は残りの空き容量です (つまり、`availableBytes` = `totalBytes` – `bytesUsed`)。

#### Steamworks

```cpp theme={null}
uint64 totalBytes, availableBytes;
SteamRemoteStorage()->GetQuota(&totalBytes, &availableBytes);
```

#### XBOX Game Development Kit (GDK)

```cpp theme={null}
// totalBytes is always 256 MB.
int64_t availableBytes = provider->GetQuota();
```

#### リファレンスドキュメント

[Microsoft.Xbox.Wrappers.XGameSave.Provider.GetQuota](/reference/system/Wrappers/xgamesave_wrapper_members)

## 用語の違い

Steam では、リモートストレージのデータはファイルとして管理され、ローカルハードドライブ上のファイルと同じように動作します。読み取りと書き込みは、読み書きしたいファイルを指定し、そのファイルに含まれるバイトを取得/設定することによって行われます。

XBOX Game Development Kit (GDK) では、Steam のファイルに相当するものは *ブロブ (blob)* であり、ブロブは *コンテナー (container)* と呼ばれる構造にまとめられます。コンテナーは単に名前付きのブロブグループです。コンテナーは、たとえば、ユーザーごとに複数のセーブスロットを持ち、各スロットに同じファイル名を持たせるために使用できます。コンテナーが提供する追加の整理レイヤーが不要な場合は、すべてのブロブ (ファイル) を同じコンテナーに配置するだけです。

<Note>
  コンテナー名にスペースを含めることはできません。スペースを含むコンテナー名にアクセスまたは作成しようとすると、
</Note>

プロバイダーメソッドが `0x80830001` の HRESULT を返します: 指定されたボリュームはストレージ層をサポートしていません。

## ストレージ制限

XBOX Game Development Kit (GDK) は、Steam よりも最大ブロブ/ファイル書き込みサイズと全体的なストレージ制限が低くなっています。Steam では、各ファイル書き込み操作は 100 メビバイト (MiB) に制限されています。各ファイルは 200 MiB を超えることはできませんが、`XGameSave` API とそのラッパーでは、各ブロブが 16 MB を超えることは許されず、ユーザーごとおよびゲームごとに最大 256 MB のストレージ許容量となっています。

ブロブに 16 MB を超えるデータを保存する必要がある場合は、データを複数のブロブに分割し、一度に 1 つのブロブずつデータを読み書きするシーケンシャル読み取り/書き込み関数を実装する必要があります。

## ラッパー関数はブロッキング

`ISteamRemoteStorage` インターフェイスは、読み取り/書き込み関数の 2 つのバージョンを提供しています: `FileRead`/`FileWrite` と `FileReadAsync`/`FileWriteAsync` です。後者は、ファイルの読み取り/書き込みが完了した時点でコールバックする非同期関数です。シンプル化された `XGameSave` ラッパー関数は、`FileRead`/`FileWrite` に相当する非同期バージョンを提供していません。ただし、`Provider::Load` と `Provider::Save` はどちらもブロッキングであるため、ゲーム内で使用する際にはその点に注意してください。

このため、`Provider::Initialize` は *UI スレッドから呼び出されると例外をスローします*。

## 初期化

他の何かを行う前に、ゲームのソリューションにラッパーのヘッダーファイルを含める必要があります。これは *%GRDKLatest%\GameKit\Include\xgamesavewrappers.hpp* にあります。

`XGameSaves` ラッパーのメソッドを使用する前に、`Provider` クラスのインスタンスを作成する (ゲームのライフタイムを通じてそのポインターを保持する必要があります) と、`Provider::Initialize` メソッドを呼び出す必要があります。繰り返しになりますが、このメソッドは UI とは別のスレッドで呼び出す必要があり、UI スレッドから呼び出された場合は例外がスローされる点に注意することが重要です。ラッパープロバイダーを初期化するには、現在のユーザーの `XUserHandle` とゲームのサービス構成識別子 (SCID) が必要であることに注意してください。

```cpp theme={null}
using namespace Microsoft::Xbox::Wrappers::GameSave;

Provider provider = new Provider();
if(SUCCEEDED(provider->Initialize(userHandle, mySCID)) {
    // Start using the XGameSave wrapper...
```

#### リファレンスドキュメント

[Microsoft.Xbox.Wrappers.XGameSave.Provider.Initialize](/reference/system/Wrappers/xgamesave_wrapper_members)


## Related topics

- [ストレージ](/ja-jp/services/xbox-services/storage/index.md)
- [Steam からの移植](/ja-jp/paths/porting/from-steam.md)
- [既存の入力コードを GameInput に移植する](/ja-jp/build/core-features/common/input/porting/index.md)
- [コンソール固有の GDK 機能](/ja-jp/build/console-features/console-features-overview.md)
- [XBOX services の概要](/ja-jp/services/xbox-services/fundamentals/live-xbl-overview.md)
