feat: standalone emulator support for batocera and multi-platform name mapping

resolve_platform_cores() builds reverse index from profile cores: field,
fixing 17 name mismatches across Batocera, RetroBat, and Recalbox
(genesisplusgx, pce_fast, pcfx, vb, mame078plus, vice cores, etc.).

standalone_path field on file entries + standalone_cores on platform
YAMLs enable mode-aware pack generation. find_undeclared_files() uses
standalone_path for cores the platform runs standalone, filters by
mode: libretro/standalone per file.

batocera.yml gains standalone_cores (92 entries from configgen-defaults).
generate_readme.py dynamically lists platforms from registry.
3 profiles updated for standalone type/path (mame, hatari, mupen64plus_next).
78 E2E tests pass, pipeline verified.
This commit is contained in:
Abdessamad Derraz
2026-03-26 00:44:21 +01:00
parent 44dc946217
commit 3f676b75e8
31 changed files with 1492 additions and 40 deletions

View File

@@ -1,8 +1,8 @@
# RetroBIOS # RetroBIOS
Complete BIOS and firmware packs for RetroArch, Batocera, Recalbox, Lakka, RetroPie, EmuDeck, RetroBat, RetroDECK, and RomM. Complete BIOS and firmware packs for Batocera, EmuDeck, Lakka, Recalbox, RetroArch, RetroBat, RetroDECK, RetroPie, and RomM.
**6,748** verified files across **294** systems, ready to extract into your emulator's BIOS directory. **6,748** verified files across **305** systems, ready to extract into your emulator's BIOS directory.
## Download BIOS packs ## Download BIOS packs
@@ -26,14 +26,14 @@ BIOS, firmware, and system files for consoles from Atari to PlayStation 3.
Each file is checked against the emulator's source code to match what the code actually loads at runtime. Each file is checked against the emulator's source code to match what the code actually loads at runtime.
- **9 platforms** supported with platform-specific verification - **9 platforms** supported with platform-specific verification
- **306 emulators** profiled from source (RetroArch cores + standalone) - **307 emulators** profiled from source (RetroArch cores + standalone)
- **294 systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...) - **305 systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
- **6,748 files** verified with MD5, SHA1, CRC32 checksums - **6,748 files** verified with MD5, SHA1, CRC32 checksums
- **5251 MB** total collection size - **5251 MB** total collection size
## Supported systems ## Supported systems
NES, SNES, Nintendo 64, GameCube, Wii, Game Boy, Game Boy Advance, Nintendo DS, Nintendo 3DS, Switch, PlayStation, PlayStation 2, PlayStation 3, PSP, PS Vita, Mega Drive, Saturn, Dreamcast, Game Gear, Master System, Neo Geo, Atari 2600, Atari 7800, Atari Lynx, Atari ST, MSX, PC Engine, TurboGrafx-16, ColecoVision, Intellivision, Commodore 64, Amiga, ZX Spectrum, Arcade (MAME), and 260+ more. NES, SNES, Nintendo 64, GameCube, Wii, Game Boy, Game Boy Advance, Nintendo DS, Nintendo 3DS, Switch, PlayStation, PlayStation 2, PlayStation 3, PSP, PS Vita, Mega Drive, Saturn, Dreamcast, Game Gear, Master System, Neo Geo, Atari 2600, Atari 7800, Atari Lynx, Atari ST, MSX, PC Engine, TurboGrafx-16, ColecoVision, Intellivision, Commodore 64, Amiga, ZX Spectrum, Arcade (MAME), and 271+ more.
Full list with per-file details: **[https://abdess.github.io/retrobios/](https://abdess.github.io/retrobios/)** Full list with per-file details: **[https://abdess.github.io/retrobios/](https://abdess.github.io/retrobios/)**
@@ -79,4 +79,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
This repository provides BIOS files for personal backup and archival purposes. This repository provides BIOS files for personal backup and archival purposes.
*Auto-generated on 2026-03-25T22:12:06Z* *Auto-generated on 2026-03-25T23:43:15Z*

View File

@@ -1,5 +1,5 @@
{ {
"generated_at": "2026-03-25T22:06:53Z", "generated_at": "2026-03-25T23:42:57Z",
"total_files": 6748, "total_files": 6748,
"total_size": 5505760050, "total_size": 5505760050,
"files": { "files": {

View File

@@ -1,7 +1,7 @@
emulator: Beetle PC-FX (Mednafen) emulator: Beetle PC-FX (Mednafen)
type: libretro type: libretro
core_classification: community_fork core_classification: community_fork
cores: [mednafen_pcfx] cores: [mednafen_pcfx, pcfx]
source: "https://github.com/libretro/beetle-pcfx-libretro" source: "https://github.com/libretro/beetle-pcfx-libretro"
upstream: "https://mednafen.github.io/" upstream: "https://mednafen.github.io/"
profiled_date: "2026-03-24" profiled_date: "2026-03-24"

View File

@@ -6,7 +6,7 @@ upstream: "https://mednafen.github.io/"
profiled_date: "2026-03-24" profiled_date: "2026-03-24"
core_version: "v0.9.36.1" core_version: "v0.9.36.1"
display_name: "Nintendo - Virtual Boy (Beetle VB)" display_name: "Nintendo - Virtual Boy (Beetle VB)"
cores: [mednafen_vb] cores: [mednafen_vb, vb]
systems: [nintendo-virtualboy] systems: [nintendo-virtualboy]
notes: | notes: |

View File

@@ -6,7 +6,7 @@ upstream: "https://github.com/bsnes-emu/bsnes"
profiled_date: "2026-03-23" profiled_date: "2026-03-23"
core_version: "v10.6" core_version: "v10.6"
display_name: "Nintendo - SNES / SFC (bsnes-hd beta)" display_name: "Nintendo - SNES / SFC (bsnes-hd beta)"
cores: [bsnes_hd_beta] cores: [bsnes_hd_beta, bsneshd]
systems: systems:
- nintendo-snes - nintendo-snes
- nintendo-sgb - nintendo-sgb

1248
emulators/clk.yml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@ core_version: "v1.7.4"
display_name: "Sega - MS/GG/MD/CD (Genesis Plus GX)" display_name: "Sega - MS/GG/MD/CD (Genesis Plus GX)"
cores: cores:
- genesis_plus_gx - genesis_plus_gx
- genesisplusgx
systems: systems:
- sega-megadrive - sega-megadrive
- sega-megacd - sega-megacd

View File

@@ -8,6 +8,7 @@ core_version: "v1.7.4"
display_name: "Sega - MS/GG/MD/CD (Genesis Plus GX Wide)" display_name: "Sega - MS/GG/MD/CD (Genesis Plus GX Wide)"
cores: cores:
- genesis_plus_gx_wide - genesis_plus_gx_wide
- genesisplusgxwide
systems: systems:
- sega-megadrive - sega-megadrive
- sega-megacd - sega-megacd

View File

@@ -1,5 +1,5 @@
emulator: Hatari emulator: Hatari
type: libretro type: standalone + libretro
core_classification: frozen_snapshot core_classification: frozen_snapshot
source: "https://github.com/libretro/hatari" source: "https://github.com/libretro/hatari"
upstream: "https://github.com/hatari/hatari" upstream: "https://github.com/hatari/hatari"

View File

@@ -1,5 +1,5 @@
emulator: MAME emulator: MAME
type: libretro type: standalone + libretro
core_classification: official_port core_classification: official_port
source: "https://github.com/libretro/mame" source: "https://github.com/libretro/mame"
upstream: "https://github.com/mamedev/mame" upstream: "https://github.com/mamedev/mame"

View File

@@ -11,6 +11,7 @@ mame_version: "0.78 (plus backports)"
cores: cores:
- mame2003_plus - mame2003_plus
- mame078plus
systems: systems:
- snk-neogeo-mvs - snk-neogeo-mvs

View File

@@ -6,7 +6,7 @@ upstream: "https://mednafen.github.io/"
profiled_date: "2026-03-24" profiled_date: "2026-03-24"
core_version: "v1.31.0.0" core_version: "v1.31.0.0"
display_name: "NEC - PC Engine / CD (Beetle PCE FAST)" display_name: "NEC - PC Engine / CD (Beetle PCE FAST)"
cores: [mednafen_pce_fast] cores: [mednafen_pce_fast, pce_fast]
systems: [nec-pc-engine] systems: [nec-pc-engine]
verification: existence verification: existence
notes: > notes: >

View File

@@ -9,7 +9,7 @@ source: "https://github.com/libretro/Mesen-S"
upstream: "https://github.com/SourMesen/Mesen-S" upstream: "https://github.com/SourMesen/Mesen-S"
profiled_date: "2026-03-24" profiled_date: "2026-03-24"
core_version: "0.4.0" core_version: "0.4.0"
cores: [mesen-s] cores: [mesen-s, mesen_s]
systems: [nintendo-snes, nintendo-gb, nintendo-gbc, nintendo-super-game-boy, nintendo-satellaview] systems: [nintendo-snes, nintendo-gb, nintendo-gbc, nintendo-super-game-boy, nintendo-satellaview]
notes: > notes: >

View File

@@ -12,10 +12,11 @@ cores: [mupen64plus_next, mupen64plus_next_develop, mupen64plus_next_gles3, mupe
files: files:
- name: "IPL.n64" - name: "IPL.n64"
path: "Mupen64plus/IPL.n64" path: "Mupen64plus/IPL.n64"
standalone_path: "64DD_IPL.bin"
aliases: ["64DD_IPL.bin"]
size: 4194304 size: 4194304
required: false required: false
description: "64DD IPL ROM" description: "64DD IPL ROM"
note: "Only needed for N64 Disk Drive games (.ndd) via subsystem API. Accepts Z64, N64, and V64 byte-swap formats."
source_ref: "mupen64plus-core/src/main/main.c:940-1024" source_ref: "mupen64plus-core/src/main/main.c:940-1024"
- name: "font.ttf" - name: "font.ttf"

View File

@@ -6,7 +6,7 @@ upstream: "https://github.com/opentyrian/opentyrian"
profiled_date: "2026-03-24" profiled_date: "2026-03-24"
core_version: "1.0.0.6" core_version: "1.0.0.6"
display_name: "Tyrian (OpenTyrian)" display_name: "Tyrian (OpenTyrian)"
cores: [opentyrian] cores: [opentyrian, tyrian]
systems: [tyrian] systems: [tyrian]
verification: existence verification: existence

View File

@@ -6,7 +6,7 @@ upstream: "https://sourceforge.net/projects/vice-emu/"
profiled_date: "2026-03-25" profiled_date: "2026-03-25"
core_version: "3.10" core_version: "3.10"
display_name: "Commodore - C128 (VICE x128)" display_name: "Commodore - C128 (VICE x128)"
cores: [vice_x128] cores: [vice_x128, x128]
systems: [commodore-c128] systems: [commodore-c128]
notes: > notes: >
System ROMs embedded in binary: C128 kernal (318020-05), chargen (390059-01), System ROMs embedded in binary: C128 kernal (318020-05), chargen (390059-01),

View File

@@ -6,7 +6,7 @@ upstream: "https://sourceforge.net/projects/vice-emu/"
profiled_date: "2026-03-25" profiled_date: "2026-03-25"
core_version: "3.10" core_version: "3.10"
display_name: "Commodore - C64 (VICE x64, fast)" display_name: "Commodore - C64 (VICE x64, fast)"
cores: [vice_x64] cores: [vice_x64, x64]
systems: [commodore-c64] systems: [commodore-c64]
notes: > notes: >
System ROMs embedded in binary: C64 BASIC (901226-01), chargen (901225-01), System ROMs embedded in binary: C64 BASIC (901226-01), chargen (901225-01),

View File

@@ -6,7 +6,7 @@ upstream: "https://sourceforge.net/projects/vice-emu/"
profiled_date: "2026-03-25" profiled_date: "2026-03-25"
core_version: "3.10" core_version: "3.10"
display_name: "Commodore - CBM-II 6x0/7x0 (VICE xcbm2)" display_name: "Commodore - CBM-II 6x0/7x0 (VICE xcbm2)"
cores: [vice_xcbm2] cores: [vice_xcbm2, xcbm2]
systems: [commodore-cbm-ii] systems: [commodore-cbm-ii]
notes: > notes: >
System ROMs embedded in binary: chargen 600 (901237-01), chargen 700 (901232-01), System ROMs embedded in binary: chargen 600 (901237-01), chargen 700 (901232-01),

View File

@@ -6,7 +6,7 @@ upstream: "https://sourceforge.net/projects/vice-emu/"
profiled_date: "2026-03-25" profiled_date: "2026-03-25"
core_version: "3.10" core_version: "3.10"
display_name: "Commodore - CBM-II 5x0 (VICE xcbm5x0)" display_name: "Commodore - CBM-II 5x0 (VICE xcbm5x0)"
cores: [vice_xcbm5x0] cores: [vice_xcbm5x0, xcbm5x0]
systems: [commodore-cbm-ii] systems: [commodore-cbm-ii]
notes: > notes: >
System ROMs embedded in binary: chargen 500 (901225-01), kernal 500 System ROMs embedded in binary: chargen 500 (901225-01), kernal 500

View File

@@ -6,7 +6,7 @@ upstream: "https://sourceforge.net/projects/vice-emu/"
profiled_date: "2026-03-25" profiled_date: "2026-03-25"
core_version: "3.10" core_version: "3.10"
display_name: "Commodore - PET (VICE xpet)" display_name: "Commodore - PET (VICE xpet)"
cores: [vice_xpet] cores: [vice_xpet, xpet]
systems: [commodore-pet] systems: [commodore-pet]
notes: > notes: >
System ROMs embedded in binary: kernal 1 (901439-04-07), kernal 2 (901465-03), System ROMs embedded in binary: kernal 1 (901439-04-07), kernal 2 (901465-03),

View File

@@ -6,7 +6,7 @@ upstream: "https://sourceforge.net/projects/vice-emu/"
profiled_date: "2026-03-25" profiled_date: "2026-03-25"
core_version: "3.10" core_version: "3.10"
display_name: "Commodore - PLUS/4 (VICE xplus4)" display_name: "Commodore - PLUS/4 (VICE xplus4)"
cores: [vice_xplus4] cores: [vice_xplus4, xplus4]
systems: [commodore-plus4] systems: [commodore-plus4]
notes: > notes: >
All system ROMs embedded in binary: BASIC (318006-01), kernal PAL (318004-05), All system ROMs embedded in binary: BASIC (318006-01), kernal PAL (318004-05),

View File

@@ -6,7 +6,7 @@ upstream: "https://sourceforge.net/projects/vice-emu/"
profiled_date: "2026-03-25" profiled_date: "2026-03-25"
core_version: "3.10" core_version: "3.10"
display_name: "Commodore - C64 SuperCPU (VICE xscpu64)" display_name: "Commodore - C64 SuperCPU (VICE xscpu64)"
cores: [vice_xscpu64] cores: [vice_xscpu64, xscpu64]
systems: [commodore-c64-supercpu] systems: [commodore-c64-supercpu]
notes: > notes: >
Embedded SCPU64 ROM V0.07 (free replacement by Soci/Singular, 64 KB), chargen Embedded SCPU64 ROM V0.07 (free replacement by Soci/Singular, 64 KB), chargen

View File

@@ -6,7 +6,7 @@ upstream: "https://sourceforge.net/projects/vice-emu/"
profiled_date: "2026-03-25" profiled_date: "2026-03-25"
core_version: "3.10" core_version: "3.10"
display_name: "Commodore - VIC-20 (VICE xvic)" display_name: "Commodore - VIC-20 (VICE xvic)"
cores: [vice_xvic] cores: [vice_xvic, xvic]
systems: [commodore-vic20] systems: [commodore-vic20]
notes: > notes: >
System ROMs embedded in binary: BASIC (901486-01), chargen (901460-03), System ROMs embedded in binary: BASIC (901486-01), chargen (901460-03),

View File

@@ -399,9 +399,10 @@ nav:
- PCSX-ReARMed: emulators/pcsx_rearmed.md - PCSX-ReARMed: emulators/pcsx_rearmed.md
- Launchers (1): - Launchers (1):
- Dolphin Launcher: emulators/dolphin_launcher.md - Dolphin Launcher: emulators/dolphin_launcher.md
- Other (10): - Other (11):
- Beetle GBA (Mednafen): emulators/beetle_gba.md - Beetle GBA (Mednafen): emulators/beetle_gba.md
- Cemu: emulators/cemu.md - Cemu: emulators/cemu.md
- Clock Signal (CLK): emulators/clk.md
- ep128emu-core: emulators/ep128emu.md - ep128emu-core: emulators/ep128emu.md
- PCSX2: emulators/pcsx2.md - PCSX2: emulators/pcsx2.md
- Redream: emulators/redream.md - Redream: emulators/redream.md

View File

@@ -5,6 +5,87 @@ source: "https://raw.githubusercontent.com/batocera-linux/batocera.linux/master/
base_destination: bios base_destination: bios
hash_type: md5 hash_type: md5
verification_mode: md5 verification_mode: md5
standalone_cores:
- abuse
- azahar
- bstone
- cannonball
- catacombgl
- cdogs
- cemu
- cgenius
- citron
- clk
- corsixth
- demul
- devilutionx
- dhewm3
- dolphin
- dxx-rebirth
- easyrpg
- ecwolf
- eduke32
- eka2l1
- etlegacy
- fallout1-ce
- fallout2-ce
- flatpak
- fury
- gsplus
- gzdoom
- hcl
- hurrican
- hypseus-singe
- ikemen
- ioquake3
- iortcw
- jazz2-native
- lexaloffle
- lindbergh-loader
- mame
- model2emu
- moonlight
- mupen64plus
- odcommander
- openbor
- openjazz
- openjk
- openjkdf2
- openmohaa
- pcsx2
- play
- ppsspp
- pygame
- pyxel
- raze
- rpcs3
- ruffle
- samcoupe
- scummvm
- sdlpop
- shadps4
- solarus
- sonic-mania
- sonic2013
- sonic3-air
- steam
- supermodel
- taradino
- theforceengine
- thextech
- tr1x
- tr2x
- tsugaru
- tyrian
- uqm
- vice
- vita3k
- vpinball
- x16emu
- xash3d_fwgs
- xemu
- xenia-canary
- yquake2
cores: cores:
- 81 - 81
- a5200 - a5200

View File

@@ -508,11 +508,20 @@ def resolve_platform_cores(
} }
if isinstance(cores_config, list): if isinstance(cores_config, list):
core_set = set(cores_config) core_set = {str(c) for c in cores_config}
# Build reverse index: platform core name -> profile name
# Uses profile filename (dict key) + all names in cores: field
core_to_profile: dict[str, str] = {}
for name, p in profiles.items():
if p.get("type") == "alias":
continue
core_to_profile[name] = name
for core_name in p.get("cores", []):
core_to_profile[str(core_name)] = name
return { return {
name for name in profiles core_to_profile[c]
if name in core_set for c in core_set
and profiles[name].get("type") != "alias" if c in core_to_profile
} }
# Fallback: system ID intersection # Fallback: system ID intersection

View File

@@ -204,7 +204,7 @@ def _collect_emulator_extras(
if not u["in_repo"]: if not u["in_repo"]:
continue continue
name = u["name"] name = u["name"]
dest = name dest = u.get("path") or name
full_dest = f"{base_dest}/{dest}" if base_dest else dest full_dest = f"{base_dest}/{dest}" if base_dest else dest
if full_dest in seen: if full_dest in seen:
continue continue

View File

@@ -109,8 +109,9 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
lines = [ lines = [
"# RetroBIOS", "# RetroBIOS",
"", "",
f"Complete BIOS and firmware packs for RetroArch, Batocera, Recalbox, Lakka," f"Complete BIOS and firmware packs for "
f" RetroPie, EmuDeck, RetroBat, and RetroDECK.", f"{', '.join(c['platform'] for c in sorted(coverages.values(), key=lambda x: x['platform'])[:-1])}"
f", and {sorted(coverages.values(), key=lambda x: x['platform'])[-1]['platform']}.",
"", "",
f"**{total_files:,}** verified files across **{len(system_ids)}** systems," f"**{total_files:,}** verified files across **{len(system_ids)}** systems,"
f" ready to extract into your emulator's BIOS directory.", f" ready to extract into your emulator's BIOS directory.",

View File

@@ -127,8 +127,12 @@ class Scraper(BaseScraper):
def __init__(self, url: str = SOURCE_URL): def __init__(self, url: str = SOURCE_URL):
super().__init__(url=url) super().__init__(url=url)
def _fetch_cores(self) -> list[str]: def _fetch_cores(self) -> tuple[list[str], list[str]]:
"""Extract core names from Batocera configgen-defaults.yml.""" """Extract core names and standalone cores from configgen-defaults.yml.
Returns (all_cores, standalone_cores) where standalone_cores are
those with emulator != "libretro".
"""
try: try:
req = urllib.request.Request( req = urllib.request.Request(
CONFIGGEN_DEFAULTS_URL, CONFIGGEN_DEFAULTS_URL,
@@ -142,13 +146,19 @@ class Scraper(BaseScraper):
) from e ) from e
data = yaml.safe_load(raw) data = yaml.safe_load(raw)
cores: set[str] = set() cores: set[str] = set()
standalone: set[str] = set()
for system, cfg in data.items(): for system, cfg in data.items():
if system == "default" or not isinstance(cfg, dict): if system == "default" or not isinstance(cfg, dict):
continue continue
core = cfg.get("core") emulator = cfg.get("emulator", "")
core = cfg.get("core", "")
if core: if core:
cores.add(core) cores.add(core)
return sorted(cores) if emulator and emulator != "libretro":
standalone.add(emulator)
if core and core != emulator:
standalone.add(core)
return sorted(cores), sorted(standalone)
def _extract_systems_dict(self, raw: str) -> dict: def _extract_systems_dict(self, raw: str) -> dict:
"""Extract and parse the 'systems' dict from the Python source via ast.literal_eval.""" """Extract and parse the 'systems' dict from the Python source via ast.literal_eval."""
@@ -295,7 +305,8 @@ class Scraper(BaseScraper):
if num.isdigit(): if num.isdigit():
batocera_version = num batocera_version = num
return { cores, standalone = self._fetch_cores()
result = {
"platform": "Batocera", "platform": "Batocera",
"version": batocera_version or "", "version": batocera_version or "",
"homepage": "https://batocera.org", "homepage": "https://batocera.org",
@@ -303,9 +314,12 @@ class Scraper(BaseScraper):
"base_destination": "bios", "base_destination": "bios",
"hash_type": "md5", "hash_type": "md5",
"verification_mode": "md5", "verification_mode": "md5",
"cores": self._fetch_cores(), "cores": cores,
"systems": systems, "systems": systems,
} }
if standalone:
result["standalone_cores"] = standalone
return result
def main(): def main():

View File

@@ -227,6 +227,7 @@ def find_undeclared_files(
profiles = emu_profiles if emu_profiles is not None else load_emulator_profiles(emulators_dir) profiles = emu_profiles if emu_profiles is not None else load_emulator_profiles(emulators_dir)
relevant = resolve_platform_cores(config, profiles) relevant = resolve_platform_cores(config, profiles)
standalone_set = set(str(c) for c in config.get("standalone_cores", []))
undeclared = [] undeclared = []
seen = set() seen = set()
for emu_name, profile in sorted(profiles.items()): for emu_name, profile in sorted(profiles.items()):
@@ -235,21 +236,36 @@ def find_undeclared_files(
if emu_name not in relevant: if emu_name not in relevant:
continue continue
# Check if this profile is standalone: match profile name or any cores: alias
is_standalone = emu_name in standalone_set or bool(
standalone_set & {str(c) for c in profile.get("cores", [])}
)
for f in profile.get("files", []): for f in profile.get("files", []):
fname = f.get("name", "") fname = f.get("name", "")
if not fname or fname in seen: if not fname or fname in seen:
continue continue
# Skip standalone-only files for libretro platforms # Mode filtering: skip files incompatible with platform's usage
if f.get("mode") == "standalone": file_mode = f.get("mode")
if file_mode == "standalone" and not is_standalone:
continue
if file_mode == "libretro" and is_standalone:
continue continue
if fname in declared_names: if fname in declared_names:
continue continue
# Determine destination path based on mode
if is_standalone:
dest = f.get("standalone_path") or f.get("path") or fname
else:
dest = f.get("path") or fname
in_repo = fname in by_name or fname.rsplit("/", 1)[-1] in by_name in_repo = fname in by_name or fname.rsplit("/", 1)[-1] in by_name
seen.add(fname) seen.add(fname)
undeclared.append({ undeclared.append({
"emulator": profile.get("emulator", emu_name), "emulator": profile.get("emulator", emu_name),
"name": fname, "name": fname,
"path": dest,
"required": f.get("required", False), "required": f.get("required", False),
"hle_fallback": f.get("hle_fallback", False), "hle_fallback": f.get("hle_fallback", False),
"category": f.get("category", "bios"), "category": f.get("category", "bios"),

View File

@@ -1098,5 +1098,83 @@ class TestE2E(unittest.TestCase):
self.assertIn("d.bin", names) self.assertIn("d.bin", names)
def test_108_standalone_path_in_undeclared(self):
"""Undeclared files use standalone_path when core is in standalone_cores."""
# Create a platform with standalone_cores
config = {
"platform": "TestStandalone",
"verification_mode": "existence",
"cores": ["test_emu"],
"standalone_cores": ["test_emu"],
"systems": {
"console-a": {
"files": [
{"name": "present_req.bin", "destination": "present_req.bin",
"required": True},
],
},
},
}
with open(os.path.join(self.platforms_dir, "test_standalone.yml"), "w") as fh:
yaml.dump(config, fh)
# Create emulator with standalone_path divergence
emu = {
"emulator": "TestStandaloneEmu",
"type": "standalone + libretro",
"cores": ["test_emu"],
"systems": ["console-a"],
"files": [
{"name": "libretro_file.bin", "path": "subdir/libretro_file.bin",
"standalone_path": "flat_file.bin", "required": True},
{"name": "standalone_only.bin", "mode": "standalone", "required": False},
{"name": "libretro_only.bin", "mode": "libretro", "required": False},
],
}
with open(os.path.join(self.emulators_dir, "test_standalone_emu.yml"), "w") as fh:
yaml.dump(emu, fh)
config = load_platform_config("test_standalone", self.platforms_dir)
profiles = load_emulator_profiles(self.emulators_dir)
undeclared = find_undeclared_files(config, self.emulators_dir, self.db, profiles)
by_name = {u["name"]: u for u in undeclared}
# standalone_path used for undeclared file (core is standalone)
self.assertIn("libretro_file.bin", by_name)
self.assertEqual(by_name["libretro_file.bin"]["path"], "flat_file.bin")
# standalone-only file IS included (core is standalone)
self.assertIn("standalone_only.bin", by_name)
# libretro-only file is EXCLUDED (core is standalone)
self.assertNotIn("libretro_only.bin", by_name)
def test_109_no_standalone_cores_uses_libretro_path(self):
"""Without standalone_cores, undeclared files use path: (libretro)."""
config = load_platform_config("test_existence", self.platforms_dir)
profiles = load_emulator_profiles(self.emulators_dir)
undeclared = find_undeclared_files(config, self.emulators_dir, self.db, profiles)
# standalone_only.bin should be excluded (platform has no standalone_cores)
names = {u["name"] for u in undeclared}
self.assertNotIn("standalone_only.bin", names)
def test_110_cores_alias_reverse_index(self):
"""resolve_platform_cores matches via cores: field aliases."""
emu = {
"emulator": "TestAliasCore",
"type": "libretro",
"cores": ["test_alias_core", "shortname"],
"systems": ["console-a"],
"files": [],
}
with open(os.path.join(self.emulators_dir, "test_alias_core.yml"), "w") as fh:
yaml.dump(emu, fh)
config = {"cores": ["shortname"]}
profiles = load_emulator_profiles(self.emulators_dir)
resolved = resolve_platform_cores(config, profiles)
self.assertIn("test_alias_core", resolved)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()