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

# Portabilidad del almacenamiento de Steam Cloud al GDK de XBOX

> Sustituya Steam Cloud e ISteamRemoteStorage por el contenedor XGameSave del GDK de XBOX, con ejemplos de código comparados para leer, escribir y sincronizar guardados.

Steam habilita el almacenamiento en la nube de una de estas dos maneras. Puede realizar todas sus lecturas y escrituras mediante los métodos de la API `ISteamRemoteStorage`, que escriben los archivos en la carpeta de almacenamiento del juego en el disco duro local y los sincronizan con la nube. Como alternativa, puede realizar todas sus lecturas y escrituras directamente en el sistema de archivos del equipo y, a continuación, usar Steam Auto-Cloud para sincronizar con la nube la carpeta local que contiene los datos del juego.

Microsoft Game Development Kit (GDK) admite ambos enfoques:

* Para los guardados en la nube basados en código, el GDK ofrece un [contenedor simplificado](/reference/system/Wrappers/xgamesave_wrapper_members) de la API `XGameSave`, más compleja, que proporciona una funcionalidad similar a la de los métodos de `ISteamRemoteStorage`.
* Para un enfoque similar a Steam Auto-Cloud, el GDK admite [la portabilidad de títulos anteriores a los guardados de juego de PC con guardados en la nube sin código](/build/core-features/common/game-save/game-saves-walkthroughs-and-samples#porting-previous-titles-to-pc-game-saves-with-no-code-cloud-saves), que sincroniza con la nube una carpeta local designada sin requerir cambios en el código de E/S de archivos.

<Warning>
  Los guardados en la nube sin código no se admiten en las consolas XBOX ni en XBOX Cloud Gaming. Si su título se dirige a consolas o a la nube además de a PC con Windows, use el contenedor de `XGameSave` o la API completa de `XGameSave` en su lugar.
</Warning>

El contenedor basado en código es la ruta recomendada para los títulos que se distribuyen en consola o en la nube. Se corresponde estrechamente con la escritura de archivos localmente o mediante la API Remote Storage de Steam. Este tema se centra en el contenedor simplificado.

<Note>
  La API completa de `XGameSave`, sin contenedor, ofrece más funcionalidad y flexibilidad que el contenedor simple. Si necesita alguna de esas funcionalidades, no use el contenedor. Los juegos no deben alternar entre los dos ni mezclar llamadas de ambas API. Para obtener más información sobre la API `XGameSave`, consulte [Guardados de juego](/build/core-features/common/game-save/game-saves-overview).
</Note>

Los siguientes ejemplos de código muestran cómo funcionan las operaciones básicas de archivos en el SDK de Steamworks y en Microsoft Game Development Kit (GDK), junto con algunas diferencias sutiles entre las dos API.

## Comparación de operaciones de archivos

Los siguientes ejemplos de código muestran cómo realizar operaciones básicas de archivos en la API Remote Storage de Steamworks y su equivalente en el GDK. Asumen que la variable `provider` contiene un puntero a un objeto `Microsoft::Xbox::Wrappers::GameSave::Provider` inicializado.

Si no usa la API Remote Storage de Steam y en su lugar optó por usar Steam Auto-Cloud, reemplace las llamadas a la API Remote Storage por sus equivalentes de la API del sistema de archivos.

### Lectura de un archivo

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

o

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

#### Documentación de referencia

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

### Escritura de un archivo

#### Steamworks

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

o

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

#### Documentación de referencia

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

### Eliminación de un archivo

En Steam, puede eliminar un archivo de la nube pero conservar la copia local (`FileForget`), o eliminar un archivo de ambas ubicaciones (`FileDelete`). La API del contenedor de `XGameSave` no tiene un equivalente de `FileForget`. Su función `Delete` funciona como `FileDelete` en Steamworks.

#### Steamworks

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

o

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

o

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

o

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

#### Documentación de referencia

* [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)

### Obtención de todos los archivos

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

#### Documentación de referencia

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

### Comprobación del espacio disponible

En los ejemplos siguientes, `totalBytes` es la cantidad de espacio que se asigna a su juego en el proveedor de almacenamiento en la nube. `availableBytes` es la cantidad de espacio libre restante (es decir, `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();
```

#### Documentación de referencia

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

## Diferencias de terminología

En Steam, los datos del almacenamiento remoto se administran como archivos, que funcionan como los archivos de un disco duro local. Para leer o escribir, especifique el archivo y, a continuación, obtenga o establezca los bytes que contiene.

En Microsoft Game Development Kit (GDK), el equivalente de los archivos de Steam son los *blobs*. Los blobs se agrupan en una estructura llamada *contenedor*. Un contenedor es un grupo de blobs con nombre. Por ejemplo, puede usar contenedores para admitir varias ranuras de guardado por usuario, con los mismos nombres de archivo en cada ranura. Si no necesita la capa organizativa adicional que proporcionan los contenedores, coloque todos sus blobs (archivos) en el mismo contenedor.

<Note>
  Los nombres de contenedor no pueden incluir espacios. Intentar acceder a un nombre de contenedor que incluya un espacio, o crearlo, hace que el método del proveedor devuelva un HRESULT de `0x80830001`: el volumen especificado no admite niveles de almacenamiento.
</Note>

## Límites de almacenamiento

Microsoft Game Development Kit (GDK) tiene un tamaño máximo de escritura de blob o archivo y un límite de almacenamiento general inferiores a los de Steam. En Steam, cada operación de escritura de archivo está limitada a 100 mebibytes (MiB), y cada archivo no puede superar los 200 MiB. En cambio, la API `XGameSave` y su contenedor limitan cada blob a 16 MB y permiten un máximo de 256 MB por usuario y juego.

Si necesita almacenar más de 16 MB de datos en un blob, divida los datos en varios blobs. A continuación, implemente una función de lectura y escritura secuencial para procesar los datos blob a blob.

## Las funciones del contenedor son bloqueantes

La interfaz `ISteamRemoteStorage` ofrece dos versiones de las funciones de lectura y escritura: `FileRead` y `FileWrite`, además de `FileReadAsync` y `FileWriteAsync`. Las versiones `Async` devuelven la llamada cuando el archivo se ha leído o escrito. Las funciones simplificadas del contenedor de `XGameSave` no ofrecen versiones asincrónicas de sus equivalentes de `FileRead` y `FileWrite`. `Provider::Load` y `Provider::Save` son ambas bloqueantes, así que tenga en cuenta este comportamiento cuando las use en su juego.

Por este motivo, `Provider::Initialize` *produce una excepción si la llama desde el subproceso de la interfaz de usuario*.

## Inicialización

Incluya el archivo de encabezado del contenedor en la solución de su juego antes de usar cualquier método del contenedor. Puede encontrarlo en *%GRDKLatest%\GameKit\Include\xgamesavewrappers.hpp*.

Antes de usar los métodos del contenedor de `XGameSave`, cree una instancia de la clase `Provider` y llame al método `Provider::Initialize`. Conserve un puntero a la instancia de `Provider` durante toda la vida útil de su juego. Llame a `Provider::Initialize` desde un subproceso distinto del subproceso de la interfaz de usuario. El método produce una excepción si lo llama desde el subproceso de la interfaz de usuario. Para inicializar el proveedor del contenedor, necesita un `XUserHandle` del usuario actual y el identificador de configuración de servicio (SCID) de su juego.

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

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

#### Documentación de referencia

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


## Related topics

- [Guías de portabilidad al GDK de XBOX](/es/home/build-first-title/porting-guides.md)
- [Información general de la guía de portabilidad de Steam](/es/build/steam-porting-guide/overview.md)
- [Portar desde Steam](/es/paths/porting/from-steam.md)
- [Cuadros de diálogo del sistema de Game Saves](/es/build/core-features/common/game-save/game-saves-dialogues.md)
- [Almacenamiento](/es/build/console-features/storage/index.md)
