-
Notifications
You must be signed in to change notification settings - Fork 0
Layer 2 Registration and Identity
Registration is how the library learns about a save file. Identity resolution determines what game a save belongs to.
sv_register() creates a new registration from a live_save_path (required) plus optional metadata:
-
rom_path— path to the ROM/disc image -
platform— target platform identifier -
emulator— emulator name/version -
product_version— emulator/core/backend version -
mode—SV_MODE_DEFAULTorSV_MODE_STRATEGY
Produces an opaque sv_registration_t* handle and a persistent 8-character unique ID.
sv_register_with_manifest() accepts an optional sv_manifest_t that drives identity resolution at registration time. When a manifest is provided:
- Platform/emulator/shape are filled from the manifest if not supplied by the caller
- Identity resolution runs automatically using the manifest's configured method
- The resolved
game_idis stored on the registration - If resolution fails,
game_idstays NULL (non-fatal) - If
save_path_templateis set, it is resolved and stored for magazine path organization
When no manifest is provided (NULL), sv_register_with_manifest() behaves identically to sv_register() — it's a safe fallback.
sv_update_register() mutates an existing registration using an explicit set_mask bitfield. The bitfield distinguishes "leave unchanged" from "explicitly reset to default/empty," since update semantics can't rely on zero-default alone.
Includes a "poke check" against the destination path: reports SV_CONFLICT_EXISTING_DATA by default rather than guessing. Caller can pass SV_ON_CONFLICT_OVERRIDE or SV_ON_CONFLICT_ABORT_SILENT explicitly.
Relocation supports:
-
SV_RELOCATE_COPY(default, non-destructive) -
SV_RELOCATE_MOVE(copy-verify-then-delete-source, never delete-then-copy)
sv_unregister() drops the metadata record only — it never touches the magazine or live files. Entries under a removed registration become orphans (parent_id zeroed), not deleted.
In SV_MODE_STRATEGY, identity resolution uses a single, explicit method selected by the identity_method field in the manifest. The method is chosen at manifest/registration time based on the platform and format — it is NOT a runtime cascade that tries multiple methods.
| Method | When to Use | External Data |
|---|---|---|
SV_IDENTITY_SERIAL_CNF |
PS1/PS2 saves with SYSTEM.CNF (simple pattern) |
None — extracts serial from embedded header |
SV_IDENTITY_SERIAL_SFO |
PSP/PS2 saves with PARAM.SFO
|
None — extracts serial from SFO structure |
SV_IDENTITY_SERIAL_IPBIN |
Saturn saves with IP.BIN
|
None — extracts serial from boot header |
SV_IDENTITY_BOOT_HEADER |
GameCube/Wii saves | None — extracts serial from boot header |
SV_IDENTITY_CHECKSUM |
SNES/Genesis saves | None — reads checksum bytes, returns formatted key |
SV_IDENTITY_ROM_HEADER |
GameCube ISOs, any format with fixed-offset ID | None — reads N bytes at configurable offset |
SV_IDENTITY_TEXT_PATTERN |
PCSX2 SYSTEM.CNF, Ryujinx cnmt scan, PPSSPP/RPCS3 directory basename | None — pattern matching with capture groups |
| Value | Meaning |
|---|---|
| (empty) | Read file at live_path directly, or fall back to rom_path
|
FILENAME |
Read live_path/FILENAME
|
_dirname |
Match against the basename of live_path itself (no file read) |
SV_IDENTITY_PLUGGABLE |
Any format with a hash database |
SV_IDENTITY_NONE |
Generic/default mode, stem-based saves |
Real-world tools (RetroArch, RetroAchievements, Playnite) all bind the identification method to the platform/format/config rather than trying multiple methods at runtime. A cascade would produce nondeterministic results — a partially-readable serial header might succeed on one attempt and fail on another, causing the same save to resolve to different game IDs across runs. The single-method design ensures deterministic, predictable identification.
These platforms name saves by ROM filename stem ({romStem}.{ext}). Decision: caller always supplies game_id derived from ROM filename (Option B). No library API change — the manifest documents the convention and uses identity=none. See docs/stem-matching-proposal.md for the full rationale.
If the selected method fails (file not found, pattern doesn't match, callback returns error), game_id stays NULL. Registration still succeeds — identity failure is never fatal.
PCSX2's file-mode shared memcards (Mcd001.ps2) multiplex many games into one binary file. libsavesync's one-registration-one-save model treats the entire memcard as a single opaque unit — per-game extraction from within a memcard image is explicitly out of scope. The pcsx2_file.cfg manifest documents this with identity=none.
The save_path_template field in the manifest controls where magazine entries are stored for that registration. It supports placeholders:
| Placeholder | Resolves To |
|---|---|
{game_id} |
The resolved game ID (or "unknown" if unresolved) |
{platform} |
The platform string from the manifest |
{emulator} |
The emulator string from the manifest |
{live_path} |
The registration's live save path |
Example: save_path_template={game_id}/{platform} resolves to TEST-00001/ps2/ and stores magazine entries under that directory.
When the template is empty or unset, magazine entries use the default <base>/magazine/ path (same as DEFAULT mode).
A simple key-value text file, one field per line. Lines starting with # are comments.
platform=ps2
emulator=pcsx2
shape=file
identity=serial_cnf
serial_file=SYSTEM.CNF
serial_offset=0
serial_length=256
serial_pattern=BOOT2 = {SERIAL:12}
save_path_template={game_id}/{platform}
Supported identity values: none, serial_cnf, serial_sfo, serial_ipbin, boot_header, checksum, pluggable.
| Mode | Identity | Manifest | Use Case |
|---|---|---|---|
SV_MODE_DEFAULT |
None | None | Generic testing, simple sync |
SV_MODE_STRATEGY |
Single method | Per-platform/emulator | Real emulator save management |
See also: Architecture-Overview | Layer-3-Metadata-Store | API-Reference
libsavesync Wiki