mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
fix: read recalbox mandatory per named core
An element lists its cores. Its mandatory flag now follows whether those cores need the file, and stays as written where none of them reads it. cdi/cdibios.zip keeps mandatory=false (same_cdi does not read it), the two amiberry kickstarts keep theirs, saturn_bios.bin becomes optional for the three HLE cores it names.
This commit is contained in:
1 parent
fbf7cb191b
commit
2e29b3be03
6 files changed
+108
-48
No files matched your search
+11
-29
@@ -7,7 +7,7 @@
|
||||
"files": [
|
||||
"es_bios.xml"
|
||||
],
|
||||
"summary": "357 kept, 87 added, 2 hashes corrected, 129 requirements corrected, 528 additions left out, 102 entries found by content not listed",
|
||||
"summary": "357 kept, 87 added, 2 hashes corrected, 127 requirements corrected, 528 additions left out, 102 entries found by content not listed",
|
||||
"counts": {
|
||||
"kept": 357,
|
||||
"added": 87,
|
||||
@@ -15,15 +15,6 @@
|
||||
"not_kept": 0
|
||||
},
|
||||
"changes": [
|
||||
{
|
||||
"kind": "requirement_corrected",
|
||||
"system": "amiga600",
|
||||
"name": "kick33180.A500",
|
||||
"destination": "amiga/bios/kick33180.A500",
|
||||
"field": "required",
|
||||
"old": true,
|
||||
"new": false
|
||||
},
|
||||
{
|
||||
"kind": "requirement_corrected",
|
||||
"system": "amiga600",
|
||||
@@ -318,15 +309,6 @@
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "requirement_corrected",
|
||||
"system": "amiga1200",
|
||||
"name": "kick39106.A1200",
|
||||
"destination": "amiga/bios/kick39106.A1200",
|
||||
"field": "required",
|
||||
"old": true,
|
||||
"new": false
|
||||
},
|
||||
{
|
||||
"kind": "requirement_corrected",
|
||||
"system": "amiga1200",
|
||||
@@ -1923,6 +1905,15 @@
|
||||
"old": true,
|
||||
"new": false
|
||||
},
|
||||
{
|
||||
"kind": "requirement_corrected",
|
||||
"system": "saturn",
|
||||
"name": "saturn_bios.bin",
|
||||
"destination": "saturn/saturn_bios.bin",
|
||||
"field": "required",
|
||||
"old": true,
|
||||
"new": false
|
||||
},
|
||||
{
|
||||
"kind": "requirement_corrected",
|
||||
"system": "saturn",
|
||||
@@ -2205,15 +2196,6 @@
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "requirement_corrected",
|
||||
"system": "cdi",
|
||||
"name": "cdibios.zip",
|
||||
"destination": "cdi/cdibios.zip",
|
||||
"field": "required",
|
||||
"old": false,
|
||||
"new": true
|
||||
},
|
||||
{
|
||||
"kind": "added",
|
||||
"system": "scummvm",
|
||||
@@ -2247,7 +2229,7 @@
|
||||
"sizes_corrected": [],
|
||||
"sizes_removed": [],
|
||||
"hashes_cleared": [],
|
||||
"requirements_corrected": 129,
|
||||
"requirements_corrected": 127,
|
||||
"withheld": [],
|
||||
"found_by_content": 102,
|
||||
"removal_candidates": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<biosList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="es_bios.xsd">
|
||||
<system fullname="Amiga 600 (ECS/OCS)" platform="amiga600">
|
||||
<bios path="amiga/bios/kick33180.A500" md5="85ad74194e87c08904327de1a9443b7a" core="amiberry" mandatory="false" />
|
||||
<bios path="amiga/bios/kick33180.A500" md5="85ad74194e87c08904327de1a9443b7a" core="amiberry" />
|
||||
<bios path="amiga/bios/kick34005.A500" md5="82a21c1890cae844b3df741f2762d48d" core="amiberry,libretro/amiberry,libretro/uae,libretro/uae4arm,libretro/uae4all" />
|
||||
<bios path="amiga/bios/kick37175.A500" md5="dc10d7bdd1b6f450773dfb558477c230" core="amiberry,libretro/uae" mandatory="false" />
|
||||
<bios path="amiga/bios/kick40063.A600" md5="e40a5dfb3d017ba8779faba30cbd1c8e" mandatory="false" core="amiberry,libretro/amiberry,libretro/uae,libretro/uae4arm" />
|
||||
@@ -32,7 +32,7 @@
|
||||
<bios path="uae_data/drive_snatch_LOUD.wav" md5="40cdf89f35b68cfefd4df5fb0256e02f" core="libretro/puae,libretro/puae2021" mandatory="false" />
|
||||
</system>
|
||||
<system fullname="Amiga 1200 (AGA)" platform="amiga1200">
|
||||
<bios path="amiga/bios/kick39106.A1200" md5="b7cc148386aa631136f510cd29e42fc3" core="amiberry" mandatory="false" />
|
||||
<bios path="amiga/bios/kick39106.A1200" md5="b7cc148386aa631136f510cd29e42fc3" core="amiberry" />
|
||||
<bios path="amiga/bios/kick40068.A1200" md5="646773759326fbac3b2311fd8c8793ee" core="amiberry,libretro/amiberry,libretro/uae,libretro/uae4arm" />
|
||||
<bios path="amiga/bios/kick40068.A4000" md5="9bdedde6a4f33555b4a270c8ca53297d" core="amiberry,libretro/amiberry,libretro/uae" note="This bios is required only for A4000 emulation" mandatory="false" />
|
||||
</system>
|
||||
@@ -579,7 +579,7 @@
|
||||
<bios path="scv/upd7801g.s01" md5="635A978FD40DB9A18EE44EFF449FC126" mandatory="true" core="libretro/emuscv" />
|
||||
</system>
|
||||
<system fullname="Sega Saturn" platform="saturn">
|
||||
<bios path="saturn/saturn_bios.bin" md5="af5828fdff51384f99b3c4926be27762" hashMatchMandatory="false" mandatory="true" core="libretro/yabause,libretro/yabasanshiro,libretro/kronos" />
|
||||
<bios path="saturn/saturn_bios.bin" md5="af5828fdff51384f99b3c4926be27762" hashMatchMandatory="false" mandatory="false" core="libretro/yabause,libretro/yabasanshiro,libretro/kronos" />
|
||||
<bios path="saturn/sega_101.bin" md5="85ec9ca47d8f6807718151cbcca8b964" core="libretro/mednafen_saturn" note="Saturn JP BIOS - Required for JP games" />
|
||||
<bios path="saturn/mpr-17933.bin" md5="3240872c70984b6cbfda1586cab68dbe" core="libretro/mednafen_saturn" note="Saturn US/EU BIOS - Required for US/EU games" />
|
||||
<bios path="saturn/mpr-18811-mx.ic1" md5="255113ba943c92a54facd25a10fd780c" core="libretro/mednafen_saturn,libretro/kronos" note="Required for The King of Fighters '95 ROM Cartridge" mandatory="false" />
|
||||
@@ -688,7 +688,7 @@
|
||||
</system>
|
||||
<system fullname="Philips CD-I" platform="cdi">
|
||||
<bios path="cdi/cdimono1.zip" md5="ce590c4787460161359f2b680136cb60,bbe6636ac11d3744f0710e8e820187e7,1a7c3c98c46555ff5fc93ee3feae4b47" core="libretro/cdi2015,libretro/same_cdi" mandatory="true" hashMatchMandatory="false" />
|
||||
<bios path="cdi/cdibios.zip" md5="9fd6b277cd877d51426427a33d1d19bb" core="libretro/same_cdi" hashMatchMandatory="false" />
|
||||
<bios path="cdi/cdibios.zip" md5="9fd6b277cd877d51426427a33d1d19bb" core="libretro/same_cdi" mandatory="false" hashMatchMandatory="false" />
|
||||
<bios path="cdi/cdimono2.zip" md5="2ac8cd5bb23287e022ca17d616949255" core="libretro/same_cdi" mandatory="false" hashMatchMandatory="false" />
|
||||
</system>
|
||||
<system fullname="Sega Naomi 2" platform="naomi2">
|
||||
|
||||
+17
-13
@@ -509,7 +509,7 @@ def _added_fields(exporter: object, entry: object) -> dict:
|
||||
if "size" in carried and entry.size() is not None:
|
||||
written["size"] = entry.size()
|
||||
if "required" in carried:
|
||||
written["required"] = entry.required
|
||||
written["required"] = exporter.required_value(entry)
|
||||
return written
|
||||
|
||||
|
||||
@@ -535,20 +535,24 @@ def landed_changes(exporter: object, systems: dict) -> LandedChanges:
|
||||
"added", entry, None, None, _added_fields(exporter, entry)
|
||||
))
|
||||
continue
|
||||
if (
|
||||
(entry.truth or {}).get("required") is not None
|
||||
and entry.platform.get("required") is not None
|
||||
and exporter.states(entry, "required")
|
||||
and exporter.required_value(entry) != bool(entry.platform["required"])
|
||||
):
|
||||
records.append(_change(
|
||||
"requirement_corrected", entry, "required",
|
||||
bool(entry.platform["required"]), exporter.required_value(entry),
|
||||
))
|
||||
for field_name in entry.corrections:
|
||||
if not exporter.states(entry, field_name):
|
||||
if field_name == "required" or not exporter.states(entry, field_name):
|
||||
continue
|
||||
if field_name == "required":
|
||||
records.append(_change(
|
||||
"requirement_corrected", entry, "required",
|
||||
bool(entry.platform.get("required")), entry.required,
|
||||
))
|
||||
else:
|
||||
records.append(_change(
|
||||
"hash_corrected", entry, field_name,
|
||||
_platform_value(entry, field_name),
|
||||
exporter.written(entry, field_name),
|
||||
))
|
||||
records.append(_change(
|
||||
"hash_corrected", entry, field_name,
|
||||
_platform_value(entry, field_name),
|
||||
exporter.written(entry, field_name),
|
||||
))
|
||||
records.extend(
|
||||
_change("hash_filled", entry, field_name, None,
|
||||
exporter.written(entry, field_name))
|
||||
|
||||
@@ -200,6 +200,14 @@ class BaseExporter(ABC):
|
||||
return self.single_value(fe, field_name)
|
||||
return ",".join(fe.hashes(field_name))
|
||||
|
||||
def required_value(self, fe: NativeFile) -> bool:
|
||||
"""The requirement the render writes for an entry.
|
||||
|
||||
The model's flag is true when any core needs the file. A format
|
||||
that names the cores of each entry narrows it to those cores.
|
||||
"""
|
||||
return fe.required
|
||||
|
||||
def states(self, fe: NativeFile, field_name: str) -> bool:
|
||||
"""Whether the written file carries this entry's corrected field.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ from xml.sax.saxutils import quoteattr
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
from common import parse_untrusted_xml
|
||||
from common import load_emulator_profiles, parse_untrusted_xml
|
||||
|
||||
from .base_exporter import BaseExporter
|
||||
from .baseline import NativeFile, NativeSystem, Report
|
||||
@@ -29,6 +29,8 @@ SOURCE_URL = (
|
||||
"https://gitlab.com/recalbox/recalbox/-/raw/master/board/recalbox/fsoverlay"
|
||||
"/recalbox/share_init/system/.emulationstation/es_bios.xml"
|
||||
)
|
||||
# Resolved from the file: the profiles say which names each core answers to.
|
||||
EMULATORS_DIR = Path(__file__).resolve().parents[2] / "emulators"
|
||||
SCHEMA_URL = (
|
||||
"https://gitlab.com/recalbox/recalbox/-/raw/master/board/recalbox/fsoverlay"
|
||||
"/recalbox/share_init/system/.emulationstation/es_bios.xsd"
|
||||
@@ -149,12 +151,48 @@ class Exporter(BaseExporter):
|
||||
return path
|
||||
return fe.destination or fe.name
|
||||
|
||||
def _profile_keys(self) -> dict[str, str]:
|
||||
"""Each name a core answers to, as Recalbox writes it, to its profile."""
|
||||
index = getattr(self, "_keys", None)
|
||||
if index is None:
|
||||
index = {}
|
||||
for key, profile in load_emulator_profiles(str(EMULATORS_DIR)).items():
|
||||
for name in (key, *(str(c) for c in profile.get("cores") or [])):
|
||||
index.setdefault(name.replace("-", "_").lower(), key)
|
||||
self._keys = index
|
||||
return index
|
||||
|
||||
def required_value(self, fe: NativeFile) -> bool:
|
||||
"""Whether the cores the element names need the file.
|
||||
|
||||
An element lists its cores, and the merged flag is true when any
|
||||
core needs the file: cdi/cdibios.zip names libretro/same_cdi, whose
|
||||
driver declares no such set, and became mandatory because MAME
|
||||
requires it. Where none of the element's cores reads the file, the
|
||||
truth says nothing about it and the platform's value stands.
|
||||
"""
|
||||
truth = fe.truth or {}
|
||||
required_by = truth.get("_required_by")
|
||||
readers = truth.get("_cores")
|
||||
if required_by is None or not readers:
|
||||
return fe.required
|
||||
index = self._profile_keys()
|
||||
named = {
|
||||
index.get(core.rsplit("/", 1)[-1].replace("-", "_").lower(), "")
|
||||
for core in fe.cores()
|
||||
} & set(readers)
|
||||
if not named:
|
||||
if fe.platform is not None and fe.platform.get("required") is not None:
|
||||
return bool(fe.platform["required"])
|
||||
return fe.required
|
||||
return bool(named & set(required_by))
|
||||
|
||||
def _bios_element(self, fe: NativeFile, native_id: str) -> str:
|
||||
attrs = [f"path={quoteattr(self._path(fe))}"]
|
||||
attrs.append(f'md5={quoteattr(",".join(fe.hashes("md5")))}')
|
||||
attrs.append(f'core={quoteattr(",".join(fe.cores()))}')
|
||||
|
||||
if not fe.required:
|
||||
if not self.required_value(fe):
|
||||
attrs.append('mandatory="false"')
|
||||
elif fe.native("mandatory_declared", None) is True:
|
||||
attrs.append('mandatory="true"')
|
||||
|
||||
@@ -1141,6 +1141,34 @@ class RecalboxExport(unittest.TestCase):
|
||||
self.assertEqual({k: v for k, v in after.items() if k in before}, before)
|
||||
self.assertEqual(set(after) - set(before), set())
|
||||
|
||||
def test_mandatory_follows_the_cores_the_element_names(self):
|
||||
"""cdi/cdibios.zip names libretro/same_cdi, which does not read the
|
||||
set: MAME requiring it says nothing about that element."""
|
||||
scraped = {"systems": {"philips-cdi": {"native_id": "cdi", "files": [
|
||||
{"name": "cdibios.zip", "destination": "cdi/cdibios.zip", "md5": "a" * 32,
|
||||
"native_system": "cdi", "core": "libretro/same_cdi", "required": False},
|
||||
{"name": "cdimono1.zip", "destination": "cdi/cdimono1.zip", "md5": "b" * 32,
|
||||
"native_system": "cdi", "core": "libretro/same_cdi", "required": False},
|
||||
]}}}
|
||||
truth = {"systems": {"philips-cdi": {"files": [
|
||||
{"name": "cdibios.zip", "required": True, "_cores": ["mame0278"],
|
||||
"_required_by": ["mame0278"]},
|
||||
{"name": "cdimono1.zip", "required": True, "_cores": ["same_cdi", "mame0278"],
|
||||
"_required_by": ["same_cdi"]},
|
||||
]}}}
|
||||
systems, report = build_native_model(truth, scraped)
|
||||
exporter = discover_exporters()["recalbox"]()
|
||||
produced = exporter.render(systems, report, {}, None)["es_bios.xml"]
|
||||
mandatory = {
|
||||
b.get("path"): b.get("mandatory") for b in ET.fromstring(produced).iter("bios")
|
||||
}
|
||||
self.assertEqual(mandatory, {"cdi/cdibios.zip": "false", "cdi/cdimono1.zip": None})
|
||||
changes = landed_changes(exporter, systems).records
|
||||
self.assertEqual(
|
||||
[(c["name"], c["old"], c["new"]) for c in changes],
|
||||
[("cdimono1.zip", False, True)],
|
||||
)
|
||||
|
||||
def test_a_truncated_export_is_reported(self):
|
||||
exporter, systems, _ = self._render()
|
||||
empty = {
|
||||
|
||||
Reference in new issue
Block a user