docs: document files read from the save dir

This commit is contained in:
Abdessamad Derraz committed 2026-10-22 19:58:35 +02:00
1 parent 811ccdfea0
commit 3d13b948c7
4 files changed
+49 -3

No files matched your search

+6
View File
@@ -284,6 +284,12 @@ that text belongs in a guide field.
case_insensitive_fs: true # if the platform runs on case-insensitive filesystems
extract_to: /userdata/bios/ # folder the pack extracts into, shown in the README,
# the site and the release notes
save_directory: # the save directory the frontend hands libretro cores,
folder: saves # where it is one place: the pack folder holding the
by_core: true # files cores read there (load_from: save_dir), its
# default place beside the BIOS folder, and whether
# the frontend appends the core's library_name.
# null when it is one folder per game or system
zip_digest: composite # the frontend hashes a .zip by its members only
firmware_folder_flat: true # the frontend lists each system folder without
# descending into it
+19
View File
@@ -87,6 +87,24 @@ from the text and calling it passes the arguments through:
[Files you already had](#files-you-already-had).
7. Copies into standalone emulator directories, only with `--standalone-copies`.
Some cores read their system data below the frontend's save directory, not
below the BIOS folder: Azahar's keys, shared font and NAND files, Citra's
`sysdata`, Dolphin's `User` tree. The file list marks them `root: save`, and
the run writes them below the save directory, which it names before checking
files (`5 files read from RetroArch's save directory go to ...`). For a
RetroArch found by its `retroarch.cfg`, that is `savefile_directory` as
RetroArch expands it (`:` for its own folder, `~` for the home), `saves/`
beside the config when the value is `default`, empty, or names no folder, and
the core's own folder below it when `sort_savefiles_enable` is on, as it is by
default. Without a config, a BIOS folder at its default name (`system`) puts
the save directory beside it (`saves`, `/storage/savefiles` on Lakka).
`--save-dir PATH` names the save directory itself. When none of these
applies, or when `savefiles_in_content_dir` or
`sort_savefiles_by_content_enable` keeps saves beside each game, those files
are left out and the run says why, like the other entries the list cannot
install. Batocera, RetroBat and RetroPie hand each system or game a save folder
of its own: their lists record these files as omitted.
A RetroArch run into an empty folder printed this on 2026-10-21:
```
@@ -398,6 +416,7 @@ what the options name, everything by default.
| `--every-board` | Install the files of every board instead of the one the system names, for a card that moves between devices |
| `--installed-cores` | Keep only what the cores already installed read (RetroArch, Lakka, RetroPie). See [Installed cores](#installed-cores) |
| `--cores-dir PATH` | The folder RetroArch loads its cores from, for `--installed-cores` when it is not found. Implies `--installed-cores` |
| `--save-dir PATH` | The frontend's save directory (RetroArch's `savefile_directory`), for the files some cores read there, when the run cannot find it. The core's own folder is still added below it when the frontend sorts saves by core |
| `--system NAMES` | Install only these systems. Comma-separated or repeated. `--list-systems` prints the names, `other` included |
| `--core NAMES` | Keep the platform's own list and only the extra files these cores load. `--list-cores` prints the names |
| `--emulator NAMES` | Install what these emulators read on the detected platform, and nothing else: their own files and the platform's files of the systems they run. Each emulator page on the site gives this command. `--list-emulators` prints the names, buildbot names such as `mednafen_psx` included |
+23 -2
View File
@@ -523,6 +523,8 @@ reports the profile as uncheckable, and the CI job that runs
| `systems` | no | list of system IDs this core handles |
| `cores` | no | every upstream name the core is known by, for buildbot/target matching |
| `alias_of` | for `type: alias` | profile key this one aliases. The alias carries no `files` |
| `library_name` | when a libretro file has `load_from: save_dir` | the `library_name` the core reports in `retro_get_system_info`, read from the code. RetroArch sorts saves by core by default and hands the core `<save directory>/<library_name>`, so packs and the installer need it to place a file read there. Empty when the core reports an empty name, for which RetroArch adds no folder (FS-UAE, `libretro/libretro.c:575`) |
| `save_folder_once` | no | `true` when the core adds its own folder to the save directory only where the directory it is handed is not already named so (Cemu's `in_named_dir`, `src/libretro/CemuLibretro.cpp:1670-1681`). Every `load_from: save_dir` path then starts with that folder, the `library_name`, and the file lands in the same place whether the frontend sorts saves by core or not |
| `mode` | no | default mode: `standalone`, `libretro`, or `both` |
| `verification` | no | how the core verifies BIOS: `existence`, `md5`, `sha1`, `crc32` |
| `files` | yes, unless `type: alias` | list of file entries |
@@ -546,6 +548,25 @@ profile whose BIOS set is the same), `resources_directory`, `rom_path`,
firmware installs), `dev_flash`, `dev_flash2`, `dev_flash3` (PS3 flash
partitions), and `game_count`.
### Files read from the save directory
Some libretro cores read system data below the save directory the frontend
hands them, not below the system directory. Azahar moves its whole user folder
to `<save_dir>/Azahar/` under the default option "LibRetro Default"
(`src/citra_libretro/core_settings.cpp:1048-1080`), falling back to the system
directory only when the frontend gives none. Such an entry carries
`load_from: save_dir` (or `{libretro: save_dir}`), a `path` relative to the
save directory, and the profile names its `library_name`.
The save directory itself is the platform's: `save_directory` in
`platforms/_registry.yml` names it where the frontend keeps it in one place.
RetroArch keeps `saves/` beside `system/` and sorts by core, so Azahar's keys
land in `saves/Azahar/Azahar/sysdata/keys.txt`. Lakka keeps
`/storage/savefiles`. Batocera, RetroBat and RetroPie hand each game or system
a folder of its own: those entries are listed as omitted
(`no_save_directory`), never placed in the BIOS tree where the core does not
look.
### File entry fields
| Field | Description |
@@ -581,10 +602,10 @@ partitions), and `game_count`.
| `installed_on` | platforms whose own package installs the file beside the emulator although the release does not: their packs leave it out (Batocera and RetroPie copy blueMSX's machines beside the core) |
| `has_builtin` | true if the core falls back to a built-in copy when the file is absent |
| `config_key` | configuration key the emulator exposes to point at the file |
| `load_from` | directory the core reads the file from when it is not the system directory |
| `load_from` | directory the core reads the file from when it is not the system directory, keyed by build (`{libretro: save_dir}`) when the standalone build reads `standalone_path` from its own folder. `save_dir` is the directory the frontend returns for `RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY`: `path` is then relative to it, as the code joins it (Azahar's `Azahar/sysdata/keys.txt`, Dolphin's `User/GBA/gba_bios.bin`), and packs and the installer place the libretro build's file below the save directory (see [Files read from the save directory](#files-read-from-the-save-directory)). `content_dir`, `working_directory`, `config_dir`, `data_dir` and the others describe places no pack reaches |
| `found_by` | `name` when the code opens the file by its name (the default), `content` when it scans a folder and identifies the file by hash, so the name is only a label (DuckStation by MD5, `bios.cpp:208`). Set on the profile or on one file, a dict splits `standalone` from `libretro`. A label is never written into a platform file as a name to hold, and pairs with a platform entry only by hash |
| `source_ref` | source file and line number (e.g. `boot.cpp:42`), read at the profile's `source_commit` when set. A dict splits `standalone` from `libretro` when they diverge. In a profile that declares both `source` and `upstream`, each cited path opens with the one its lines are in: `source libretro.c:120` for the port's own code, `upstream emu/memory.c:46` for the emulator's, including the copy a port carries. `profile_sync --attribute-refs` writes these words from where the lines are found, and the site labels each citation with them |
| `path` | destination path relative to system directory |
| `path` | destination path relative to the system directory, or to the save directory under `load_from: save_dir` |
| `standalone_path` | where the standalone build reads the file, under its own data folder, when it differs from `path` (the libretro destination). Packs for a platform running the emulator standalone use it |
| `on_mismatch` | what the code does when a declared check fails: `reject` (default) or `warn` and run with it, for every check or check by check (`{size: warn, md5: reject}`) |
| `variant_group` | one slot of one core that several entries fill, whatever system each is filed under (PicoDrive's twelve Mega CD BIOS). Region selection keeps one per group |
+1 -1
View File
@@ -49,7 +49,7 @@ Every module in `tests/`, by the area it guards.
| Core regression suites | synthetic | `test_e2e`, `test_audit_regressions`, `test_tool_messages` |
| File resolution and identity | synthetic + collection | `test_adler32_resolution`, `test_agnostic_scan`, `test_agnostic_scan_mode`, `test_agnostic_scope`, `test_agnostic_substitute`, `test_archive_choice`, `test_archive_recipes`, `test_bios_companions`, `test_bundled_identity`, `test_casefold_cache`, `test_db_aliases`, `test_declared_names`, `test_derivations`, `test_directory_entries`, `test_extra_identity`, `test_foreign_tree`, `test_foreign_tree_names`, `test_frontend_digest`, `test_game_data_homonyms`, `test_hashing`, `test_identity`, `test_md5_pack_context`, `test_name_tiebreak`, `test_nec_filing`, `test_owner_resolution`, `test_path_suffix`, `test_resolution_evidence`, `test_sega_filing`, `test_shipped_content`, `test_twin_declarations`, `test_validated_choice`, `test_variant_choice`, `test_variant_identity`, `test_zipped_member` |
| Verification, cross-reference and profile checks | synthetic + profiles | `test_cache_independent_counts`, `test_case_insensitive_platforms`, `test_checks_have_values`, `test_core_file_fills_declaration`, `test_core_size_refusal`, `test_cross_reference_sources`, `test_crypto_aes`, `test_crypto_unique_data`, `test_crypto_verify`, `test_entry_categories`, `test_file_consumers`, `test_fileless_audit`, `test_flycast_layout`, `test_gap_settlement`, `test_hidden_extras`, `test_launcher_aliases`, `test_launcher_layer`, `test_native_mode`, `test_no_case_collisions`, `test_path_conflict_status`, `test_path_null_copies`, `test_profile_checks`, `test_profile_repositories`, `test_romm_hash_rule`, `test_shared_groups`, `test_standalone_links`, `test_standalone_mode`, `test_undeclared_dedup`, `test_unplaced_extras`, `test_validation_scope`, `test_verify_all_dir`, `test_verify_emulator_evidence`, `test_verify_listing`, `test_verify_pack_choice`, `test_verify_release_asset` |
| Packs and manifests | synthetic + real packs | `test_artifact_lock`, `test_atomic_artifacts`, `test_batocera_cores`, `test_deterministic_zip`, `test_emulator_pack_counts`, `test_finalize_pack_names`, `test_large_file_cache`, `test_libretro_layout`, `test_manifest_entry`, `test_minui_platform`, `test_no_game_data`, `test_pack_conformance_dirs`, `test_pack_core_extras`, `test_pack_counts`, `test_pack_destinations`, `test_pack_failures`, `test_pack_file_names`, `test_pack_grouping`, `test_pack_integrity`, `test_pack_member_identity`, `test_pack_readme`, `test_platform_inheritance`, `test_platform_keys`, `test_required_only_archives`, `test_required_only_twins`, `test_split_extras`, `test_split_names`, `test_split_pack`, `test_system_pack_extras`, `test_system_pack_parity`, `test_torrentzip`, `test_which_pack` |
| Packs and manifests | synthetic + real packs | `test_artifact_lock`, `test_atomic_artifacts`, `test_batocera_cores`, `test_deterministic_zip`, `test_emulator_pack_counts`, `test_finalize_pack_names`, `test_large_file_cache`, `test_libretro_layout`, `test_manifest_entry`, `test_minui_platform`, `test_no_game_data`, `test_pack_conformance_dirs`, `test_pack_core_extras`, `test_pack_counts`, `test_pack_destinations`, `test_pack_failures`, `test_pack_file_names`, `test_pack_grouping`, `test_pack_integrity`, `test_pack_member_identity`, `test_pack_readme`, `test_platform_inheritance`, `test_platform_keys`, `test_required_only_archives`, `test_required_only_twins`, `test_save_root`, `test_split_extras`, `test_split_names`, `test_split_pack`, `test_system_pack_extras`, `test_system_pack_parity`, `test_torrentzip`, `test_which_pack` |
| Slots and regions | synthetic + profiles | `test_region`, `test_region_agnostic_scan`, `test_region_groups`, `test_region_held`, `test_region_platform_index`, `test_region_required_only`, `test_slot`, `test_slots`, `test_slots_shipped_file` |
| Hardware targets and systems | synthetic + target files | `test_extract_targets`, `test_lakka_targets`, `test_libretro_slugs`, `test_system_ids`, `test_system_selection`, `test_target_names`, `test_target_scrapers`, `test_target_systems`, `test_target_verify` |
| Installer and downloads | loopback server | `test_check_release`, `test_download`, `test_install`, `test_install_cores`, `test_install_experience`, `test_install_selection` |