mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-13 13:33:52 -06:00
fix: read xroar coco3 ROMs from RetroBat coco
RetroBat passes XRoar -rompath bios/coco for the coco system, and its es_features offers the CoCo 3 machines there. The per-system record now carries those machines (machines:), and an entry whose name the platform list does not declare is launched for the system offering its own profile system as a machine, by _norm_system_id. coco3.rom and coco3p.rom move from bios/dragon to bios/coco. RetroBat offers no MC-10 machine, so the mc10 ROMs keep the default bios/dragon.
This commit is contained in:
1 parent
339297c75c
commit
4b17bf0460
8 files changed
+138
-8
No files matched your search
+10
-1
@@ -5402,7 +5402,16 @@ launchers:
|
||||
fails_when_missing: false
|
||||
systems:
|
||||
- coco
|
||||
source_ref: "emulatorLauncher/Generators/Xroar.Generator.cs:76-80"
|
||||
machines:
|
||||
- coco
|
||||
- cocous
|
||||
- coco2b
|
||||
- coco2bus
|
||||
- coco3
|
||||
- coco3h
|
||||
- coco3p
|
||||
- coco3ph
|
||||
source_ref: "emulatorLauncher/Generators/Xroar.Generator.cs:76-80, .emulationstation/es_features.cfg:22650-22659"
|
||||
- emulator: xroar
|
||||
build: standalone
|
||||
kind: passes_path
|
||||
|
||||
@@ -243,6 +243,13 @@
|
||||
},
|
||||
"description": "Systems the package registers, under the platform's own names, in the order the script adds them. On a record handing a directory, the systems it is written for: the record applies to an emulator launched for one of them, and replaces there what the records naming no system hand"
|
||||
},
|
||||
"machines": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "On a record naming systems, the machines the platform offers the emulator under them, as the emulator names them: an entry of a profile system spelled like one of them is launched for those systems"
|
||||
},
|
||||
"slot": {
|
||||
"type": "string",
|
||||
"description": "The key the launcher files this list under, such as a region or a machine"
|
||||
|
||||
+24
-2
@@ -2697,6 +2697,8 @@ EXECUTED_PREFIX = "exec:"
|
||||
# systems a launcher record is written for, as JSON [system, name]: it says
|
||||
# which launch reads a profile entry of that name.
|
||||
SYSTEM_FILE_PREFIX = "sysfile:"
|
||||
# The key, in that index, of a machine a launcher record offers.
|
||||
MACHINE_KEY = "machine:"
|
||||
|
||||
|
||||
def core_system_dirs(
|
||||
@@ -2781,6 +2783,18 @@ def standalone_set(config: dict) -> set[str]:
|
||||
for f in system.get("files") or []
|
||||
if f.get("name")
|
||||
}
|
||||
# The machines a record offers under its systems, by normalized id.
|
||||
from launchers import native_systems # noqa: PLC0415
|
||||
|
||||
natives = native_systems(config)
|
||||
names |= {
|
||||
SYSTEM_FILE_PREFIX + json.dumps(
|
||||
[natives.get(str(native), str(native)), MACHINE_KEY + _norm_system_id(str(m))]
|
||||
)
|
||||
for record in config.get("launchers") or []
|
||||
for native in record.get("systems") or []
|
||||
for m in record.get("machines") or []
|
||||
}
|
||||
names |= {
|
||||
EXECUTED_PREFIX + json.dumps([run.emulator, run.name, run.place, run.source_ref])
|
||||
for run in executed_files(config)
|
||||
@@ -3000,9 +3014,17 @@ def platform_layouts(
|
||||
def bindings_of(entry: dict) -> dict[str, tuple[str, str]]:
|
||||
systems = frozenset()
|
||||
if per_system:
|
||||
own = entry_launch_systems(entry, {})
|
||||
systems = entry_launch_systems(entry, index)
|
||||
if systems == entry_launch_systems(entry, {}):
|
||||
systems = systems.union(*(family.get(s, set()) for s in systems))
|
||||
if systems == own:
|
||||
systems = systems.union(*(family.get(s, set()) for s in own))
|
||||
if systems == own:
|
||||
# The platform's list names none of the entry's names: its
|
||||
# own system selects the launch that offers it as a machine
|
||||
# (RetroBat runs XRoar's coco3 under coco).
|
||||
systems = systems.union(*(
|
||||
index.get(MACHINE_KEY + _norm_system_id(s), set()) for s in own
|
||||
))
|
||||
if systems not in by_systems:
|
||||
by_systems[systems] = standalone_bindings_for(
|
||||
emu_name, profile, standalone_cores, systems
|
||||
|
||||
@@ -35,6 +35,8 @@ class Launcher:
|
||||
fails_scope: str | None = None
|
||||
depends_on_option: str | None = None
|
||||
device: str | None = None
|
||||
# The machines the platform offers under the record's systems.
|
||||
machines: list[str] | None = None
|
||||
|
||||
def entry(self) -> dict[str, Any]:
|
||||
"""The platform YAML form, in a fixed key order, unset keys left out."""
|
||||
@@ -42,7 +44,7 @@ class Launcher:
|
||||
"emulator", "build", "kind", "slot", "names", "expands",
|
||||
"case_insensitive", "search_dir", "passes_to",
|
||||
"fails_when_missing", "fails_scope", "depends_on_option",
|
||||
"device", "source_ref",
|
||||
"device", "machines", "source_ref",
|
||||
)
|
||||
return {key: getattr(self, key) for key in order if getattr(self, key) is not None}
|
||||
|
||||
|
||||
@@ -292,6 +292,33 @@ def _throw_message(src: Source, start: int, end: int) -> tuple[str, int]:
|
||||
return f"ApplicationException '{message}'", src.line(found.start())
|
||||
|
||||
|
||||
def system_feature_choices(
|
||||
src: Source, emulator: str, option: str, system: str
|
||||
) -> tuple[list[str], tuple[int, int]]:
|
||||
"""Values es_features.cfg offers for an option of an emulator under one system."""
|
||||
text = src.text
|
||||
for found in re.finditer(r'<emulator name="([^"]*)"', text):
|
||||
if emulator in [name.strip() for name in found.group(1).split(",")]:
|
||||
start, end = found.start(), text.find("</emulator>", found.start())
|
||||
break
|
||||
else:
|
||||
raise LauncherPatternMissing(src.path, f"emulator {emulator}")
|
||||
for block in re.finditer(r'<system name="([^"]*)">', text[start:end]):
|
||||
if system not in [name.strip() for name in block.group(1).split(",")]:
|
||||
continue
|
||||
scope = start + block.start()
|
||||
close = text.find("</system>", scope)
|
||||
feature = src.find(
|
||||
rf'<feature [^>]*value="{re.escape(option)}"', f"{option} of {system}", scope, close
|
||||
)
|
||||
stop = text.find("</feature>", feature.end())
|
||||
values = re.findall(r'<choice [^>]*value="([^"]*)"', text[feature.end():stop])
|
||||
if not values:
|
||||
raise LauncherPatternMissing(src.path, f"choices of {option} for {system}")
|
||||
return values, src.lines(feature.start(), stop + len("</feature>"))
|
||||
raise LauncherPatternMissing(src.path, f"system {system} of {emulator}")
|
||||
|
||||
|
||||
def feature_choices(
|
||||
src: Source, emulator: str, option: str, core: str | None = None
|
||||
) -> tuple[list[str], tuple[int, int]]:
|
||||
@@ -2983,6 +3010,21 @@ def xroar(sources: dict[str, Source]) -> list[Record]:
|
||||
for record, conditions in found
|
||||
for split in _per_system(src, _with_conditions(record, conditions))
|
||||
]
|
||||
# The machines ES offers under a system the folder is chosen for: XRoar
|
||||
# runs a CoCo 3 for coco, so its ROMs are read from that system's folder.
|
||||
features = sources[FEATURES]
|
||||
for record in records:
|
||||
if not record.get("systems"):
|
||||
continue
|
||||
machines: list[str] = []
|
||||
lines = []
|
||||
for system in record["systems"]:
|
||||
choices, span = system_feature_choices(features, "xroar", "xroar_machine", system)
|
||||
machines += [m for m in choices if m not in machines]
|
||||
lines.append(span)
|
||||
record["machines"] = machines
|
||||
ref = record.pop("source_ref")
|
||||
record["source_ref"] = f"{ref}, {source_ref((features.path, lines))}"
|
||||
line = src.find(r'string (\w+) = ("rompath (?:[^"\\\n]|\\.)*");', "config rompath line")
|
||||
written = _unescape(line.group(2)[1:-1])
|
||||
relative = re.fullmatch(r'rompath "(.*)"', written)
|
||||
|
||||
@@ -1150,7 +1150,9 @@ class FolderArguments(unittest.TestCase):
|
||||
|
||||
def test_xroar_reassigned_folder_and_config_line(self):
|
||||
# romPath is bios/dragon, rewritten to bios/coco for the coco system.
|
||||
default, coco, config = rl.xroar(_sources(**{f"{G}/Xroar.Generator.cs": XROAR}))
|
||||
default, coco, config = rl.xroar(_sources(**{
|
||||
f"{G}/Xroar.Generator.cs": XROAR, rl.FEATURES: XROAR_FEATURES,
|
||||
}))
|
||||
self.assertEqual(
|
||||
(default["search_dir"], default["passes_to"], default.get("systems")),
|
||||
("bios/dragon", "command line -rompath bios/dragon", None),
|
||||
@@ -1159,13 +1161,34 @@ class FolderArguments(unittest.TestCase):
|
||||
(coco["search_dir"], coco["passes_to"], coco["systems"]),
|
||||
("bios/coco", "command line -rompath bios/coco", ["coco"]),
|
||||
)
|
||||
self.assertEqual(coco["source_ref"], default["source_ref"])
|
||||
self.assertEqual(coco["machines"], ["coco", "coco3"])
|
||||
self.assertNotIn("machines", default)
|
||||
self.assertEqual(
|
||||
coco["source_ref"], f"{default['source_ref']}, {rl.FEATURES}:3-6"
|
||||
)
|
||||
self.assertEqual(config["search_dir"], "bios/dragon")
|
||||
self.assertEqual(
|
||||
config["passes_to"], 'xroar.conf rompath ".\\\\..\\\\..\\\\bios\\\\dragon"'
|
||||
)
|
||||
|
||||
|
||||
XROAR_FEATURES = """
|
||||
<emulator name="xroar">
|
||||
<system name="coco">
|
||||
<feature submenu="EMULATION" name="MACHINE" value="xroar_machine" order="100">
|
||||
<choice name="TANDY COCO(PAL)" value="coco"/>
|
||||
<choice name="TANDY COCO 3(NTSC)" value="coco3"/>
|
||||
</feature>
|
||||
</system>
|
||||
<system name="dragon32,dragon64,dragon">
|
||||
<feature submenu="EMULATION" name="MACHINE" value="xroar_machine" order="100">
|
||||
<choice name="DRAGON64" value="dragon64"/>
|
||||
</feature>
|
||||
</system>
|
||||
</emulator>
|
||||
"""
|
||||
|
||||
|
||||
PICO8 = """
|
||||
public override System.Diagnostics.ProcessStartInfo Generate(string system, string emulator, string core, string rom, string playersControllers, ScreenResolution resolution)
|
||||
{
|
||||
|
||||
@@ -308,6 +308,29 @@ class SystemFamily(unittest.TestCase):
|
||||
)
|
||||
|
||||
|
||||
class OfferedMachine(unittest.TestCase):
|
||||
def test_an_entry_system_offered_as_a_machine_selects_that_launch(self) -> None:
|
||||
profile = {
|
||||
"emulator": "Emu", "type": "standalone", "standalone_pools": {"-rompath": ""},
|
||||
"files": [
|
||||
{"name": "coco3.rom", "path": "coco3.rom", "system": "coco3"},
|
||||
{"name": "mc10.rom", "path": "mc10.rom", "system": "mc10"},
|
||||
],
|
||||
}
|
||||
cfg = {
|
||||
**config(
|
||||
passes("emu", "bios/dragon", "-rompath"),
|
||||
{**passes("emu", "bios/coco", "-rompath"), "systems": ["coco"],
|
||||
"machines": ["coco", "coco3"]},
|
||||
),
|
||||
"systems": {"coco": {"files": [{"name": "x.zip", "native_system": "coco"}]}},
|
||||
}
|
||||
((view, _standalone),) = platform_layouts("emu", profile, standalone_set(cfg))
|
||||
self.assertEqual(
|
||||
[f.get("standalone_path") for f in view["files"]], ["coco/coco3.rom", "dragon/mc10.rom"]
|
||||
)
|
||||
|
||||
|
||||
class Layout(unittest.TestCase):
|
||||
LINKED = link("emu", "$biosdir/dc", "$home/.local/share/emu is a symlink to it")
|
||||
|
||||
@@ -574,8 +597,9 @@ class XroarOnEachPlatform(unittest.TestCase):
|
||||
"batocera": dict.fromkeys(("dragon32", "dragon64", "coco", "coco3", "mc10"), "xroar"),
|
||||
"retrodeck": dict.fromkeys(("dragon32", "dragon64", "coco", "coco3", "mc10"), ""),
|
||||
"retropie": dict.fromkeys(("dragon32", "dragon64", "coco", "coco3", "mc10"), ""),
|
||||
"retrobat": {**dict.fromkeys(("dragon32", "dragon64", "coco3", "mc10"), "dragon"),
|
||||
"coco": "coco"},
|
||||
# RetroBat offers XRoar's CoCo 3 machines under coco and no MC-10.
|
||||
"retrobat": {**dict.fromkeys(("dragon32", "dragon64", "mc10"), "dragon"),
|
||||
**dict.fromkeys(("coco", "coco3"), "coco")},
|
||||
"recalbox": {**dict.fromkeys(("dragon32", "dragon64"), "dragon"),
|
||||
**dict.fromkeys(("coco", "coco3", "mc10"), "trs80coco")},
|
||||
}
|
||||
|
||||
@@ -429,6 +429,7 @@ launchers:
|
||||
| `repo` | What the package fetches and builds, as the script writes it (`rp_module_repo`: method, URL, branch or commit) |
|
||||
| `systems` | Systems the package registers, under the platform's names (`addSystem`, `addPort` for ports) |
|
||||
| `slot` | The key the code files the list under: a region, a machine |
|
||||
| `machines` | On a record naming systems, the machines the platform offers the emulator under them (RetroBat's `xroar_machine` choices for coco) |
|
||||
| `names` | In the order the code tries or writes them, relative to `search_dir` |
|
||||
| `expands` | Values a `{X}` placeholder in `names` takes, in the order tried (Hatari tries each TOS in ten languages) |
|
||||
| `case_insensitive` | Whether the launcher matches names regardless of case |
|
||||
|
||||
Reference in new issue
Block a user