Repository navigation
Conversation
The bundled libsigil was an early build: it read only Switch containers and PS1/PS2/PSP/Wii images, and declined every ".iso" because Ludo never told it the platform. A Python reader covered GameCube/Wii and ISO 9660 beside it, and nothing at all read a zipped game, a CHD or a Dreamcast disc. Sigil is now upstream 8a3b008, built in full with cmake (3DS and Wii U included, deps vendored and static, still libc-only at GLIBC_2.33). title_ids passes the platform -- named by the caller, or by the roms/<platform>/ folder the ROM sits in -- and exposes identify(), which adds the emulator's on-disk save name and layout to the title ID. That is the same identity Argosy reads with the same library. The Python disc readers are gone; what stays is what Sigil cannot see: IDs in the names of games not on this device, and Switch base/update/DLC arithmetic. Also: the GCI filename fallback expected a six-character code where Dolphin writes "<maker>-<game code>", two then four; and build_sigil.sh resolved the repo root after cd-ing away from it, so it never installed its build into the package. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014P4FnbXeH6kbQAgBJ6BDgG
Both download paths wrote a server save under the uploader's filename. Argosy names a game's autosave after its own ROM file, and the same game is routinely called something else here -- a zip Ludo extracted, a different revision tag, a disc set booted through its .m3u -- so the save landed beside the game as a file RetroArch never loads. A battery save now takes the name RetroArch reads on this device: the uploader's name when it is one of this ROM's own files (a regional variant keeps its region), otherwise the launched file, the ROM itself, the one game inside an extracted folder, a disc set's playlist or a dump's descriptor. A folder ROM that leaves a choice and has not been launched defers the background download; the pre-launch sync, which runs after the launch is noted, places it. The pre-launch path also groups server saves by that local name, so another client's save and ours are one save, newest wins, instead of two writes to one file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014P4FnbXeH6kbQAgBJ6BDgG
Argosy now syncs flycast's port A1 card, "<product id>.A1.bin", in the "autosave" slot, uploaded under its own ROM's name and restored by product id. Ludo gave every port a "vmu-<port>" slot, so the two never met, and a "Crazy Taxi (USA).bin" from Argosy would have been written beside the card as a file flycast never reads. A1 uploads as the autosave; the other ports keep their slots. A Dreamcast autosave from the server is written as the game's A1 card: the card already on disk names it, else the product number Sigil reads off the disc (zipped or not), else the content name flycast falls back to. Old "vmu-a1" rows hold an earlier copy of the same card and are no longer downloaded over the autosave. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014P4FnbXeH6kbQAgBJ6BDgG
Dolphin, the libretro core included, keeps each save a game writes as its own .gci in "<user dir>/GC/<region>/Card A/". Ludo reported every GCI on the game's (rom, "autosave"), so the dedupe kept the newest and dropped the rest; a game with two save files synced one. Under core or content sorting the card folder sat one level below the save scan, so nothing was found at all. A game's GCIs are now one unit, as Argosy's GciSaveHandler has them: one GCI travels raw, several as a flat zip of their file names, which the server hashes the same as Argosy's own. A restore replaces that game's GCIs in the folder Dolphin reads -- the one holding them, else the one the core would create -- keeps the old ones as backups, names a lone GCI as Dolphin does, refuses another game's save, and waits while RetroArch runs. A legacy per-GCI row from an older Ludo replaces only the save file it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014P4FnbXeH6kbQAgBJ6BDgG
Argosy finds a game's autosave on the server by its name: the name of its own ROM file, "argosy-latest" or "autosave" (SaveSyncApiClient.isLatestSaveFileName). Ludo uploaded under its own name for the game, which often is not Argosy's -- a zip extracted here, a revision tag -- so Argosy saw Ludo's save only while it was the lone one on the server. Ludo places downloads by its own rule now, not by the server's name, so the name can serve Argosy: a game's autosave goes up as "autosave.<ext>". VMU ports, named channels and a ROM of several regional games keep their names, the last because the name is all that says which region's save it is. Version restore takes the local name too, and an Eden save whose name carries no title ID -- Argosy's, or ours as "autosave.zip" -- restores under the ROM's own ID from RomM. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014P4FnbXeH6kbQAgBJ6BDgG
Eden packs went up as "<title id>.zip", a name Argosy reads as this
game's autosave only while it is the lone save on the server. They now
go up as "autosave.zip", like every other game's autosave. The title ID
still travels inside the pack ("<title id>/…", Argosy's layout too), and
a restore whose name carries none -- ours now, or Argosy's ROM-named
packs -- reads it from the ROM's RomM title ID, else from the pack.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014P4FnbXeH6kbQAgBJ6BDgG
Neither console's save is a file: PPSSPP keeps a game's save as folders under PSP/SAVEDATA named by its serial, Citra and Azahar as a title's data and extdata folders on their virtual SD card. Ludo's save walk looks for save-file extensions, so neither was ever synced. Both are now discovered where the libretro cores write them, under any of RetroArch's sortings, and packed as Argosy packs them -- every SAVEDATA folder starting with the serial as a root of its own, minus installed game data; a 3DS title's "data/" and "extdata/" -- so the server hashes the two clients' zips alike. A restore replaces the game's folders (a 3DS component only when the zip carries it), keeps backups, waits while RetroArch runs, and finds the place to write from the save already there, else where the core would create it. Games are matched by serial or title ID; RomM's "00040000/00033500" spelling of a 3DS title now folds onto its 16-hex ID. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014P4FnbXeH6kbQAgBJ6BDgG
Picking a version in the save history wrote the server file beside the game under its own name -- right for an .srm, but a PS2 card's folders, a GameCube game's GCIs, a PSP or 3DS game's save folders and an Eden pack all arrive as zips that only mean something unpacked into the emulator's tree. Those versions now go through the sync's own restore, with its backups and its refusal while the emulator is open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014P4FnbXeH6kbQAgBJ6BDgG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Makes Ludo's save sync interoperate with Argosy, the Android RomM client, for the popular platforms. It does this by reading games the same way Argosy does (argosy-sigil) and shaping saves as Argosy's handlers do. One commit per step:
8a3b008) and read every disc through it. The full upstream build adds zipped games, CHD, Dreamcast, PSP and 3DS; it still needs only libc at the sameGLIBC_2.33floor.title_idsnow passes the platform, from the caller or theroms/<platform>/folder. Without one, Sigil declines every.iso. The Python disc readers are removed.build_sigil.shnow builds with cmake and actually installs into the package; it never did before..m3uor a.cue. Regional-variant saves keep their own name. Saves that can't be placed yet wait for the next launch.autosaveslot as Argosy does, restored as<product id>.A1.bin. Ludo's legacyvmu-a1rows are no longer downloaded over it..gcifiles sync as one save: one file raw, several as a flat zip, matching the server hash of Argosy's zip. Before this Ludo kept one file per game, or found none: the libretro Dolphin card folder sat one level below the save scan.autosave.<ext>, Eden included. Argosy recognises an autosave by name: its own ROM name,argosy-latestorautosave. Ludo's names were often none of these. Version restore and Eden restore no longer depend on the filename; Eden reads the title ID from RomM, else from the pack itself.SAVEDATA/<serial>*folders, zipped with each folder as a root.data/+extdata/, zipped under those two root names.Saves already on the server under the old names stay as they are; Argosy recognises each game's next upload.
Which shells it affects
Both. The changes are in
engine/plus one call inapp/ludo_app/backend.py(version restore).How you tested it
cd engine && tests/run.sh: all 34 files pass. New:test_save_naming.py,test_dreamcast_sync.py,test_gamecube_sync.py,test_folder_saves.py;test_title_ids.pywas updated for Sigil.cd app && pytest: 21 passed.desktopuntouched; not run.run_negotiated_save_syncandbuild_sync_inventoryagainst a stubbed server. Fixture zips are built the way Argosy'sSaveArchiverwrites them, and the tests assert the server hashes them the same as Ludo's.Boot.cpp, PPSSPPlibretro.cpp, Citra/Azaharcitra_libretro.cppandarchive.h.Not tried by hand: a real round trip with Argosy on hardware. Worth checking one game each for Melee (GameCube), a Dreamcast game, a PSP game, a 3DS game, a zipped SNES game, and a Switch game, Deck → phone → Deck.
🤖 Generated with Claude Code
https://claude.ai/code/session_014P4FnbXeH6kbQAgBJ6BDgG
Generated by Claude Code