Unity SDK 튜토리얼

이 튜토리얼은 Unity에서 Cloud Save SDK를 사용하여 데이터를 저장하고 로드하는 방법을 보여 줍니다.

참고: 이 기능은 Cloud Save SDK 버전 3부터 사용할 수 있습니다.

Unity에서 Cloud Save 사용

Unity 내의 C# 스크립트에서 Cloud Save SDK를 호출할 수 있습니다.

  1. Unity 내에서 C# MonoBehaviour 스크립트를 생성합니다.
  2. Cloud Save에서 데이터를 저장/로드하는 코드를 추가합니다(아래 예제 참고).
  3. 새로 만든 스크립트를 게임 오브젝트에 연결합니다.
  4. Play를 선택하여 프로젝트를 실행하고 Cloud Save를 실제로 경험해 봅니다.

Unity의 스크립팅에 관한 자세한 내용은 스크립트 생성 및 사용을 참고하십시오.

SDK 샘플

SDK에 포함된 CloudSaveSample 스크립트는 이 튜토리얼에 제공된 예제를 확장한 것입니다. Unity에서 Package ManagerCloud SaveSamples를 선택하여 샘플을 확인할 수 있습니다.

인증 예제

다음 예제는 Authentication 패키지를 사용하여 익명 인증으로 플레이어를 로그인하는 방법과, Cloud Save를 초기화하는 방법을 보여 주며, 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>()}");
        }
    }
}

플레이어 데이터

Unity Cloud Dashboard에서 플레이어의 데이터를 조회하고, 수정하고, 삭제할 수 있습니다.

항목 저장

SaveAsync 메서드를 사용하여 하나 이상의 항목을 저장할 수 있습니다.

public async void SaveData()
{
    var data = new Dictionary<string, object>{{"keyName", "value"}};
    await CloudSaveService.Instance.Data.Player.SaveAsync(data);
}

다른 플레이어가 해당 데이터를 읽을 수 있도록 하려면, 공개 액세스 클래스에 데이터를 저장할 수 있습니다.

public async void SavePublicData()
{
    var data = new Dictionary<string, object>{{"keyName", "value"}};
    await CloudSaveService.Instance.Data.Player.SaveAsync(data, new SaveOptions(new PublicWriteAccessClassOptions()));
}

데이터 가져오기

LoadAsync 메서드를 사용하여 플레이어 데이터로 저장된 키와 값을 가져올 수 있습니다.

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

공개보호 액세스 클래스의 데이터에 대한 키와 값을 가져올 수 있습니다.

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

플레이어 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>()}");
  }
}

항목 삭제

DeleteAsync 메서드를 사용하여 항목을 삭제할 수 있습니다.

public async void DeleteData()
{
    await CloudSaveService.Instance.Data.Player.DeleteAsync("key");
}

키 목록 가져오기

ListAllKeysAsync 메서드를 사용하여 키 목록을 가져올 수 있습니다.

또한 키가 마지막으로 수정된 시간과 같은 메타데이터를 가져올 수 있습니다.

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

공개보호 액세스 클래스의 데이터에 대한 키 목록도 확인할 수 있습니다.

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

플레이어 데이터 쿼리

플레이어 데이터의 공개 액세스 클래스에 있는 인덱싱된 키 값을 쿼리할 수 있습니다.

인덱스가 생성되기 전에 저장된 데이터(또는 인덱싱할 수 없을 만큼 큰 데이터)는 쿼리에서 반환되지 않습니다.

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

게임 데이터

플레이어와 관련되지 않은 게임 데이터커스텀 아이템을 사용하여 저장하고 불러올 수 있습니다.

게임 클라이언트는 커스텀 아이템을 읽기만 할 수 있습니다. 커스텀 아이템을 생성하거나 수정하거나 삭제할 수는 없습니다. 커스텀 아이템은 Cloud Code, 게임 서버, HTTP API 또는 Unity Cloud Dashboard를 사용하여 쓸 수 있습니다.

데이터 가져오기

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

커스텀 아이템 쿼리

커스텀 아이템의 기본 액세스 클래스에 있는 인덱싱된 키 값을 쿼리할 수 있습니다.

인덱스가 생성되기 전에 저장된 데이터(또는 인덱싱할 수 없을 만큼 큰 데이터)는 쿼리에서 반환되지 않습니다.

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

플레이어 파일

Cloud Save 파일은 대규모 저장 파일(최대 1GB)을 어떤 형식으로든 저장하는 방법과 여러 디바이스와 플랫폼에서 저장된 게임 파일에 액세스할 수 있는 방법을 제공합니다.

플레이어 파일 저장

디바이스에 로컬로 저장된 파일을 읽고 SaveAsync 메서드를 사용하여 Cloud Save에 저장할 수 있습니다.

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

플레이어 파일 삭제

API 클라이언트 DeleteAsync 메서드를 사용해 플레이어 파일을 삭제할 수 있습니다.

public async void DeletePlayerFile()
{
    await CloudSaveService.Instance.Files.Player.DeleteAsync("fileName");
}

플레이어 파일 나열

ListAllAsync 메서드를 사용해 플레이어의 모든 파일 이름 목록을 가져올 수 있습니다.

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

플레이어 파일을 바이트 배열로 가져오기

LoadBytesAsync 메서드를 사용해 플레이어 파일을 바이트 배열로 가져올 수 있습니다.

public async void GetPlayerFileAsByteArray()
{
    byte[] file = await CloudSaveService.Instance.Files.Player.LoadBytesAsync("fileName");
}

플레이어 파일을 스트림으로 가져오기

LoadStreamAsync 메서드를 사용해 플레이어 파일을 스트림으로 가져올 수 있습니다.

public async void GetPlayerFileAsStream()
{
    Stream file = await CloudSaveService.Instance.Files.Player.LoadStreamAsync("fileName");
}

플레이어 파일 메타데이터 가져오기

GetMetadataAsync 메서드를 사용해 단일 플레이어 파일의 메타데이터(크기, 마지막 수정일과 생성일, 키, 콘텐츠 유형, 현재 WriteLock)를 검색합니다.

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

Unity Dashboard를 사용하여 개별 플레이어의 파일을 액세스할 수 있습니다. 이 파일들은 Cloud Save 모듈의 플레이어 세부 정보에서 확인할 수 있습니다.

오류 처리

오류 처리 로직에서 SDK가 메서드에 대해 반환하는 오류 코드나 유형을 사용합니다.

추후 변경될 수 있으므로 오류 메시지는 사용하지 않는 것이 좋습니다.