This website uses cookies to improve our services and deliver relevant ads.
By interacting with this site, you agree to this use. For more information, see our Cookies Policy

Cloud Storage

Seamlessly save, synchronize, and load data between devices and installs using our Cloud Storage service.

Cloud Storage is designed to support the following use-cases:

  1. Save progress between installs. Users are able to uninstall and re-install without losing their saved data.
  2. Share progress between devices. Users can sync data between user devices.
  3. Disaster recovery. User data can be restored if devices are lost or damaged, or if the local data is corrupted.

Storage Formats

The Cloud Storage service uses buckets (directories) and blobs (files), indexed by a key (file name), to store data. The number of blobs stored per Bucket can not exceed 10,000. However, apps should use a smaller limit for the number of blobs, as the resources required to process a large number of keys may impact the user’s experience.

Direct file storage is not supported.

Note: The Cloud Storage service does not retain old versions of data. An app that needs old save files preserved should store them using a bucket/key backup strategy. For example, creating buckets saved_games_prior1 and saved_games_prior2 would allow to you store 2 old save files in addition to the latest save.

Data Storage Structure

Cloud Storage is divided into buckets (directories) of data that are configured in the Developer Center, under the Cloud Storage tab. Apps may define more than one bucket for multiple save types or data.

For example, when creating a new save you would call ovr_CloudStorage_Save(bucket_name, key, data_pointer, data_size, counter, extra_data). More details can be found in the ovr_CloudStorage_Save reference.

  • bucket_name - The name defined in the Developer Center.
  • key - The unique index for the blob. Total size cannot exceed 512 bytes.
  • data_pointer - The pointer to the data blob in your app.
  • data_size - The size, in bytes, of the data blob.
  • counter - The counter is an incremented uint64 metadata. The value is optional unless the Highest Counter conflict resolution policy is specified.
  • extra_data - Any extra, optional, metadata. Total size cannot exceed 512 bytes as a unsigned 64bit integer data.

Creating Buckets

In the Cloud Storage tab of the Developer Center click the Create Cloud Storage Bucket button and enter the information about the bucket that you would like to create.

Bucket names must to conform to the Microsoft Windows directory name restrictions (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx), are case-insensitive, must be unique within an Application Grouping, and less than 128 characters. Buckets do not exist by default for an application, to enable Cloud Storage at least one must be created on the dashboard.

Information about conflict management strategies can be found below in the Managing Conflicts section below.

Integrating Cloud Storage

Once you've defined the Cloud Storage buckets, you can integrate the service into your game. When calling the methods listed below you'll reference the bucket_name you created for the bucket.

The following is the typical Cloud Storage lifecycle:

  1. Retrieve a list of the entries in each Cloud Storage bucket you've defined by calling ovr_CloudStorage_LoadBucketMetadata(). Perform any conflict resolution required if the data retrieved is not in sync with the local data. Information about how to resolve conflicts can be found later in this guide.
  2. Once the metadata has been loaded and you've determined which save data you need to load, call ovr_CloudStorage_Load(), with the data key, to load the data. You can now launch your game using the game state data you loaded.
  3. During gameplay and at the prompt of the user, save the game state data by calling ovr_CloudStorage_Save() with the data blob. We recommend triggering saves once a minute, at most, and when prompted to prevent runaway game saves.
  4. When quitting the game, make sure to reconcile local and cloud saves ensuring that the latest data is saved to the Cloud Storage service.
Note: We recommend that you review the sample app described below for a detailed walk-through of how you may implement the Cloud Storage service.

The following SDK methods can be called from your client app:

  • Save a blob:

    Native - ovr_CloudStorage_Save()

    Unity - Platform.CloudStorage.Save()

    Data is stored as an opaque binary blob, review the ovr_CloudStorage_Save page for information about the parameters and return data structure.

    This call sends the blob data to the locally running Oculus process and will not trigger network calls. Network synchronization happens when the App is no longer running. Total size for a blob can not exceed 10Mb.

    Note: It is important, when sending a cloud save, that a local copy of the data is maintained until confirmation is received that the cloud save was successful. If an error occurs, the data contained in the request will be lost and you'll need to try again.
  • Load a blob:

    Native - ovr_CloudStorage_Load()

    Unity - Platform.CloudStorage.Load()

    Data is stored as an opaque binary blob, review the ovr_CloudStorage_Load page for information about the parameters and return data structure.

    If the bucket is configured for manual conflict resolution and a conflict exists between the local and remote versions, the load call will return an error. The process to resolve conflicts is discussed below. Loading a blob will not initiate a network call.

  • Delete a blob:

    Native - ovr_CloudStorage_Delete()

    Unity - Platform.CloudStorage.Delete()

    Data is stored as an opaque binary Blob, review the ovr_CloudStorage_Delete page for information about the parameters and return data structure.

    This will delete both the cloud and local copies of the blob. You may write new data to a deleted blob without waiting for synchronization.

  • Find a blob:

    You may want to retrieve some information about the available blobs to determine which one to load. The following methods allow you to retrieve the metadata for one or all saved data blobs.

    • Retrieve blob metadata for all blobs:

      Native - ovr_CloudStorage_LoadBucketMetadata(bucket_name)

      Unity - Platform.CloudStorage.LoadBucketMetadata(bucket_name)

      Review the ovr_CloudStorage_LoadBucketMetadata page for information about the parameters and return data structure.

    • Retrieve blob metadata for a specific blob:

      Native - ovr_CloudStorage_LoadMetadata(bucket_name, key)

      Unity - Platform.CloudStorage.LoadMetadata(bucket_name, key)

      Review the ovr_CloudStorage_LoadMetadata page for information about the parameters and return data structure.

Blob Metadata

Both of the metadata SDK methods will return results in the same format containing information you can use to determine which save you want to use or load.

The response payload will be in a format similar to the following:

uint32 data_size = ovr_CloudStorageMetadata_getDataSize(metadataHandle) 
uint64 saved_time = ovr_CloudStorageMetadata_getSaveTime(metadataHandle) 
int64 counter = ovr_CloudStorageMetadata_getCounter(metadataHandle) 
const char* extra_data = ovr_CloudStorageMetadata_getExtraData(metadataHandle) 
ovrCloudStorageVersionHandle handle = ovr_CloudStorageMetadata_getHandle(metadataHandle) 
ovrCloudStorageDataStatus status = ovr_CloudStorageMetadata_getStatus(metadataHandle)
  • data_size - The size, in bytes, of the stored data blob.
  • saved_time - the UTC time, in seconds, since the UNIX epoch when the blob was locally saved. This is the time as recorded on the local device so includes local clock skew.
  • counter - The value specified when saved, else zero.
  • extra_data - the value specified when saved, else null.
  • handle - used for manual conflict resolution (see below).
  • status - enum describing the state of the blob. This state as determined by the Oculus process's most recent network update. The following states are possible:
    • ovrCloudStorageDataStatus_InSync - the local and remote versions are in-sync.
    • ovrCloudStorageDataStatus_NeedsDownload - a newer version exists in the cloud but hasn't yet downloaded.
    • ovrCloudStorageDataStatus_NeedsUpload - the local version is newer and needs to be uploaded.
    • ovrCloudStorageDataStatus_InConflict - the local and remote version have a conflict that must be manually resolved. Only occurs for buckets set to manual conflict resolution.

Managing Conflicts

The Cloud Storage service supports synchronizing data between multiple devices and platforms. This requires a conflict resolution strategy to handle situations where multiple devices may upload blobs to the same key. This situation is common on mobile devices but can occur between PCs as well. The following resolution strategies are available:

Latest Timestamp

Resolving the conflict by using the latest timestamp is the least complex resolution. It configures the bucket to prefer the blob that has the timestamp recorded most recently by the local device. A timestamp is recorded at the time the call to ovr_CloudStorage_Save() is made. Client blobs with timestamps earlier than the remotely stored version are discarded.

Highest Counter

Buckets configured with the highest counter method will prefer blobs with the highest value set in the counter field. This method could be used if you wanted to preserve the blob with the highest score. Blobs stored with the same counter value as a remote version will attempt to be stored. However, multiple devices doing this represent a race-condition where either device may win.

Manual

You may also choose to handle conflict resolution entirely in your app. When an app saves a new local blob to a specific key that's in state ovrCloudStorageDataStatus_InConflict, the blob will not be uploaded until the app resolves the conflict. Conflict resolution can be done at any time but it's best done during App startup and shutdown. The need for manual conflict resolution can be detected by checking the metadata status, or by reviewing the save message response.

ovrCloudStorageUpdateResponseHandle response = ovr_Message_GetCloudStorageUpdateResponse(save_message) 
ovrCloudStorageUpdateStatus status = ovr_CloudStorageUpdateResponse_GetStatus(response)) 
if (status == ovrCloudStorageUpdateStatus_ManualMergeRequired) { // perform manual merge... }

The first step to resolving is to load the metadata for the conflicting blobs:

ovr_CloudStorage_LoadConflictMetadata(bucket, key)

This is an asynchronous call and the response message is parsed to get the metadata:

ovrCloudStorageConflictMetadataHandle response = ovr_Message_GetCloudStorageConflictMetadata(message) 
ovrCloudStorageMetadataHandle local_metadata = ovr_CloudStorageConflictMetadata_GetLocal(response) 
ovrCloudStorageMetadataHandle remote_metadata = ovr_CloudStorageConflictMetadata_GetRemote(response)
  • Resolving based on metadata

    If the metadata for the blob contains enough information to resolve the conflict, then the next step is to call:

    ovr_CloudStorage_ResolveKeepRemote(bucket_name, key, remote_handle)

    to choose the remote blob, or:

    ovr_CloudStorage_ResolveKeepLocal(bucket_name, key, remote_handle)

    to choose the local blob. The handle from the remote blob's metadata is passed in to prevent data loss in the instance that a new remote blob appears during conflict resolution.

  • Resolving by inspecting data

    If you need to inspect the data blobs to determine which to keep, they can be loaded using the handle from the metadata:

    ovr_CloudStorage_LoadHandle(handle)

    This works for both the local and remote handles. If the remote blob has not been cached locally, requesting the remote will initiate a network call to fetch any remaining data.

  • Resolving by merging the remote and local data

    If the app needs to merge the saved blobs, they can be loaded as described above, then the app can save a new local version and resolve by choosing that:

    ovr_CloudStorage_Save(bucket_name, key, merged_data_pointer, merged_data_size, counter, extra_data) 
    ovr_CloudStorage_ResolveKeepLocal(bucket_name, key, remote_handle)

Example Implementation

The CloudStorageSample Unity app provided in the Platform SDK download demonstrates using the Cloud Storage service to save multiple records and perform conflict resolution. Please see the Sample Apps page for more information about the apps that are available.