Unity SDK sample
Refer to sample code that shows how to save and load data with the Cloud Save Software Development Kit.
Read time 4 minutesLast updated 2 days ago
This sample shows how to use the Cloud Save SDK to save and load data. You can find the sample in Unity by selecting Package Manager > Cloud Save > Samples.
using System;using System.Collections.Generic;using System.IO;using System.Text;using System.Threading.Tasks;using Unity.Services.Authentication;using Unity.Services.CloudSave;using Unity.Services.CloudSave.Models;using Unity.Services.Core;using UnityEngine;namespace CloudSaveSample{ [Serializable] public class SampleObject { public string SophisticatedString; public int SparklingInt; public float AmazingFloat; } public class CloudSaveSample : MonoBehaviour { private async void Awake() { // Cloud Save needs to be initialized along with the other Unity Services that // it depends on (namely, Authentication), and then the user must sign in. await UnityServices.InitializeAsync(); await AuthenticationService.Instance.SignInAnonymouslyAsync(); // Player Data // first set of data saved without a write lock await ForceSaveSingleData("primitive_key", "value!"); SampleObject firstSample = new SampleObject { AmazingFloat = 13.37f, SparklingInt = 1337, SophisticatedString = "hi there!" }; string objectKey = "object_key"; string writeLock = await ForceSaveObjectData(objectKey, firstSample); SampleObject incomingSample = await RetrieveSpecificData<SampleObject>(objectKey); Debug.Log( $"Loaded sample object: {incomingSample.AmazingFloat}, {incomingSample.SparklingInt}, {incomingSample.SophisticatedString}, write lock {writeLock}" ); // second set of data saved with a write lock SampleObject secondSample = new SampleObject { AmazingFloat = 42.26f, SparklingInt = 4226, SophisticatedString = "hi there... again!" }; string updatedWriteLock = await SaveObjectData(objectKey, secondSample, writeLock); SampleObject updatedSample = await RetrieveSpecificData<SampleObject>(objectKey); Debug.Log( $"Loaded updated sample object: {updatedSample.AmazingFloat}, {updatedSample.SparklingInt}, {updatedSample.SophisticatedString}, write lock {updatedWriteLock}" ); // deletion with wrong write lock, this will fail with a validation error await DeleteSpecificData(objectKey, "incorrect-write-lock"); // force delete without write lock await ForceDeleteSpecificData(objectKey); await ListAllKeys(); await RetrieveEverything(); // Custom Data, read-only string customTestId = "custom-test-id"; await ListAllCustomKeys(customTestId); await RetrieveAllCustomData(customTestId); // Files var inputBytes = Encoding.UTF8.GetBytes("test content for file bytes"); var inputStream = new MemoryStream( Encoding.UTF8.GetBytes("test content for file stream") ); string bytesFileKey = "bytes-test-file"; string streamFileKey = "stream-test-file"; await SaveFileBytes(bytesFileKey, inputBytes); await SaveFileStream(streamFileKey, inputStream); await ListAllFiles(); await GetFileMetadata(bytesFileKey); await GetFileMetadata(streamFileKey); var fileBytes = await LoadFileBytes(bytesFileKey); Debug.Log( $"Loaded sample file containing content: {Encoding.UTF8.GetString(fileBytes)}" ); using var fileStream = await LoadFileStream(streamFileKey); using var streamReader = new StreamReader(fileStream); Debug.Log( $"Loaded sample file containing content: {await streamReader.ReadToEndAsync()}" ); await DeleteFile(bytesFileKey); await DeleteFile(streamFileKey); } private async Task ListAllKeys() { try { var keys = await CloudSaveService.Instance.Data.Player.ListAllKeysAsync(); Debug.Log($"Keys count: {keys.Count}\n" + $"Keys: {String.Join(", ", keys)}"); } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task ListAllCustomKeys(string customId) { try { var keys = await CloudSaveService.Instance.Data.Custom.ListAllKeysAsync(customId); Debug.Log( $"Keys count for custom ID {customId}: {keys.Count}\n" + $"Keys: {String.Join(", ", keys)}" ); } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task ForceSaveSingleData(string key, string value) { try { Dictionary<string, object> oneElement = new Dictionary<string, object>(); // It's a text input field, but let's see if you actually entered a number. if (Int32.TryParse(value, out int wholeNumber)) { oneElement.Add(key, wholeNumber); } else if (Single.TryParse(value, out float fractionalNumber)) { oneElement.Add(key, fractionalNumber); } else { oneElement.Add(key, value); } // Saving the data without write lock validation by passing the data as an object instead of a SaveItem Dictionary<string, string> result = await CloudSaveService.Instance.Data.Player.SaveAsync(oneElement); Debug.Log( $"Successfully saved {key}:{value} with updated write lock {result[key]}" ); } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task<string> ForceSaveObjectData(string key, SampleObject value) { try { // Although we are only saving a single value here, you can save multiple keys // and values in a single batch. Dictionary<string, object> oneElement = new Dictionary<string, object> { { key, value } }; // Saving data without write lock validation by passing the data as an object instead of a SaveItem Dictionary<string, string> result = await CloudSaveService.Instance.Data.Player.SaveAsync(oneElement); string writeLock = result[key]; Debug.Log($"Successfully saved {key}:{value} with updated write lock {writeLock}"); return writeLock; } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } return null; } private async Task<string> SaveObjectData(string key, SampleObject value, string writeLock) { try { // Although we are only saving a single value here, you can save multiple keys // and values in a single batch. // Use SaveItem to specify a write lock. The request will fail if the provided write lock // does not match the one currently saved on the server. Dictionary<string, SaveItem> oneElement = new Dictionary<string, SaveItem> { { key, new SaveItem(value, writeLock) } }; // Saving data with write lock validation by using a SaveItem with the write lock specified Dictionary<string, string> result = await CloudSaveService.Instance.Data.Player.SaveAsync(oneElement); string newWriteLock = result[key]; Debug.Log( $"Successfully saved {key}:{value} with updated write lock {newWriteLock}" ); return newWriteLock; } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } return null; } private async Task<T> RetrieveSpecificData<T>(string key) { try { var results = await CloudSaveService.Instance.Data.Player.LoadAsync( new HashSet<string> { key } ); if (results.TryGetValue(key, out var item)) { return item.Value.GetAs<T>(); } else { Debug.Log($"There is no such key as {key}!"); } } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } return default; } private async Task RetrieveEverything() { try { // If you wish to load only a subset of keys rather than everything, you // can call a method LoadAsync and pass a HashSet of keys into it. var results = await CloudSaveService.Instance.Data.Player.LoadAllAsync(); Debug.Log($"{results.Count} elements loaded!"); foreach (var result in results) { Debug.Log($"Key: {result.Key}, Value: {result.Value.Value}"); } } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task RetrieveAllCustomData(string customId) { try { // If you wish to load only a subset of keys rather than everything, you // can call a method LoadAsync and pass a HashSet of keys into it. var results = await CloudSaveService.Instance.Data.Custom.LoadAllAsync(customId); Debug.Log($"{results.Count} elements loaded from custom Id {customId}!"); foreach (var result in results) { Debug.Log($"Key: {result.Key}, Value: {result.Value.Value}"); } } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task ForceDeleteSpecificData(string key) { try { // Deletion of the key without write lock validation by omitting the DeleteOptions argument await CloudSaveService.Instance.Data.Player.DeleteAsync(key); Debug.Log($"Successfully deleted {key}"); } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task DeleteSpecificData(string key, string writeLock) { try { // Deletion of the key with write lock validation await CloudSaveService.Instance.Data.Player.DeleteAsync( key, new DeleteOptions { WriteLock = writeLock } ); Debug.Log($"Successfully deleted {key}"); } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task ListAllFiles() { try { var results = await CloudSaveService.Instance.Files.Player.ListAllAsync(); Debug.Log("Metadata loaded for all files!"); foreach (var element in results) { Debug.Log($"Key: {element.Key}, File Size: {element.Size}"); } } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task GetFileMetadata(string key) { try { var results = await CloudSaveService.Instance.Files.Player.GetMetadataAsync(key); Debug.Log("File metadata loaded!"); Debug.Log($"Key: {results.Key}, File Size: {results.Size}"); } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task SaveFileBytes(string key, byte[] bytes) { try { await CloudSaveService.Instance.Files.Player.SaveAsync(key, bytes); Debug.Log("File saved!"); } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task SaveFileStream(string key, Stream stream) { try { await CloudSaveService.Instance.Files.Player.SaveAsync(key, stream); Debug.Log("File saved!"); } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } private async Task<byte[]> LoadFileBytes(string key) { try { var results = await CloudSaveService.Instance.Files.Player.LoadBytesAsync(key); Debug.Log("File loaded!"); return results; } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } return null; } private async Task<Stream> LoadFileStream(string key) { try { var results = await CloudSaveService.Instance.Files.Player.LoadStreamAsync(key); Debug.Log("File loaded!"); return results; } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } return null; } private async Task DeleteFile(string key) { try { await CloudSaveService.Instance.Files.Player.DeleteAsync(key); Debug.Log("File deleted!"); } catch (CloudSaveValidationException e) { Debug.LogError(e); } catch (CloudSaveRateLimitedException e) { Debug.LogError(e); } catch (CloudSaveException e) { Debug.LogError(e); } } }}