Search documentation

Find pages, sections, and content across all docs.

WavedashDocs

Cloud saves

Save and sync player data across sessions and devices

Cloud saves use the Remote Storage API: per-player files in the cloud, synced across devices. The SDK methods are named uploadRemoteFile, downloadRemoteFile, and similar.

Upload and download files

func save_to_cloud(file_name: String):
    var path = OS.get_user_data_dir() + "/" + file_name
    WavedashSDK.upload_remote_file(path)

func load_from_cloud(file_name: String):
    var path = OS.get_user_data_dir() + "/" + file_name
    WavedashSDK.download_remote_file(path)
public async void SaveToCloud(string localPath)
{
    await Wavedash.SDK.UploadRemoteFile(localPath);
}

public async void LoadFromCloud(string localPath)
{
    await Wavedash.SDK.DownloadRemoteFile(localPath);
}
const data = new TextEncoder().encode(JSON.stringify(gameState));
await Wavedash.writeLocalFile("saves/slot1.json", data);
await Wavedash.uploadRemoteFile("saves/slot1.json");

const dl = await Wavedash.downloadRemoteFile("saves/slot1.json");
if (dl.success) {
  const bytes = await Wavedash.readLocalFile("saves/slot1.json");
}

Paths may be either user://... (auto-normalized) or absolute paths under OS.get_user_data_dir(). Paths outside the user data directory are rejected.

Signals. Each call emits a response signal when it resolves — connect to them once in _ready() if you prefer signal-based flow over await:

func _ready():
    WavedashSDK.remote_file_uploaded.connect(func(r): print("Uploaded: ", r.data))
    WavedashSDK.remote_file_downloaded.connect(func(r): print("Downloaded: ", r.data))
    WavedashSDK.remote_directory_downloaded.connect(func(r): print("Dir: ", r.data))
    WavedashSDK.got_remote_directory_listing.connect(func(r): print(r.data))

Deleting files

const result = await Wavedash.deleteRemoteFile("saves/slot1.json");
if (result.success) {
  console.log("Deleted:", result.data);
}

deleteRemoteFile is currently only exposed on the JavaScript SDK. From Unity and Godot, call Wavedash.deleteRemoteFile(...) through your engine's JS interop (JSLib for Unity, JavaScriptBridge for Godot).

Directories

func download_save_folder():
    var path = OS.get_user_data_dir() + "/saves/"
    WavedashSDK.download_remote_directory(path)

func list_remote_saves():
    var path = OS.get_user_data_dir() + "/saves/"
    WavedashSDK.list_remote_directory(path)
var path = $"{Application.persistentDataPath}/saves/";
await Wavedash.SDK.DownloadRemoteDirectory(path);

var files = await Wavedash.SDK.ListRemoteDirectory(path);
await Wavedash.downloadRemoteDirectory("saves/");

const list = await Wavedash.listRemoteDirectory("saves/");

File metadata

interface RemoteFileMetadata {
  exists: boolean;
  key: string;
  name: string;
  lastModified: number;
  size: number;
  etag: string;
}

Path conventions

Use forward slashes in remote keys, even on Windows builds.

saves/slot1.json
settings.json
replays/run-001.dat

Remote keys are relative to the player root. Keep names short and stable so you can migrate formats later.

Full save system example

const SAVE_VERSION = 2
var save_root: String

func _ready():
    save_root = OS.get_user_data_dir() + "/saves/"

func cloud_save(slot: int, game_state: Dictionary) -> void:
    var payload = {"version": SAVE_VERSION, "timestamp": Time.get_unix_time_from_system(), "state": game_state}
    var path = save_root + "slot" + str(slot) + ".json"
    DirAccess.make_dir_recursive_absolute(save_root)
    var file = FileAccess.open(path, FileAccess.WRITE)
    file.store_string(JSON.stringify(payload))
    file.close()
    WavedashSDK.upload_remote_file(path)

func cloud_load(slot: int) -> void:
    var path = save_root + "slot" + str(slot) + ".json"
    WavedashSDK.download_remote_file(path)
public async Task<bool> Save(int slot, Dictionary<string, object> gameState)
{
    var payload = new Dictionary<string, object>
    {
        { "version", 2 },
        { "timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds() },
        { "state", gameState }
    };
    var path = $"{Application.persistentDataPath}/saves/slot{slot}.json";
    Directory.CreateDirectory(Path.GetDirectoryName(path));
    File.WriteAllText(path, JsonConvert.SerializeObject(payload));
    var result = await Wavedash.SDK.UploadRemoteFile(path);
    return !string.IsNullOrEmpty(result);
}
async function cloudSave(slot, gameState) {
  const payload = { version: 2, timestamp: Date.now(), state: gameState };
  const path = `saves/slot${slot}.json`;
  await Wavedash.writeLocalFile(path, new TextEncoder().encode(JSON.stringify(payload)));
  return (await Wavedash.uploadRemoteFile(path)).success;
}