fix: keep a held file in emulator region packs

Emulator mode reduced region groups without knowing which files the
collection holds, so a requested-region image nobody had collected
withdrew the held one and left the slot empty. Platform mode already
kept it; both emulator readers now pass the database.
This commit is contained in:
Abdessamad Derraz committed 2026-10-18 03:52:47 +02:00
1 parent a40a68c1f7
commit 2dcb49fa4c
4 files changed
+47 -3

No files matched your search

+1 -1
View File
@@ -1351,7 +1351,7 @@ def generate_emulator_pack(
os.makedirs(output_dir, exist_ok=True)
region_drops: set[str] = (
emulator_region_drops(selected, standalone, regions, required_only)
emulator_region_drops(selected, standalone, regions, required_only, db)
if regions
else set()
)
+12 -1
View File
@@ -1028,6 +1028,7 @@ def emulator_region_drops(
standalone: bool,
regions: list[str],
required_only: bool = False,
db: dict | None = None,
) -> set[str]:
"""Destinations an emulator-mode `--region` withdraws.
@@ -1035,6 +1036,11 @@ def emulator_region_drops(
a multi-system core such as O2EM keeps a fallback BIOS for every system
instead of letting one matching system empty another. The emulator pack
and `verify --emulator` both read this, keyed by pack destination.
With `db`, a requested-region file the collection lacks never displaces
a held one, as in platform mode: a held scph5501.bin was withdrawn for a
Japanese image nobody had collected, and the pack shipped no PlayStation
BIOS at all.
"""
import region as region_mod
from packpaths import _resolve_destination
@@ -1042,6 +1048,7 @@ def emulator_region_drops(
region_index = region_mod.build_region_index(dict(selected))
region_groups: dict[str, list[tuple[str, str]]] = {}
held: set[str] | None = set() if db is not None else None
for emu_name, profile in sorted(selected):
# Decided over what the pack keeps, as on the platform side: an
# optional winner removed afterwards left its slot empty.
@@ -1053,7 +1060,11 @@ def emulator_region_drops(
region_groups.setdefault(group_id, []).append(
(dest, fe.get("name", ""))
)
return region_mod.resolve_region_drops(region_groups, region_index, regions)
if held is not None and resolve_local_file(
dict(fe, source_profile=emu_name), db, dest_hint=dest
)[0]:
held.add(dest)
return region_mod.resolve_region_drops(region_groups, region_index, regions, held)
def _emulator_region_group(emu_name: str, profile: dict, file_entry: dict) -> str:
+1 -1
View File
@@ -1519,7 +1519,7 @@ def verify_emulator(
if regions:
from packextras import emulator_region_drops
region_drops = emulator_region_drops(selected, standalone, regions)
region_drops = emulator_region_drops(selected, standalone, regions, db=db)
# The emulator pack walks profiles in name order and keeps the first
# file at a path, folding case: a later profile's different file there
+33
View File
@@ -877,5 +877,38 @@ class FontRomsCarryNoTerritory(unittest.TestCase):
]
self.assertEqual(tagged, [])
class EmulatorModeKeepsAHeldFile(unittest.TestCase):
"""Platform mode never lets a missing file displace a held one; emulator
mode did. A held scph5501.bin (north-america) was withdrawn under
--region jp for a Japanese image the collection lacks, and the pack
shipped no PlayStation BIOS."""
def test_a_missing_match_does_not_withdraw_the_held_file(self):
import hashlib # noqa: PLC0415
import shutil # noqa: PLC0415
import tempfile # noqa: PLC0415
root = Path(tempfile.mkdtemp(dir=Path(__file__).resolve().parents[1] / "tmp"))
self.addCleanup(shutil.rmtree, root, True)
held = root / "scph5501.bin"
held.write_bytes(b"us bios")
sha1 = hashlib.sha1(b"us bios").hexdigest()
db = {"files": {sha1: {"path": str(held), "name": held.name, "sha1": sha1}},
"indexes": {"by_name": {held.name: [sha1]}, "by_md5": {},
"by_crc32": {}, "by_path_suffix": {}}}
profile = {"systems": ["sony-playstation"], "files": [
{"name": "scph5501.bin", "region": ["north-america"]},
{"name": "scph5500.bin", "region": ["japan"]},
]}
selected = [("psx", profile)]
self.assertEqual(
emulator_region_drops(selected, False, ["japan"], db=db), set()
)
# Without the collection to ask, the old reading stands.
self.assertEqual(
emulator_region_drops(selected, False, ["japan"]), {"scph5501.bin"}
)
if __name__ == "__main__":
unittest.main()