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