Unity SDK tutorial

This tutorial shows how to use the Cloud Save SDK 3.1 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 Cloud Save logic 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.

The CloudSaveSample script included with the SDK expands on the examples given here. 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 System.Collections.Generic;
using Unity.Services.Authentication;
using Unity.Services.CloudSave;
using Unity.Services.CloudSave.Models;
using Unity.Services.Core;
using UnityEngine;

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

using SaveOptions = Unity.Services.CloudSave.Models.Data.Player.SaveOptions;

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

Query Player Data

Query values for any indexed key in the Player Data Public Access Class.

Data saved before an index was created (or that is too large to be indexed) will not be returned from a query.

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

  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.

Game clients can only read custom items. They cannot create, modify or delete Custom items. Custom Items can be written to using Cloud Code, a game server, using the HTTP API or from the Unity Cloud Dashboard.

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(customId);
  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.

Data saved before an index was created (or that is too larged to be indexed) will not be returned from a query.

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.

public async void SavePlayerFile()
{
    byte[] file = System.IO.File.ReadAllBytes("fileName.txt");
    await CloudSaveService.Instance.Files.Player.SaveAsync("fileName", file);
}

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<string> 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 Cloud Dashboard to access the files of an individual player. You can find these files under the player details in the Cloud Save module in the LiveOps section.

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.