Documentation

Support

Unity SDK tutorial

Use the Cloud Save Software Development Kit to save and load player data, game data, and files in your Unity project.
Read time 5 minutesLast updated 2 days ago

This tutorial shows how to use the Cloud Save SDK to save and load data in Unity.

Using Cloud Save from Unity

You can call the Cloud Save SDK from a C# script within Unity.
  1. Create a C# MonoBehaviour script within Unity.
  2. Add code to Save/Load data from Cloud Save (refer to the example below).
  3. Attach the newly made script to a game object.
  4. Select Play to run the project to experience Cloud Save in action.
To learn more about scripting in Unity, refer to Creating and Using Scripts.

SDK sample

The
CloudSaveSample
script included with the SDK expands on the examples given in this tutorial. You can find the sample in Unity by selecting Package ManagerCloud SaveSamples.

Example with authentication

The following example demonstrates how to sign in a player with anonymous authentication using the Authentication package, initialize Cloud Save and provides methods that save and load data with Cloud Save.
using UnityEngine;using Unity.Services.Core;using Unity.Services.Authentication;using Unity.Services.CloudSave;using Unity.Services.CloudSave.Models;using Unity.Services.CloudSave.Models.Data.Player;using SaveOptions = Unity.Services.CloudSave.Models.Data.Player.SaveOptions;using System.Collections.Generic;public class CloudSaveSample : MonoBehaviour{ private async void Awake() { await UnityServices.InitializeAsync(); await AuthenticationService.Instance.SignInAnonymouslyAsync(); } public async void SaveData() { var playerData = new Dictionary<string, object>{ {"firstKeyName", "a text value"}, {"secondKeyName", 123} }; await CloudSaveService.Instance.Data.Player.SaveAsync(playerData); Debug.Log($"Saved data {string.Join(',', playerData)}"); } public async void LoadData() { var playerData = await CloudSaveService.Instance.Data.Player.LoadAsync(new HashSet<string> { "firstKeyName", "secondKeyName" }); if (playerData.TryGetValue("firstKeyName", out var firstKey)) { Debug.Log($"firstKeyName value: {firstKey.Value.GetAs<string>()}"); } if (playerData.TryGetValue("secondKeyName", out var secondKey)) { Debug.Log($"secondKey value: {secondKey.Value.GetAs<int>()}"); } }}

Player Data

You can view, edit and delete data for player in the Unity Dashboard.

Save an item

Save one or more items using the
SaveAsync
method.
public async void SaveData(){ var data = new Dictionary<string, object>{{"keyName", "value"}}; await CloudSaveService.Instance.Data.Player.SaveAsync(data);}
You can save data in the Public Access Class, if you want other players to be able to read that data.
public async void SavePublicData(){ var data = new Dictionary<string, object>{{"keyName", "value"}}; await CloudSaveService.Instance.Data.Player.SaveAsync(data, new SaveOptions(new PublicWriteAccessClassOptions()));}

Fetch data

Get keys and values stored as Player Data using the
LoadAsync
method.
public async void LoadData(){ var playerData = await CloudSaveService.Instance.Data.Player.LoadAsync(new HashSet<string>{"keyName"}); if (playerData.TryGetValue("keyName", out var keyName)) { Debug.Log($"keyName: {keyName.Value.GetAs<string>()}"); }}
You can get keys and values for data in the Public and Protected Access Classes.
public async void LoadPublicData(){ var playerData = await CloudSaveService.Instance.Data.Player.LoadAsync(new HashSet<string>{"keyName"}, new LoadOptions(new PublicReadAccessClassOptions())); if (playerData.TryGetValue("keyName", out var keyName)) { Debug.Log($"keyName: {keyName.Value.GetAs<string>()}"); }}
public async void LoadProtectedData(){ var playerData = await CloudSaveService.Instance.Data.Player.LoadAsync(new HashSet<string>{"keyName"}, new LoadOptions(new ProtectedReadAccessClassOptions())); if (playerData.TryGetValue("keyName", out var keyName)) { Debug.Log($"keyName: {keyName.Value.GetAs<string>()}"); }}
You can read (but not write to) data in the Public Access Class of another player by passing a Player ID.
public async void LoadPublicDataByPlayerId(){ var playerId = "JE1unrWOOzzbIwy3Nl60fRefuiVE"; var playerData = await CloudSaveService.Instance.Data.Player.LoadAsync(new HashSet<string>{"keyName"}, new LoadOptions(new PublicReadAccessClassOptions(playerId))); if (playerData.TryGetValue("keyName", out var keyName)) { Debug.Log($"keyName: {keyName.Value.GetAs<string>()}"); }}

Delete an item

Delete items using the
DeleteAsync
method.
public async void DeleteData(){ await CloudSaveService.Instance.Data.Player.DeleteAsync("key");}

Get a list of keys

Use the
ListAllKeysAsync
method to get a list of keys.
You can also fetch metadata, such as the last time a key was modified.
public async void ListKeys(){ var keys = await CloudSaveService.Instance.Data.Player.ListAllKeysAsync(); for (int i = 0; i < keys.Count; i++) { Debug.Log(keys[i].Key); }}
You can also list keys for data in the Public and Protected Access Classes.
public async void ListKeys(){ var keys = await CloudSaveService.Instance.Data.Player.ListAllKeysAsync( new ListAllKeysOptions(new PublicReadAccessClassOptions()) ); for (int i = 0; i < keys.Count; i++) { Debug.Log(keys[i].Key); }}
public async void ListKeys(){ var keys = await CloudSaveService.Instance.Data.Player.ListAllKeysAsync( new ListAllKeysOptions(new ProtectedReadAccessClassOptions()) ); for (int i = 0; i < keys.Count; i++) { Debug.Log(keys[i].Key); }}

Query Player Data

Query values for any indexed key in the Player Data Public Access Class.
public async void QueryPlayerData(){ var query = new Query( // The first argument to Query is a list of one or more filters, all must evaluate to true for a result to be included new List<FieldFilter> { new FieldFilter("indexedKeyName", "value", FieldFilter.OpOptions.EQ, true), new FieldFilter("anotherIndexedKeyName", "otherValue", FieldFilter.OpOptions.NE, true) }, // The second (optional) argument is a list of keys you want to be included with their values in the response // This may include keys which are not part of the index, and does not need to include the index keys // If you don't specify any, you will still get back a list of IDs for Players that matched the query new HashSet<string> { "indexedKeyName" } ); var results = await CloudSaveService.Instance.Data.Player.QueryAsync(query, new QueryOptions()); Debug.Log($"Number of results from query: {results.Count}"); results.ForEach(r => { Debug.Log($"Player ID: {r.Id}"); r.Data.ForEach(d => Debug.Log($"Key: {d.Key}, Value: {d.Value.GetAsString()}")); });}

Game Data

You can save and load Game Data that is not player-specific by using a Custom Item.

Fetch data

Fetch all data for a Custom Item using
LoadAllAsync
.
public async void LoadCustomItemData(){ var customItemId = "my-custom-item"; var customItemData = await CloudSaveService.Instance.Data.Custom.LoadAllAsync(customItemId); foreach (var customItem in customItemData) { Debug.Log($"Key: {customItem.Key}, Value: {customItem.Value.Value}"); }}

Query Custom Items

Query values for any indexed key in the Custom Item Default Access Class.
public async void QueryCustomItems(){ var query = new Query( // The first argument to Query is a list of one or more filters, all must evaluate to true for a result to be included new List<FieldFilter> { new FieldFilter("indexedKeyName", "value", FieldFilter.OpOptions.EQ, true), new FieldFilter("anotherIndexedKeyName", "otherValue", FieldFilter.OpOptions.NE, true) }, // The second (optional) argument is a list of keys you want to be included with their values in the response // This may include keys which are not part of the index, and does not need to include the index keys // If you don't specify any, you will still get back a list of IDs for Players that matched the query new HashSet<string> { "indexedKeyName" } ); var results = await CloudSaveService.Instance.Data.Custom.QueryAsync(query); Debug.Log($"Number of results from query: {results.Count}"); results.ForEach(r => { Debug.Log($"Custom Item ID: {r.Id}"); r.Data.ForEach(d => Debug.Log($"Key: {d.Key}, Value: {d.Value.GetAsString()}")); });}

Player Files

Cloud Save Files provides a way to store large save files (up to 1 GB) in any format and to access save game files across multiple devices / platforms.

Save Player File

Read in a locally saved file on a device and save to Cloud Save using the
SaveAsync
method.
Files can be passed in as a byte array or a stream.
public async void SavePlayerFileBytes(){ byte[] fileBytes = System.IO.File.ReadAllBytes("fileName.txt"); await CloudSaveService.Instance.Files.Player.SaveAsync("fileByteName", fileBytes);}
public async void SavePlayerFileStream(){ Stream fileStream = System.IO.File.OpenRead("fileName.txt"); await CloudSaveService.Instance.Files.Player.SaveAsync("fileStreamName", fileStream);}

Save Player File options

The
SaveAsync
method accepts two options via the
SaveOptions
object:
WriteLock
and
RequestTimeout
.
The
WriteLock
is an alphanumerical string which is returned by read and write operations, and can be used for conflict detection and mitigation. If the write lock is specified and it doesn't match what's in the Cloud Save service, the service returns an error to indicate that the value in the service has been updated since the last time you retrieved the write lock.
The
RequestTimeout
is an SDK-level timeout in seconds, which can be used to detect long-running uploads. It defaults to 10s but can be customised for larger files or to account for slow connections.
public async void SavePlayerFileWithOptions(){ Stream file = System.IO.File.OpenRead("fileName.txt"); await CloudSaveService.Instance.Files.Player.SaveAsync("fileName", file, new Unity.Services.CloudSave.SaveOptions { WriteLock = "27efb4b1b27a732c0e32a6229ec52776" RequestTimeout = 60 });}

Delete Player File

Delete a player file using the
DeleteAsync
method.
public async void DeletePlayerFile(){ await CloudSaveService.Instance.Files.Player.DeleteAsync("fileName");}

List Player Files

Use the
ListAllAsync
method to get a list of names of all files for a player.
public async void ListPlayerFiles(){ List<FileItem> files = await CloudSaveService.Instance.Files.Player.ListAllAsync(); for (int i = 0; i < files.Count; i++) { Debug.Log(files[i]); }}

Get Player File as a byte array

Get player file as a byte array with the
LoadBytesAsync
method.
public async void GetPlayerFileAsByteArray(){ byte[] file = await CloudSaveService.Instance.Files.Player.LoadBytesAsync("fileName");}

Get Player File as a stream

Get player file as a stream with the
LoadStreamAsync
method.
public async void GetPlayerFileAsStream(){ Stream file = await CloudSaveService.Instance.Files.Player.LoadStreamAsync("fileName");}

Get Player File Metadata

Retrieves the metadata (size, date last modified and created, key, content type, and current WriteLock) of a single player file with the
GetMetadataAsync
method.
public async void GetPlayerFileMetadata(){ var metadata = await CloudSaveService.Instance.Files.Player.GetMetadataAsync("fileName"); Debug.Log(metadata.Key); Debug.Log(metadata.Size); Debug.Log(metadata.ContentType); Debug.Log(metadata.Created); Debug.Log(metadata.LastModified); Debug.Log(metadata.WriteLock);}
You can use the Unity Dashboard to access the files of an individual player. You can find these files under the player details in the Cloud Save module.

Error handling

Use the error code or type that the SDK returns for a method in your error handling logic. Avoid using error messages as they might change in the future.