From 7035da1154ed63bacc62fbfc9cd695972ba37836 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Wed, 11 Nov 2026 12:30:53 +0100 Subject: [PATCH] feat: read libretro MAME's -rompath from ES-DE ES-DE starts the libretro MAME core with a command line as its content in 22 commands across 21 systems ("apple2e -rompath \"%GAMEDIRRAW%; %ROMPATH%/apple2\" -flop1 ...", resources/systems/linux/es_systems.xml at RetroDECK's 15e1b236 and EmuDeck's ES-DE v3.5.0), run through the shell by popen (es-core/src/utils/PlatformUtil.cpp:231, 257). At 5f5a0774 the core reads content that is no file as a command line (retro_init.cpp:966-1008). Set_Path_Option passes its own -rompath ;/mame/bios;/mame/roms (580-597), then every word of the command line follows, -rompath included, only -rp being dropped when mame_paths_enable is off (902-940, 914-919). MAME keeps the later value of an option given twice at one priority (src/lib/util/options.cpp:260-276, clifront.cpp:243). Those commands read their sets in the folders they name, and mame/bios stays read by every command that passes none. The ES-DE parser records these commands in searched_by with their core, the mame profile declares libretro_pools (-rompath and -rp stand for mame/bios), and a set there also goes to each folder a command names for a machine that reads it. Manifests: EmuDeck gains 16 files below roms/ (apple2, apple2gs, astrocde, crvision, gamate, gamecom, gmaster, intellivision, odyssey2, scv, supracan, vectrex, videopac, vsmile). RetroDECK does not change: its standalone MAME commands already put the same sets at the same paths. No file leaves. --- emulators/mame.yml | 15 ++- platforms/romfolders/emudeck-windows.yml | 147 +++++++++++++++++++++++ platforms/romfolders/emudeck.yml | 147 +++++++++++++++++++++++ platforms/romfolders/retrodeck.yml | 147 +++++++++++++++++++++++ schemas/emulator.schema.json | 18 +++ schemas/romfolders.schema.json | 3 +- scripts/common.py | 86 ++++++++----- scripts/scraper/romfolders/es.py | 64 +++++++--- tests/test_launcher_placement.py | 26 ++++ tests/test_romfolders_es.py | 17 ++- 10 files changed, 618 insertions(+), 52 deletions(-) diff --git a/emulators/mame.yml b/emulators/mame.yml index b7f23ce3d..5c8c31325 100644 --- a/emulators/mame.yml +++ b/emulators/mame.yml @@ -172,6 +172,14 @@ standalone_pools: pluginspath: "plugins" "-pluginspath": "plugins" +libretro_pools: + "-rompath": + folder: "mame/bios" + source_ref: "src/osd/libretro/libretro-internal/retro_init.cpp:580-597, 804-809, 902-940, src/lib/util/options.cpp:260-276" + "-rp": + folder: "mame/bios" + source_ref: "src/osd/libretro/libretro-internal/retro_init.cpp:580-597, 804-809, 914-919" + data_root: windows: path: "" @@ -195,7 +203,12 @@ notes: | samples, crosshair). ROM search: content_dir + system_dir/mame/bios + system_dir/mame/roms, never system_dir itself (src/osd/libretro/libretro-internal/retro_init.cpp:580-597), so the libretro - build reads its sets in mame/bios. Cheats via per-game XML files. + build reads its sets in mame/bios. Content that is no file is read as a + command line (retro_init.cpp:966-1008): a -rompath there is passed to + MAME after the core's own, and the later value wins + (src/lib/util/options.cpp:260-276), so the sets are read in the folders + it names. A -rp is dropped and appended to the core's list (580-597, + 914-919). Cheats via per-game XML files. The standalone build splits every search path on semicolons and tries each directory in turn until the file opens (src/emu/fileio.cpp:53-58, 330-392). rompath defaults to roms, samplepath to samples, hashpath to diff --git a/platforms/romfolders/emudeck-windows.yml b/platforms/romfolders/emudeck-windows.yml index 4de006fa3..5b5ec40c4 100644 --- a/platforms/romfolders/emudeck-windows.yml +++ b/platforms/romfolders/emudeck-windows.yml @@ -222,6 +222,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:128" searched_by: + - emulator: retroarch + core: mame + reads: + - apple2 + machines: + - apple2e + source_ref: "esde resources/systems/windows/es_systems.xml:135" - emulator: mame reads: - apple2 @@ -237,6 +244,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:142" searched_by: + - emulator: retroarch + core: mame + reads: + - apple2gs + machines: + - apple2gs + source_ref: "esde resources/systems/windows/es_systems.xml:146,147" - emulator: mame reads: - apple2gs @@ -279,6 +293,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:191" searched_by: + - emulator: retroarch + core: mame + reads: + - arcadia + machines: + - arcadia + source_ref: "esde resources/systems/windows/es_systems.xml:196" - emulator: mame reads: - arcadia @@ -348,6 +369,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:225" searched_by: + - emulator: retroarch + core: mame + reads: + - astrocde + machines: + - astrocde + source_ref: "esde resources/systems/windows/es_systems.xml:229" - emulator: mame reads: - astrocde @@ -391,6 +419,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:262" searched_by: + - emulator: retroarch + core: mame + reads: + - atari7800 + machines: + - a7800 + source_ref: "esde resources/systems/windows/es_systems.xml:267" - emulator: mame reads: - atari7800 @@ -624,6 +659,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:411" searched_by: + - emulator: retroarch + core: mame + reads: + - channelf + machines: + - channelf + source_ref: "esde resources/systems/windows/es_systems.xml:416" - emulator: mame reads: - channelf @@ -748,6 +790,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:553" searched_by: + - emulator: retroarch + core: mame + reads: + - crvision + machines: + - crvision + source_ref: "esde resources/systems/windows/es_systems.xml:558" - emulator: mame reads: - crvision @@ -988,6 +1037,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:769" searched_by: + - emulator: retroarch + core: mame + reads: + - fmtowns + machines: + - fmtownshr + source_ref: "esde resources/systems/windows/es_systems.xml:773" - emulator: mame reads: - fmtowns @@ -1009,6 +1065,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:790" searched_by: + - emulator: retroarch + core: mame + reads: + - gamate + machines: + - gamate + source_ref: "esde resources/systems/windows/es_systems.xml:794" - emulator: mame reads: - gamate @@ -1038,6 +1101,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:812" searched_by: + - emulator: retroarch + core: mame + reads: + - gamecom + machines: + - gamecom + source_ref: "esde resources/systems/windows/es_systems.xml:816" - emulator: mame reads: - gamecom @@ -1169,6 +1239,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:954" searched_by: + - emulator: retroarch + core: mame + reads: + - gmaster + machines: + - gmaster + source_ref: "esde resources/systems/windows/es_systems.xml:958" - emulator: mame reads: - gmaster @@ -1210,6 +1287,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:975" searched_by: + - emulator: retroarch + core: mame + reads: + - intellivision + machines: + - intv + source_ref: "esde resources/systems/windows/es_systems.xml:980" - emulator: mame reads: - intellivision @@ -1479,6 +1563,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:1227" searched_by: + - emulator: retroarch + core: mame + reads: + - megaduck + machines: + - megaduck + source_ref: "esde resources/systems/windows/es_systems.xml:1232" - emulator: mame reads: - megaduck @@ -1834,6 +1925,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:1548" searched_by: + - emulator: retroarch + core: mame + reads: + - odyssey2 + machines: + - odyssey2 + source_ref: "esde resources/systems/windows/es_systems.xml:1553" - emulator: mame reads: - odyssey2 @@ -2136,6 +2234,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:1798" searched_by: + - emulator: retroarch + core: mame + reads: + - pv1000 + machines: + - pv1000 + source_ref: "esde resources/systems/windows/es_systems.xml:1802" - emulator: mame reads: - pv1000 @@ -2223,6 +2328,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:1898" searched_by: + - emulator: retroarch + core: mame + reads: + - scv + machines: + - scv + source_ref: "esde resources/systems/windows/es_systems.xml:1902" - emulator: mame reads: - scv @@ -2479,6 +2591,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:2138" searched_by: + - emulator: retroarch + core: mame + reads: + - supervision + machines: + - svision + source_ref: "esde resources/systems/windows/es_systems.xml:2143" - emulator: mame reads: - supervision @@ -2494,6 +2613,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:2149" searched_by: + - emulator: retroarch + core: mame + reads: + - supracan + machines: + - supracan + source_ref: "esde resources/systems/windows/es_systems.xml:2153" - emulator: mame reads: - supracan @@ -2659,6 +2785,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:2296" searched_by: + - emulator: retroarch + core: mame + reads: + - vectrex + machines: + - vectrex + source_ref: "esde resources/systems/windows/es_systems.xml:2301" - emulator: mame reads: - vectrex @@ -2714,6 +2847,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:2317" searched_by: + - emulator: retroarch + core: mame + reads: + - videopac + machines: + - videopac + source_ref: "esde resources/systems/windows/es_systems.xml:2322" - emulator: mame reads: - videopac @@ -2754,6 +2894,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/windows/es_systems.xml:2357" searched_by: + - emulator: retroarch + core: mame + reads: + - vsmile + machines: + - vsmile + source_ref: "esde resources/systems/windows/es_systems.xml:2361" - emulator: mame reads: - vsmile diff --git a/platforms/romfolders/emudeck.yml b/platforms/romfolders/emudeck.yml index b6c4c94ca..21692154c 100644 --- a/platforms/romfolders/emudeck.yml +++ b/platforms/romfolders/emudeck.yml @@ -221,6 +221,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:131" searched_by: + - emulator: retroarch + core: mame + reads: + - apple2 + machines: + - apple2e + source_ref: "esde resources/systems/linux/es_systems.xml:138" - emulator: mame reads: - apple2 @@ -236,6 +243,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:145" searched_by: + - emulator: retroarch + core: mame + reads: + - apple2gs + machines: + - apple2gs + source_ref: "esde resources/systems/linux/es_systems.xml:149,150" - emulator: mame reads: - apple2gs @@ -278,6 +292,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:193" searched_by: + - emulator: retroarch + core: mame + reads: + - arcadia + machines: + - arcadia + source_ref: "esde resources/systems/linux/es_systems.xml:198" - emulator: mame reads: - arcadia @@ -347,6 +368,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:226" searched_by: + - emulator: retroarch + core: mame + reads: + - astrocde + machines: + - astrocde + source_ref: "esde resources/systems/linux/es_systems.xml:230" - emulator: mame reads: - astrocde @@ -390,6 +418,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:263" searched_by: + - emulator: retroarch + core: mame + reads: + - atari7800 + machines: + - a7800 + source_ref: "esde resources/systems/linux/es_systems.xml:268" - emulator: mame reads: - atari7800 @@ -619,6 +654,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:412" searched_by: + - emulator: retroarch + core: mame + reads: + - channelf + machines: + - channelf + source_ref: "esde resources/systems/linux/es_systems.xml:417" - emulator: mame reads: - channelf @@ -743,6 +785,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:552" searched_by: + - emulator: retroarch + core: mame + reads: + - crvision + machines: + - crvision + source_ref: "esde resources/systems/linux/es_systems.xml:557" - emulator: mame reads: - crvision @@ -984,6 +1033,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:776" searched_by: + - emulator: retroarch + core: mame + reads: + - fmtowns + machines: + - fmtownshr + source_ref: "esde resources/systems/linux/es_systems.xml:780" - emulator: mame reads: - fmtowns @@ -1003,6 +1059,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:796" searched_by: + - emulator: retroarch + core: mame + reads: + - gamate + machines: + - gamate + source_ref: "esde resources/systems/linux/es_systems.xml:800" - emulator: mame reads: - gamate @@ -1032,6 +1095,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:818" searched_by: + - emulator: retroarch + core: mame + reads: + - gamecom + machines: + - gamecom + source_ref: "esde resources/systems/linux/es_systems.xml:822" - emulator: mame reads: - gamecom @@ -1163,6 +1233,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:962" searched_by: + - emulator: retroarch + core: mame + reads: + - gmaster + machines: + - gmaster + source_ref: "esde resources/systems/linux/es_systems.xml:966" - emulator: mame reads: - gmaster @@ -1204,6 +1281,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:983" searched_by: + - emulator: retroarch + core: mame + reads: + - intellivision + machines: + - intv + source_ref: "esde resources/systems/linux/es_systems.xml:988" - emulator: mame reads: - intellivision @@ -1475,6 +1559,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:1233" searched_by: + - emulator: retroarch + core: mame + reads: + - megaduck + machines: + - megaduck + source_ref: "esde resources/systems/linux/es_systems.xml:1238" - emulator: mame reads: - megaduck @@ -1823,6 +1914,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:1558" searched_by: + - emulator: retroarch + core: mame + reads: + - odyssey2 + machines: + - odyssey2 + source_ref: "esde resources/systems/linux/es_systems.xml:1563" - emulator: mame reads: - odyssey2 @@ -2122,6 +2220,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:1814" searched_by: + - emulator: retroarch + core: mame + reads: + - pv1000 + machines: + - pv1000 + source_ref: "esde resources/systems/linux/es_systems.xml:1818" - emulator: mame reads: - pv1000 @@ -2209,6 +2314,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:1910" searched_by: + - emulator: retroarch + core: mame + reads: + - scv + machines: + - scv + source_ref: "esde resources/systems/linux/es_systems.xml:1914" - emulator: mame reads: - scv @@ -2464,6 +2576,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2150" searched_by: + - emulator: retroarch + core: mame + reads: + - supervision + machines: + - svision + source_ref: "esde resources/systems/linux/es_systems.xml:2155" - emulator: mame reads: - supervision @@ -2479,6 +2598,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2161" searched_by: + - emulator: retroarch + core: mame + reads: + - supracan + machines: + - supracan + source_ref: "esde resources/systems/linux/es_systems.xml:2165" - emulator: mame reads: - supracan @@ -2646,6 +2772,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2311" searched_by: + - emulator: retroarch + core: mame + reads: + - vectrex + machines: + - vectrex + source_ref: "esde resources/systems/linux/es_systems.xml:2316" - emulator: mame reads: - vectrex @@ -2701,6 +2834,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2332" searched_by: + - emulator: retroarch + core: mame + reads: + - videopac + machines: + - videopac + source_ref: "esde resources/systems/linux/es_systems.xml:2337" - emulator: mame reads: - videopac @@ -2741,6 +2881,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2372" searched_by: + - emulator: retroarch + core: mame + reads: + - vsmile + machines: + - vsmile + source_ref: "esde resources/systems/linux/es_systems.xml:2376" - emulator: mame reads: - vsmile diff --git a/platforms/romfolders/retrodeck.yml b/platforms/romfolders/retrodeck.yml index 12648a64f..61dbf0ecf 100644 --- a/platforms/romfolders/retrodeck.yml +++ b/platforms/romfolders/retrodeck.yml @@ -195,6 +195,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:139" searched_by: + - emulator: retroarch + core: mame + reads: + - apple2 + machines: + - apple2e + source_ref: "esde resources/systems/linux/es_systems.xml:146" - emulator: mame reads: - apple2 @@ -210,6 +217,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:153" searched_by: + - emulator: retroarch + core: mame + reads: + - apple2gs + machines: + - apple2gs + source_ref: "esde resources/systems/linux/es_systems.xml:157" - emulator: mame reads: - apple2gs @@ -247,6 +261,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:198" searched_by: + - emulator: retroarch + core: mame + reads: + - arcadia + machines: + - arcadia + source_ref: "esde resources/systems/linux/es_systems.xml:203" - emulator: mame reads: - arcadia @@ -316,6 +337,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:231" searched_by: + - emulator: retroarch + core: mame + reads: + - astrocde + machines: + - astrocde + source_ref: "esde resources/systems/linux/es_systems.xml:235" - emulator: mame reads: - astrocde @@ -358,6 +386,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:268" searched_by: + - emulator: retroarch + core: mame + reads: + - atari7800 + machines: + - a7800 + source_ref: "esde resources/systems/linux/es_systems.xml:273" - emulator: mame reads: - atari7800 @@ -570,6 +605,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:420" searched_by: + - emulator: retroarch + core: mame + reads: + - channelf + machines: + - channelf + source_ref: "esde resources/systems/linux/es_systems.xml:425" - emulator: mame reads: - channelf @@ -694,6 +736,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:557" searched_by: + - emulator: retroarch + core: mame + reads: + - crvision + machines: + - crvision + source_ref: "esde resources/systems/linux/es_systems.xml:562" - emulator: mame reads: - crvision @@ -921,6 +970,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:785" searched_by: + - emulator: retroarch + core: mame + reads: + - fmtowns + machines: + - fmtownshr + source_ref: "esde resources/systems/linux/es_systems.xml:789" - emulator: mame reads: - fmtowns @@ -936,6 +992,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:807" searched_by: + - emulator: retroarch + core: mame + reads: + - gamate + machines: + - gamate + source_ref: "esde resources/systems/linux/es_systems.xml:811" - emulator: mame reads: - gamate @@ -965,6 +1028,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:829" searched_by: + - emulator: retroarch + core: mame + reads: + - gamecom + machines: + - gamecom + source_ref: "esde resources/systems/linux/es_systems.xml:833" - emulator: mame reads: - gamecom @@ -1096,6 +1166,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:972" searched_by: + - emulator: retroarch + core: mame + reads: + - gmaster + machines: + - gmaster + source_ref: "esde resources/systems/linux/es_systems.xml:976" - emulator: mame reads: - gmaster @@ -1137,6 +1214,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:993" searched_by: + - emulator: retroarch + core: mame + reads: + - intellivision + machines: + - intv + source_ref: "esde resources/systems/linux/es_systems.xml:998" - emulator: mame reads: - intellivision @@ -1381,6 +1465,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:1247" searched_by: + - emulator: retroarch + core: mame + reads: + - megaduck + machines: + - megaduck + source_ref: "esde resources/systems/linux/es_systems.xml:1252" - emulator: mame reads: - megaduck @@ -1718,6 +1809,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:1576" searched_by: + - emulator: retroarch + core: mame + reads: + - odyssey2 + machines: + - odyssey2 + source_ref: "esde resources/systems/linux/es_systems.xml:1581" - emulator: mame reads: - odyssey2 @@ -2028,6 +2126,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:1854" searched_by: + - emulator: retroarch + core: mame + reads: + - pv1000 + machines: + - pv1000 + source_ref: "esde resources/systems/linux/es_systems.xml:1858" - emulator: mame reads: - pv1000 @@ -2104,6 +2209,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:1951" searched_by: + - emulator: retroarch + core: mame + reads: + - scv + machines: + - scv + source_ref: "esde resources/systems/linux/es_systems.xml:1955" - emulator: mame reads: - scv @@ -2352,6 +2464,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2193" searched_by: + - emulator: retroarch + core: mame + reads: + - supervision + machines: + - svision + source_ref: "esde resources/systems/linux/es_systems.xml:2198" - emulator: mame reads: - supervision @@ -2367,6 +2486,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2204" searched_by: + - emulator: retroarch + core: mame + reads: + - supracan + machines: + - supracan + source_ref: "esde resources/systems/linux/es_systems.xml:2208" - emulator: mame reads: - supracan @@ -2509,6 +2635,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2357" searched_by: + - emulator: retroarch + core: mame + reads: + - vectrex + machines: + - vectrex + source_ref: "esde resources/systems/linux/es_systems.xml:2362" - emulator: mame reads: - vectrex @@ -2564,6 +2697,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2378" searched_by: + - emulator: retroarch + core: mame + reads: + - videopac + machines: + - videopac + source_ref: "esde resources/systems/linux/es_systems.xml:2383" - emulator: mame reads: - videopac @@ -2597,6 +2737,13 @@ folders: emulator: retroarch source_ref: "esde resources/systems/linux/es_systems.xml:2420" searched_by: + - emulator: retroarch + core: mame + reads: + - vsmile + machines: + - vsmile + source_ref: "esde resources/systems/linux/es_systems.xml:2424" - emulator: mame reads: - vsmile diff --git a/schemas/emulator.schema.json b/schemas/emulator.schema.json index 7bb563009..f684a8fba 100644 --- a/schemas/emulator.schema.json +++ b/schemas/emulator.schema.json @@ -1112,6 +1112,24 @@ }, "description": "Settings the standalone build reads as a list of directories it searches one after the other, each mapped to the subfolder of the layout (relative to standalone_directories, empty for the whole of it) its directories stand for: openMSX's filepool entries are searched like share/systemroms, XRoar's rompath entries hold the ROMs themselves. A file in any entry is read, so several platform records naming entries give the first one a pack can fill." }, + "libretro_pools": { + "type": "object", + "additionalProperties": { + "oneOf": [ + {"type": "string"}, + { + "type": "object", + "additionalProperties": false, + "required": ["folder", "source_ref"], + "properties": { + "folder": {"type": "string"}, + "source_ref": {"type": "string", "minLength": 1, "description": "Where the build reads the option from its content"} + } + } + ] + }, + "description": "Options of the command line a libretro build is handed as its content that set a list of directories it searches, each mapped to the folder below the system directory whose files those directories stand for: libretro MAME hands MAME /mame/bios unless the content's own -rompath replaces it." + }, "prose_written_at": { "type": "string", "pattern": "^[0-9a-f]{40}$", diff --git a/schemas/romfolders.schema.json b/schemas/romfolders.schema.json index 6bff93d77..14c0d443a 100644 --- a/schemas/romfolders.schema.json +++ b/schemas/romfolders.schema.json @@ -123,13 +123,14 @@ "arcade": { "type": "boolean" }, "searched_by": { "type": "array", - "description": "The standalone emulators whose commands for this folder pass a ROM search path, and the folders below the roms root it names.", + "description": "The emulators, or the libretro core with its runner, whose commands for this folder pass a ROM search path, and the folders below the roms root it names.", "items": { "type": "object", "additionalProperties": false, "required": ["emulator", "reads", "source_ref"], "properties": { "emulator": { "type": "string", "minLength": 1 }, + "core": { "type": "string", "minLength": 1, "description": "The libretro core RetroArch starts, handed the search path in its content command line." }, "reads": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, "machines": { "type": "array", "description": "The machines the commands start, as the emulator names them.", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, "any_machine": { "type": "boolean", "description": "A command starts the game itself as the machine (ES-DE's %BASENAME%)." }, diff --git a/scripts/common.py b/scripts/common.py index 41bd5f527..3c8510cf2 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -2872,9 +2872,10 @@ CONTENT_SCOPE_TAG = "contentscope:" # [core name, roms folder, (tree, path)]: a libretro core the platform # launches for the games of that folder, which it reads beside. CONTENT_FOLDER_PREFIX = "contentdir:" -# [emulator, (tree, path), system, machines, any machine, source_ref]: a -# standalone emulator handed a roms folder as its ROM search path on the -# command line of a system's launch. +# [emulator or core, (tree, path), system, machines, any machine, +# source_ref, build]: a standalone emulator, or a libretro core in the +# command line it is handed as content, given a roms folder as its ROM +# search path by a system's launch command. ROM_SEARCH_PREFIX = "romsearch:" # The frontend writes the BIOS it hands a core beside the content: the # folder it gives the BIOS is the content's. @@ -3413,7 +3414,7 @@ def _core_key(name: str) -> str: def content_folder_tags(config: dict) -> set[str]: """The roms folders a platform launches each libretro core for, and the - ROM search paths its commands hand standalone emulators, as tags. + ROM search paths its commands hand emulators and cores, as tags. A core reading its BIOS sets beside the game (MAME 2003's osd_get_path gives FILETYPE_ROM the content directory) reads them in the folder of @@ -3466,9 +3467,10 @@ def content_folder_tags(config: dict) -> set[str]: for read in search.get("reads") or []: if read in folders: tags.add(ROM_SEARCH_PREFIX + json.dumps([ - str(search["emulator"]), place(read), str(row["folder"]), - sorted(search.get("machines") or []), bool(search.get("any_machine")), - str(search.get("source_ref", "")), + str(search.get("core") or search["emulator"]), place(read), + str(row["folder"]), sorted(search.get("machines") or []), + bool(search.get("any_machine")), str(search.get("source_ref", "")), + "libretro" if search.get("core") else "standalone", ])) return tags @@ -3550,10 +3552,11 @@ def content_layout( A libretro entry read beside the content (``load_from: content_dir``) goes to the folder of each system the platform launches the core for, - and is named as read outside the BIOS folder where it knows none. A - standalone entry no launcher record places, under the root of the - layout a passed ROM search path stands for, goes to each folder a - command passes for a machine that reads it. Outside a platform (no + and is named as read outside the BIOS folder where it knows none. An + entry in the folder a passed ROM search path stands for (the root of a + standalone layout no launcher record places it in, a ``libretro_pools`` + folder) goes to each folder a command passes for a machine that reads + it, a libretro one staying where it is too. Outside a platform (no CONTENT_SCOPE_TAG) the view is left as it is. """ tags = [t for t in standalone_cores if t.startswith(CONTENT_TAG_PREFIXES)] @@ -3571,6 +3574,29 @@ def content_layout( files = view.get("files") or [] out: list = [] changed = False + searches = [ + json.loads(t[len(ROM_SEARCH_PREFIX):]) + for t in tags if t.startswith(ROM_SEARCH_PREFIX) + ] + build = "standalone" if standalone else "libretro" + searches = [s for s in searches if _core_key(s[0]) in names and s[6] == build] + + def search_reads(name: str) -> list[tuple[str, str]]: + stem = name.rsplit(".", 1)[0] + return sorted({ + tuple(where) for _emu, where, system, machines, any_machine, _ref, _build in searches + if where and stem in rom_search_sets(emu_name, system, machines, any_machine) + }) + + def roms_entry(entry: dict, tree: str, folder: str, rel: str) -> dict: + # Below the roms root inside the install tree (EmuELEC's + # /storage/roms): a plain dest the platform prefix skips, as a + # standalone entry placed there (_placed_entry). + where: dict[str, object] = ( + {"unprefixed": True} if tree == "install" else {"root": ROMS_ROOT} + ) + return {**entry, **where, "path": f"{folder}/{rel}", "layout_path": rel} + if not standalone: folders = sorted({ tuple(where) for core, _folder, where in ( @@ -3578,11 +3604,25 @@ def content_layout( for t in tags if t.startswith(CONTENT_FOLDER_PREFIX) ) if core in names and where }) + # The folders a passed -rompath replaces the build's own search + # path with stand for these: libretro MAME hands MAME + # /mame/bios unless the content's command line names + # another (retro_init.cpp Set_Path_Option, execute_game_cmd). + from launchers import pool_folders # noqa: PLC0415 + + pools = set(pool_folders({"standalone_pools": view.get("libretro_pools")}).values()) for f in files: - if (not isinstance(f, dict) or _content_load(f) != "content_dir" - or f.get("category") == "game_data"): + if not isinstance(f, dict): + out.append(f) + continue + if _content_load(f) != "content_dir" or f.get("category") == "game_data": # Game data read beside the content is the game's own. out.append(f) + parent, _, rel = str(f.get("path") or "").rpartition("/") + if searches and parent in pools and rel: + reads = search_reads(rel) + changed |= bool(reads) + out.extend(roms_entry(f, tree, folder, rel) for tree, folder in reads) continue changed = True plain = _without_libretro_load(f) @@ -3590,20 +3630,8 @@ def content_layout( out.append({**plain, "unplaced": OUTSIDE_BIOS_FOLDER}) continue rel = str(f.get("path") or f.get("name") or "") - for tree, folder in folders: - # Below the roms root inside the install tree (EmuELEC's - # /storage/roms): a plain dest the platform prefix skips, as - # a standalone entry placed there (_placed_entry). - where: dict[str, object] = ( - {"unprefixed": True} if tree == "install" else {"root": ROMS_ROOT} - ) - out.append({**plain, **where, "path": f"{folder}/{rel}", "layout_path": rel}) + out.extend(roms_entry(plain, tree, folder, rel) for tree, folder in folders) return {**view, "files": out} if changed else view - searches = [ - json.loads(t[len(ROM_SEARCH_PREFIX):]) - for t in tags if t.startswith(ROM_SEARCH_PREFIX) - ] - searches = [s for s in searches if _core_key(s[0]) in names] pools = {str(v).strip("/") for v in (view.get("standalone_pools") or {}).values()} if not searches or "" not in pools: return view @@ -3612,11 +3640,7 @@ def content_layout( if not layout or "/" in layout or f.get("unplaced") != OUTSIDE_BIOS_FOLDER: out.append(f) continue - stem = layout.rsplit(".", 1)[0] - reads = sorted({ - tuple(where) for _emu, where, system, machines, any_machine, _ref in searches - if where and stem in rom_search_sets(emu_name, system, machines, any_machine) - }) + reads = search_reads(layout) if not reads: out.append(f) continue diff --git a/scripts/scraper/romfolders/es.py b/scripts/scraper/romfolders/es.py index ac9f85ad7..25bcb3fb2 100644 --- a/scripts/scraper/romfolders/es.py +++ b/scripts/scraper/romfolders/es.py @@ -526,21 +526,55 @@ def _alternative_emulators(text: str, function: str) -> dict[str, tuple[str, int _ROMPATH_OPTIONS = ("-rompath", "-rp") +def _core_words(command: str) -> tuple[str, list[str]] | None: + """The core and the words of the content RetroArch hands it. + + ES-DE starts the libretro MAME core with a quoted command line as its + content (`-L .../mame_libretro.so "apple2e -rompath \\"...\\" ..."`): popen + runs it through the shell (es-core/src/utils/PlatformUtil.cpp:231, 257), + and the core splits the content on spaces and quotes when it is no file + (retro_init.cpp parse_cmdline, mmain2). + """ + core = _RA_CORE.search(command) + if core is None: + return None + try: + args = shlex.split(command) + at = args.index("-L") + content = shlex.split(args[at + 2]) if at + 2 < len(args) else [] + except ValueError: + return None + return core.group(1), content + + def _searched_by(commands: list[tuple[str, str, int | None]], key: str, path: str) -> list[dict]: - """The ROM folders each standalone emulator's commands pass it, by emulator. + """The ROM folders each emulator's commands pass it, by emulator and core. ES-DE starts standalone MAME with `-rompath %GAMEDIR%\\;%ROMPATH%/` and a machine, or %BASENAME% where the game is the machine. The command - line outranks mame.ini. %GAMEDIR% is the game's own folder, no folder a - pack fills. + line outranks mame.ini. The libretro MAME core gets the same option in + the command line it is handed as content, after the machine. %GAMEDIR% + is the game's own folder, no folder a pack fills. """ - found: dict[str, dict] = {} + found: dict[tuple[str, str], dict] = {} for _label, command, line in commands: - emulator = _EMULATOR.search(command) - if emulator is None or _RA_CORE.search(command): - continue - words = command.replace("\\;", ";").split() - at = next((i for i, w in enumerate(words) if w in _ROMPATH_OPTIONS), None) + libretro = _core_words(command) + if libretro is not None: + core, words = libretro + if words[:1] == [core]: + # A first word naming the core is dropped (mmain2). + words = words[1:] + name = "retroarch" + at = next((i for i, w in enumerate(words) if w in _ROMPATH_OPTIONS), None) + machine = words[0] if words and at else "" + else: + emulator = _EMULATOR.search(command) + if emulator is None: + continue + core, name = "", emulator.group(1).lower() + words = command.replace("\\;", ";").split() + at = next((i for i, w in enumerate(words) if w in _ROMPATH_OPTIONS), None) + machine = words[at + 2] if at is not None and at + 2 < len(words) else "" if at is None or at + 1 >= len(words): continue reads = [ @@ -549,11 +583,10 @@ def _searched_by(commands: list[tuple[str, str, int | None]], key: str, path: st ] if not reads: continue - name = emulator.group(1).lower() - record = found.setdefault(name, {"emulator": name, "reads": [], "machines": [], - "any_machine": False, "lines": []}) + record = found.setdefault((name, core), {"emulator": name, "core": core, "reads": [], + "machines": [], "any_machine": False, + "lines": []}) record["reads"] += [r for r in reads if r not in record["reads"]] - machine = words[at + 2] if at + 2 < len(words) else "" if not machine or machine.startswith("%"): record["any_machine"] = True elif machine not in record["machines"]: @@ -561,7 +594,10 @@ def _searched_by(commands: list[tuple[str, str, int | None]], key: str, path: st record["lines"].append(line) rows = [] for record in found.values(): - row = {"emulator": record["emulator"], "reads": record["reads"]} + row = {"emulator": record["emulator"]} + if record["core"]: + row["core"] = record["core"] + row["reads"] = record["reads"] if record["machines"]: row["machines"] = record["machines"] if record["any_machine"]: diff --git a/tests/test_launcher_placement.py b/tests/test_launcher_placement.py index 2ab289e51..5bddd1974 100644 --- a/tests/test_launcher_placement.py +++ b/tests/test_launcher_placement.py @@ -1148,6 +1148,32 @@ class MameOnRetroDeckRomPaths(unittest.TestCase): self.assertEqual(places["stvbios.zip"] - {"arcade", "mame", "consolearcade"}, {"stv"}) +class LibretroMameOnEsdeRomPaths(unittest.TestCase): + """ES-DE hands the libretro MAME core a command line as its content, + with -rompath "%GAMEDIRRAW%;%ROMPATH%/" after the machine. The + core passes it to MAME after its own /mame/bios, and the later + value wins (retro_init.cpp:580-597, 902-940, options.cpp:260-276).""" + + def test_the_rom_folders_file_records_the_core(self) -> None: + with (REPO_ROOT / "platforms" / "romfolders" / "retrodeck.yml").open() as f: + rows = yaml.safe_load(f)["folders"] + found = {r["folder"]: s for r in rows for s in r.get("searched_by") or [] + if s.get("core") == "mame"} + self.assertEqual(len(found), 21) + self.assertEqual(found["apple2"]["machines"], ["apple2e"]) + self.assertEqual(found["atari7800"]["reads"], ["atari7800"]) + self.assertEqual(found["atari7800"]["emulator"], "retroarch") + + def test_sets_also_land_in_the_folder_the_command_names(self) -> None: + # RetroDECK's roms/ sits beside bios/ in the install tree. + for platform, read in (("retrodeck", ("", "roms/gamate/gamate.zip")), + ("emudeck", ("roms", "gamate/gamate.zip"))): + view = libretro_view("mame", platform) + places = {(e.get("root") or "", e["path"]) for e in view["files"] + if e["name"] == "gamate.zip"} + self.assertEqual(places, {("", "mame/bios/gamate.zip"), read}, platform) + + class MacBootDisksOnKnulli(unittest.TestCase): def test_the_hard_records_bind(self) -> None: # mameGenerator.py and libretroMAMEConfig.py pass the boot disk as diff --git a/tests/test_romfolders_es.py b/tests/test_romfolders_es.py index fb1f44aba..af4075e9a 100644 --- a/tests/test_romfolders_es.py +++ b/tests/test_romfolders_es.py @@ -207,12 +207,19 @@ class EsdeFormat(unittest.TestCase): self.assertNotIn("any_machine", tano) self.assertEqual(tano["source_ref"], "os es_systems.xml:20") - def test_the_game_itself_as_machine_and_libretro_left_out(self) -> None: - (arcade,) = self.rows["arcade"]["searched_by"] - self.assertEqual(arcade["emulator"], "mame") - self.assertTrue(arcade["any_machine"]) - self.assertNotIn("machines", arcade) + def test_the_game_itself_as_machine(self) -> None: + libretro, standalone = self.rows["arcade"]["searched_by"] + self.assertEqual(standalone["emulator"], "mame") + self.assertNotIn("core", standalone) + self.assertTrue(standalone["any_machine"]) + self.assertNotIn("machines", standalone) self.assertNotIn("searched_by", self.rows["psx"]) + # The libretro core reads the -rompath of the command line it is + # handed as content (retro_init.cpp execute_game_cmd). + self.assertEqual((libretro["emulator"], libretro["core"]), ("retroarch", "mame")) + self.assertEqual(libretro["reads"], ["arcade"]) + self.assertTrue(libretro["any_machine"]) + self.assertEqual(libretro["source_ref"], "os es_systems.xml:27") def test_first_command_without_alternative(self) -> None: rows = by_folder(scrape("esde", "esde", {"systems": {"source": "os", "path": "es_systems.xml"}}))