MAME splits rompath, samplepath, hashpath and pluginspath on semicolons and tries each directory in turn (src/emu/fileio.cpp:53-58, 330-392, src/emu/emuopts.cpp:44-46, 53). The launcher records spell those lists with the game's own folder in them, which handed_directories skipped: - RetroBat passes -rp bios;<rom directory> (Mame64.Generator.cs:93-96) and -rompath bios/psxmame/bios;<rom directory> to pSxMAME (PSXMame.Generator.cs:38-48). - KNULLI passes -rompath <romDirname>;/userdata/bios/mame;/userdata/bios (mameGenerator.py:116-122). - RetroPie writes rompath $romdir/mame;$romdir/arcade;$biosdir/mame (mame.sh:133). A semicolon list now gives each directory but the game's folder. A pool that already lists the folder the files take keeps them there, and a pool standing for the whole layout holds its files, never its folders. The MAME profile names its sets at the top of the rompath and its search settings as pools, pSxMAME its sets and rompath. RetroBat's -sp and -hash records split on `bool hbmame = emulator == "hbmame"` (Mame64.Generator.cs:30): bios/mame/samples for mame64, bios/hbmame/samples for hbmame. Manifests: RetroBat gains the 12 pSxMAME sets in psxmame/bios and drops samples/bbc.zip, read by nobody, which mame/samples/bbc.zip already serves. KNULLI drops the same copy. RetroPie gains the 1427 MAME sets in BIOS/mame, the root copies staying for the libretro cores. EmuDeck names samples/bbc.zip as read outside the BIOS folder. RetroDECK's samplepath is $bios_path/mame-sa/samples (mame/component_prepare.sh:94, 117): bbc.zip moves there from bios/samples/. Its MAME runs with the -rompath ES-DE passes, %GAMEDIR%;%ROMPATH%/<system>, so the standalone sets are named as read outside the BIOS folder and the root copies stay for the libretro core. The 1427 sets of RetroBat, KNULLI and EmuDeck stay at the BIOS root, listed in their rompath. No file of any manifest is lost.
Platform Configs
How platform YAML files work and where subdirectory requirements come from.
Files
_registry.yml-- platform metadata (name, release pack, display order)_shared.yml-- shared file groups with canonical destinations<platform>.yml-- per-platform BIOS declarations- Inheritance:
lakka.ymlinheritsretroarch,retropie.ymlinheritsretroarch
Shared groups (_shared.yml)
The subdirectory a BIOS goes into is determined by the libretro core, not
the platform. NP2kai expects np2kai/BIOS.ROM whether you're on RetroArch,
Batocera, or Recalbox. Only base_destination varies (system/ vs bios/).
Shared groups define files with correct destinations once. Platforms
reference them via includes: [group_name] in their system definitions.
load_platform_config() in common.py resolves includes at load time,
deduplicating by filename.
When to use shared groups: whenever 2+ platforms share files that a core expects in a specific subdirectory. The group carries the correct destination so platforms can't drift.
For RetroArch specifically, libretro_scraper.py injects includes:
references and applies subdirectory prefixes via CORE_SUBDIR_MAP during
generation. Manual edits to retroarch.yml will be overwritten on next scrape.
Data directories (_data_dirs.yml)
Some cores need entire directory trees, not just individual BIOS files.
Dolphin needs dolphin-emu/Sys/ (GameSettings, DSP firmware, fonts),
PPSSPP needs PPSSPP/ (font assets, shaders), blueMSX needs Databases/
and Machines/ (machine configs).
These are defined in _data_dirs.yml as a central registry with upstream
source URLs. The pack generator auto-refreshes from upstream before building
(use --offline to skip). Data directories live in data/ (not bios/)
and are NOT indexed in database.json.
Adding a data directory:
- Add entry to
_data_dirs.ymlwith source URL, extraction path, cache location - Reference via
data_directories: [{ref: key, destination: path}]in platform systems - For scraper-generated platforms, add to
SYSTEM_DATA_DIRSin the scraper - Run
python scripts/refresh_data_dirs.py --key <name>to populate the cache
Subdirectory reference
Each entry documents where the requirement comes from. Check these source files to verify or update the paths.
| Core | Subdirectory | Source |
|---|---|---|
| NP2kai | np2kai/ |
libretro-np2kai/sdl/libretro.c |
| PX68k | keropi/ |
px68k/libretro/libretro.c |
| QUASI88 | quasi88/ |
quasi88/src/libretro.c |
| Kronos | kronos/ |
libretro-kronos/libretro/libretro.c |
| ep128emu | ep128emu/rom/ |
ep128emu-core/src/libretro.cpp |
| Flycast | dc/ |
flycast/shell/libretro/libretro.cpp |
| FBNeo NeoCD | neocd/ |
fbneo/src/burn/drv/neogeo/neo_run.cpp |
| Fuse | fuse/ |
fuse-libretro/fuse/settings.c |
| hatari | hatari/tos/ |
hatari/src/tos.c |
Full libretro docs: https://docs.libretro.com/library/<core>/
Adding a platform
- Create
platforms/<name>.yml - Set
base_destination(systemorbios),verification_mode,hash_type - Use
includes: [group]for systems with subdirectory requirements - Use
inherits: retroarchto share RetroArch's file set - Add platform-specific overrides in
overrides.systems - Test:
python scripts/verify.py --platform <name>
Adding a shared group
- Add the group to
_shared.ymlwith a source ref comment - Include: filename, destination with subdirectory prefix, required flag, hashes
- Reference via
includes: [group_name]in platform system definitions - For scraper-generated platforms, add the mapping in the scraper's
SYSTEM_SHARED_GROUPSdict so it persists across regeneration
Verification modes
| Platform | Mode | Native logic | Upstream source |
|---|---|---|---|
| RetroArch | existence | path_is_valid() -- file exists |
core_info.c |
| Lakka | existence | inherits RetroArch | idem |
| RetroPie | existence | inherits RetroArch | idem |
| Batocera | md5 | md5sum() + checkInsideZip() |
batocera-systems |
| RetroBat | md5 | MD5 check via JSON config | batocera-systems.json |
| EmuDeck | md5 | MD5 whitelist per system | checkBIOS.sh |
| Recalbox | md5 | multi-hash comma-separated | es_bios.xml + Bios.cpp |
| RetroDECK | md5 | MD5 per file via component manifests | api_data_processing.sh |
| RomM | md5 | size + any hash (MD5/SHA1/CRC32) | firmware.py |
| ROCKNIX | md5 | md5sum() + checkInsideZip() with altmd5 |
rocknix-systems |
| MiSTer FPGA | md5 | MD5 of the file at its destination | process_db_index_worker.py |
| BizHawk | sha1 | SHA1 per firmware entry | FirmwareDatabase.cs |