Skip to content

Add RetroArch save sync with the RomM server#112

Draft
gantoine wants to merge 1 commit into
mainfrom
claude/brave-feynman-d4ivcn
Draft

Add RetroArch save sync with the RomM server#112
gantoine wants to merge 1 commit into
mainfrom
claude/brave-feynman-d4ivcn

Conversation

@gantoine

Copy link
Copy Markdown
Member

Summary

Implements save synchronization between local games and the RomM server, per the save sync RFC, the server-side #3137, and the behaviour change in #3479.

Uses the server's API sync mode:

  1. Register this machine as a RomM device once (POST /api/devices, client playnite, sync_mode: "api"); the server-assigned device_id is persisted in settings.
  2. POST /api/sync/negotiate — report the local save (rom_id, file name, MD5 content_hash, updated_at, size) and let the server decide per save: upload / download / conflict / no_op.
  3. Execute the returned operations — POST/PUT /api/saves (multipart saveFile), GET /api/saves/{id}/content then POST /api/saves/{id}/downloaded.
  4. POST /api/sync/sessions/{id}/complete.

Conflicts are resolved most-recent-wins (the RFC default), with the decision logged.

Scope & behaviour

  • RetroArch battery saves (.srm): the local save path is derived from retroarch.cfg (savefile_directory plus the sort_savefiles_enable / sort_savefiles_by_content_enable options and the : base-dir token), with a recursive-search fallback for sorted layouts.
  • Saves only — save states aren't part of the server's device-sync flow.
  • When: pull the newest save before launch (OnGameStarting), push after play (OnGameStopped), plus a "Sync saves with RomM" game-menu action.
  • Gated behind a new "Enable save sync" setting (off by default).
  • Save content is hashed with MD5 to match the server's comparison exactly.
  • Failures are logged and surfaced via notifications; they never block a game from launching.

Files

  • New: Saves/SaveSyncService.cs (orchestration), Saves/RetroArchConfig.cs + Saves/SaveFileHash.cs (pure, unit-tested), Models/RomM/Save/* (wire models).
  • Changed: RomM.cs (play hooks + menu item), Settings/Settings.cs + SettingsView.xaml (new toggle, persisted device id).
  • Tests: RetroArchConfigTests, SaveFileHashTests.

Testing

  • Added unit tests for the pure logic (retroarch.cfg parsing, save-path resolution, MD5 hashing).
  • Not built/run locally — the plugin is WPF / .NET Framework 4.6.2 (Windows-only) and this environment has no Windows SDK; relying on CI for the build + test run.

Open questions

  • Device registration needs the client token to carry device/asset scopes — worth documenting.
  • extension.yaml version bump and a README section for the new setting can follow if wanted.

🤖 Draft opened for review.


Generated by Claude Code

Implements the API-mode save sync flow from the RomM server PRs (#3137,
#3479): register this machine as a RomM device once, POST /sync/negotiate
to let the server decide upload/download/conflict/no_op per save, execute
the returned operations, then complete the sync session. Conflicts are
resolved most-recent-wins.

Scope is RetroArch battery saves (.srm): the local save path is derived
from retroarch.cfg (savefile_directory plus the sort_savefiles* options),
with a recursive search fallback for sorted layouts. Saves are pulled down
before launch (OnGameStarting) and pushed back after play (OnGameStopped),
plus a "Sync saves with RomM" game-menu action. Gated behind a new
"Enable save sync" setting; the server-assigned device id is persisted.

Save content is hashed with MD5 to match the server's comparison. Pure
parsing/path/hashing logic is unit-tested.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants