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

# Porter le stockage Steam Cloud vers le XBOX GDK

> Remplacez Steam Cloud et ISteamRemoteStorage par le wrapper XGameSave du XBOX GDK, avec des exemples de code côte à côte pour la lecture, l'écriture et la synchronisation des sauvegardes.

Steam active le stockage infonuagique de l'une de deux façons. Vous pouvez effectuer toutes vos lectures et écritures à l'aide des méthodes de l'API `ISteamRemoteStorage`, qui écrivent les fichiers dans le dossier de stockage du jeu sur le disque dur local et les synchronisent avec le nuage. Vous pouvez aussi effectuer toutes vos lectures et écritures directement dans le système de fichiers de l'ordinateur, puis utiliser Steam Auto-Cloud pour synchroniser avec le nuage le dossier local contenant les données du jeu.

Le Microsoft Game Development Kit (GDK) prend en charge les deux approches :

* Pour les sauvegardes infonuagiques basées sur le code, le GDK offre un [wrapper simplifié](/fr-CA/reference/system/Wrappers/xgamesave_wrapper_members) de l'API `XGameSave`, plus complexe, qui fournit des fonctionnalités similaires aux méthodes de `ISteamRemoteStorage`.
* Pour une approche semblable à Steam Auto-Cloud, le GDK prend en charge le [portage de titres antérieurs vers PC Game Saves avec des sauvegardes infonuagiques sans code](/fr-CA/build/core-features/common/game-save/game-saves-walkthroughs-and-samples#porting-previous-titles-to-pc-game-saves-with-no-code-cloud-saves), qui synchronise un dossier local désigné avec le nuage sans nécessiter de modifications à votre code d'E/S de fichiers.

<Warning>
  Les sauvegardes infonuagiques sans code ne sont pas prises en charge sur les consoles XBOX ni sur XBOX Cloud Gaming. Si votre titre cible la console ou le nuage en plus du PC Windows, utilisez plutôt le wrapper `XGameSave` ou l'API `XGameSave` complète.
</Warning>

Le wrapper basé sur le code est l'approche recommandée pour les titres publiés sur console ou dans le nuage. Il correspond étroitement à l'écriture de fichiers en local ou à l'utilisation de l'API Steam Remote Storage. Cette rubrique porte sur le wrapper simplifié.

<Note>
  L'API `XGameSave` complète, sans wrapper, offre plus de fonctionnalités et de souplesse que le wrapper simple. Si vous avez besoin de l'une de ces fonctionnalités, n'utilisez pas le wrapper. Les jeux ne doivent pas passer de l'un à l'autre ni combiner des appels d'API des deux. Pour plus d'informations sur l'API `XGameSave`, consultez [Sauvegardes de jeu](/fr-CA/build/core-features/common/game-save/game-saves-overview).
</Note>

Les exemples de code suivants montrent le fonctionnement des opérations de base sur les fichiers dans le SDK Steamworks et dans le Microsoft Game Development Kit (GDK), ainsi que certaines différences subtiles entre les deux API.

## Comparaisons des opérations sur les fichiers

Les exemples de code suivants montrent comment effectuer des opérations de base sur les fichiers avec l'API Steamworks Remote Storage et son équivalent dans le GDK. Ils supposent que la variable `provider` contient un pointeur vers un objet `Microsoft::Xbox::Wrappers::GameSave::Provider` initialisé.

Si vous n'utilisez pas l'API Steam Remote Storage, mais avez plutôt choisi d'utiliser Steam Auto-Cloud, remplacez les appels à l'API Remote Storage par leurs équivalents de l'API du système de fichiers.

### Lecture d'un fichier

#### 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);
}           
```

ou

```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.
}
```

#### Documentation de référence

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

### Écriture d'un fichier

#### Steamworks

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

ou

```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);
```

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

#### Documentation de référence

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

### Supprimer un fichier

Sur Steam, vous pouvez soit supprimer un fichier dans le nuage tout en conservant la copie locale (`FileForget`), soit supprimer un fichier des deux emplacements (`FileDelete`). L'API du wrapper `XGameSave` n'a pas d'équivalent à `FileForget`. Sa fonction `Delete` fonctionne comme `FileDelete` dans Steamworks.

#### Steamworks

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

ou

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

#### GDK

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

ou

```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);
```

ou

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

#### Documentation de référence

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

### Obtenir tous les fichiers

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

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

#### Documentation de référence

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

### Vérifier l'espace disponible

Dans les exemples suivants, `totalBytes` correspond à la quantité d'espace attribuée à votre jeu chez le fournisseur de stockage infonuagique. `availableBytes` correspond à la quantité d'espace libre restant (c'est-à-dire `availableBytes` = `totalBytes` – `bytesUsed`).

#### Steamworks

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

#### GDK

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

#### Documentation de référence

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

## Différences de terminologie

Sur Steam, les données de stockage à distance sont gérées sous forme de fichiers, qui fonctionnent comme des fichiers sur un disque dur local. Pour lire ou écrire, vous spécifiez le fichier, puis vous obtenez ou définissez les octets qu'il contient.

Dans le Microsoft Game Development Kit (GDK), l'équivalent des fichiers Steam est l'objet *blob*. Les blobs sont regroupés dans une structure appelée *conteneur*. Un conteneur est un groupe nommé de blobs. Par exemple, vous pouvez utiliser des conteneurs pour prendre en charge plusieurs emplacements de sauvegarde par utilisateur, avec les mêmes noms de fichiers dans chaque emplacement. Si vous n'avez pas besoin de la couche d'organisation supplémentaire qu'offrent les conteneurs, placez tous vos blobs (fichiers) dans le même conteneur.

<Note>
  Les noms de conteneur ne peuvent pas contenir d'espaces. Toute tentative d'accéder à un conteneur ou d'en créer un dont le nom contient un espace amène la méthode du fournisseur à retourner un HRESULT `0x80830001` : le volume spécifié ne prend pas en charge les niveaux de stockage.
</Note>

## Limites de stockage

Le Microsoft Game Development Kit (GDK) impose une taille maximale d'écriture de blob ou de fichier et une limite de stockage globale inférieures à celles de Steam. Sur Steam, chaque opération d'écriture de fichier est limitée à 100 mébioctets (Mio), et chaque fichier ne peut pas dépasser 200 Mio. En revanche, l'API `XGameSave` et son wrapper limitent chaque blob à 16 Mo et autorisent un maximum de 256 Mo par utilisateur et par jeu.

Si vous devez stocker plus de 16 Mo de données dans un blob, divisez les données en plusieurs blobs. Implémentez ensuite une fonction de lecture et d'écriture séquentielle pour traiter les données un blob à la fois.

## Les fonctions du wrapper sont bloquantes

L'interface `ISteamRemoteStorage` offre deux versions des fonctions de lecture et d'écriture : `FileRead` et `FileWrite`, ainsi que `FileReadAsync` et `FileWriteAsync`. Les versions `Async` effectuent un rappel lorsque le fichier a été lu ou écrit. Les fonctions du wrapper `XGameSave` simplifié n'offrent pas de versions asynchrones de leurs équivalents à `FileRead` et `FileWrite`. `Provider::Load` et `Provider::Save` sont toutes deux bloquantes; tenez donc compte de ce comportement lorsque vous les utilisez dans votre jeu.

Pour cette raison, `Provider::Initialize` *lève une exception si vous l'appelez à partir du thread d'interface utilisateur*.

## Initialisation

Incluez le fichier d'en-tête du wrapper dans la solution de votre jeu avant d'utiliser les méthodes du wrapper. Vous le trouverez à l'emplacement *%GRDKLatest%\GameKit\Include\xgamesavewrappers.hpp*.

Avant d'utiliser les méthodes du wrapper `XGameSave`, créez une instance de la classe `Provider` et appelez la méthode `Provider::Initialize`. Conservez un pointeur vers l'instance `Provider` pendant toute la durée de vie de votre jeu. Appelez `Provider::Initialize` à partir d'un thread autre que le thread d'interface utilisateur. La méthode lève une exception si vous l'appelez à partir du thread d'interface utilisateur. Pour initialiser le fournisseur du wrapper, vous avez besoin d'un `XUserHandle` pour l'utilisateur actuel et de l'identificateur de configuration de service (SCID) de votre jeu.

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

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

#### Documentation de référence

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


## Related topics

- [Guides de portage vers le XBOX GDK](/fr-CA/home/build-first-title/porting-guides.md)
- [Migration du réseau XDK vers le XBOX GDK](/fr-CA/build/console-features/networking/xdk-migration/index.md)
- [Porter depuis Steam](/fr-CA/paths/porting/from-steam.md)
- [Porter depuis PC (hors Steam)](/fr-CA/paths/porting/from-pc.md)
- [Porter depuis d'autres plateformes](/fr-CA/paths/porting/from-console.md)
