-
Notifications
You must be signed in to change notification settings - Fork 0
Examples
Quick-start code showing how to use libsavesync from C and from Python via the IPC binary.
All examples use fictional identifiers only — no real game titles or IDs.
#include "savesync.h"
int main(void) {
// Initialize with a directory for versioned storage
sv_init("/tmp/savesync-data");
// Load an emulator manifest (auto-detects game identity)
sv_manifest_t *manifest = sv_manifest_create();
sv_manifest_load("manifests/dolphin_gc.cfg", manifest);
// Register a save — game ID is extracted from the ROM header
sv_register_opts_t opts = {0};
opts.live_path = "/path/to/save/TEST01";
sv_status_t st;
sv_registration_t *reg = sv_register_with_manifest(&opts, manifest, &st);
// Snapshot the current save into the versioned magazine
sv_save_result_t save_result;
sv_save(reg, NULL, &save_result);
// save_result.entry_id now holds the new entry's ID
// save_result.entry_created is true on first save
// Pull (restore) the latest saved version to the live path
sv_pull_result_t pull_result;
sv_pull(reg, NULL, &pull_result);
// pull_result.did_pull is true if a restore happened
// List all saved versions
sv_id_t ids[64];
size_t count;
sv_list_entries(save_result.entry_id, ids, 64, &count);
sv_shutdown();
return 0;
}Build: make static && cc -o myapp main.c -Lbuild -lsavesync -Iinclude
import json, subprocess, tempfile, os
proc = subprocess.Popen(["build/savesync-ipc"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
def send(method, params=None):
msg = {"id": method, "method": method}
if params: msg["params"] = params
proc.stdin.write(json.dumps(msg) + "\n")
proc.stdin.flush()
return json.loads(proc.stdout.readline())
with tempfile.TemporaryDirectory() as tmpdir:
os.makedirs(os.path.join(tmpdir, "live_save"))
with open(os.path.join(tmpdir, "live_save", "data.bin"), "wb") as f:
f.write(b"SYNTHETIC_SAVE_V1")
send("init", {"base_path": os.path.join(tmpdir, "data")})
resp = send("manifest_load", {"path": "manifests/dolphin_gc.cfg"})
mid = resp["result"]["manifest_id"]
resp = send("register_with_manifest", {
"manifest_id": mid,
"live_path": os.path.join(tmpdir, "live_save", "data.bin"),
"shape": "file",
})
rid = resp["result"]["registration_id"]
resp = send("save", {"registration_id": rid})
print(f"Saved: {resp['result']['entry_id']}")
resp = send("pull", {"registration_id": rid})
print(f"Pull: did_pull={resp['result']['did_pull']}")
send("shutdown")See examples/python_client.py for the full, runnable example.
This walkthrough uses the Dolphin GC manifest to register a GameCube save automatically:
-
Load the manifest —
manifests/dolphin_gc.cfgtells the library to useSV_IDENTITY_ROM_HEADER, reading 4 bytes from the ROM file at a fixed offset to extract the game ID. -
Register with
live_path— pointlive_pathat a GameCube save file (e.g. a.gcifile). The library reads the ROM header and extracts the game ID automatically — no manualgame_idconfiguration needed. -
Save — the library copies the save into a versioned magazine entry with a unique ID, computing a content hash for deduplication.
-
Pull — restores the latest (or a specific) magazine entry back to the live path via atomic copy (temp file + rename), never touching the live file in-place.
The same pattern works for any of the 8 supported manifests. For emulators where identity is caller-supplied (DuckStation, RetroArch SNES, PCSX2 file mode), simply set game_id in the register options instead of relying on manifest-based detection.
See also: API-Reference | Testing-Guide | Layer-1-Interface
libsavesync Wiki