mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-14 05:53:47 -06:00
chore: merge issue 87 and platform refresh
This commit is contained in:
commit
19264db538
42 files changed
+3123
-376
No files matched your search
@@ -37,7 +37,7 @@ KEY_TYPES: dict[str, dict] = {
|
||||
**dict.fromkeys((
|
||||
"installer", "os", "os_name", "stage", "reason", "platform", "message",
|
||||
"folder", "dest", "system", "name", "bios_dir", "path", "member",
|
||||
"list_version", "installed_version", "board",
|
||||
"list_version", "installed_version", "board", "core",
|
||||
), _TEXT),
|
||||
"mode": {"enum": ["install", "check", "dry-run", "list"]},
|
||||
"state": {"enum": ["present", "wrong_hash", "missing"]},
|
||||
@@ -47,7 +47,7 @@ KEY_TYPES: dict[str, dict] = {
|
||||
"bytes_needed", "data_missing", "not_installable", "installed", "up_to_date",
|
||||
"pending", "code", "games", "recognised", "not_games",
|
||||
), _COUNT),
|
||||
**dict.fromkeys(("truncated", "ok", "interrupted", "required_only", "applied"), _FLAG),
|
||||
**dict.fromkeys(("truncated", "ok", "interrupted", "required_only", "applied", "info"), _FLAG),
|
||||
**dict.fromkeys(("systems", "other_drives", "dests", "written"), _NAMES),
|
||||
**dict.fromkeys(("platforms", "failed", "skipped", "left_out", "kept", "found",
|
||||
"fallback"), _RECORDS),
|
||||
|
||||
@@ -5299,14 +5299,15 @@ def _manifest_core_index(
|
||||
|
||||
A target list, or the cores found installed, names cores the way the
|
||||
buildbot does, and a file names the profile that reads it: `core_names`
|
||||
gives each profile the other names it goes by. `system_cores` gives each
|
||||
platform system the cores whose presence keeps it, as
|
||||
gives each profile the other names it goes by, and names every core the
|
||||
platform runs, one that reads no file included: a core found installed
|
||||
that the list does not name is one it has no profile for. `system_cores`
|
||||
gives each platform system the cores whose presence keeps it, as
|
||||
`filter_systems_by_target` decides. A system absent from it is kept
|
||||
whatever is available.
|
||||
"""
|
||||
reach = system_core_reach(
|
||||
config.get("systems", {}), profiles, _platform_cores(config, profiles)
|
||||
)
|
||||
runs = _platform_cores(config, profiles)
|
||||
reach = system_core_reach(config.get("systems", {}), profiles, runs)
|
||||
system_cores = {
|
||||
sys_id: sorted(cores) for sys_id, cores in sorted(reach.items())
|
||||
if cores is not None
|
||||
@@ -5317,7 +5318,8 @@ def _manifest_core_index(
|
||||
for c in copy.get("cores") or []
|
||||
}
|
||||
named |= {c for cores in system_cores.values() for c in cores}
|
||||
aliases: dict[str, set[str]] = {}
|
||||
named |= set(runs)
|
||||
aliases: dict[str, set[str]] = {profile: set() for profile in named & set(runs)}
|
||||
for name, claimants in upstream_profile_index(profiles, include_aliases=True).items():
|
||||
for profile in claimants & named:
|
||||
if name != profile:
|
||||
|
||||
@@ -782,6 +782,14 @@ def verify_pack_against_platform(
|
||||
baseline_groups.setdefault(expected, []).append(fe)
|
||||
|
||||
baseline_checked = len(baseline_groups)
|
||||
# RetroBat's group: one packed file of it is enough, as verify counts it.
|
||||
packed_groups = {
|
||||
(system_of[id(fe)], fe["group"])
|
||||
for expected, declarations in baseline_groups.items()
|
||||
if expected in zip_set or expected.lower() in zip_lower
|
||||
for fe in declarations
|
||||
if fe.get("group")
|
||||
}
|
||||
exclusion_index = build_zip_contents_index(db) if db is not None else {}
|
||||
categories = EntryCategories(config, emu_profiles, data_registry)
|
||||
for expected, declarations in baseline_groups.items():
|
||||
@@ -803,6 +811,12 @@ def verify_pack_against_platform(
|
||||
):
|
||||
baseline_excluded += 1
|
||||
continue
|
||||
elif all(
|
||||
fe.get("group") and (system_of[id(fe)], fe["group"]) in packed_groups
|
||||
for fe in declarations
|
||||
):
|
||||
baseline_absent += 1
|
||||
continue
|
||||
elif db is not None and all(
|
||||
categories.category(fe, fe.get("destination", fe.get("name", "")),
|
||||
system_of[id(fe)]) != BIOS
|
||||
|
||||
@@ -147,12 +147,14 @@ class Source:
|
||||
return max(holding)
|
||||
|
||||
def header(self, block: tuple[int, int]) -> str:
|
||||
"""The statement that owns a block's opening brace, comments removed."""
|
||||
"""The statement that owns a block's opening brace, comments and
|
||||
preprocessor lines (#region, #if) removed."""
|
||||
if self._ends is None:
|
||||
self._ends = [o for o, c in _code_chars(self.text) if c in ";{}"]
|
||||
previous = bisect.bisect_left(self._ends, block[0]) - 1
|
||||
start = self._ends[previous] + 1 if previous >= 0 else 0
|
||||
text = re.sub(r"//[^\n]*|/\*.*?\*/", "", self.text[start : block[0]], flags=re.S)
|
||||
text = re.sub(r"//[^\n]*|/\*.*?\*/|^[ \t]*#[^\n]*", "", self.text[start : block[0]],
|
||||
flags=re.S | re.M)
|
||||
return " ".join(text.split())
|
||||
|
||||
def statement_span(self, block: tuple[int, int]) -> tuple[int, int]:
|
||||
@@ -381,34 +383,65 @@ def ares(sources: dict[str, Source]) -> list[Record]:
|
||||
|
||||
|
||||
def hatari(sources: dict[str, Source]) -> list[Record]:
|
||||
"""tos.img in bios, a TOS chosen in bios/hatari/tos, and EmuTOS from there
|
||||
for a hard disk image, for a missing tos.img, or after a TOS too old for
|
||||
autostart or GEMDOS."""
|
||||
src = sources[f"{GENERATORS}/Hatari.Generator.cs"]
|
||||
features = sources[FEATURES]
|
||||
default = src.find(rf'string (\w+) = Path\.Combine\({BIOS}, "([^"]+)"\);', "default TOS path")
|
||||
folder = src.find(
|
||||
rf'string (\w+) = Path\.Combine\({BIOS}, ((?:"[^"]+"(?:, )?)+)\);', "TOS folder"
|
||||
)
|
||||
tos_dir, folders = folder.group(1), _strings(folder.group(2))
|
||||
default = src.find(
|
||||
rf'string (\w+) = Path\.Combine\({BIOS}, "([^"]+)"\);', "default TOS path", folder.end()
|
||||
)
|
||||
var, name = default.group(1), default.group(2)
|
||||
emutos = src.find(
|
||||
rf'string (\w+) = Path\.Combine\({tos_dir}, "([^"]+)"\);', "EmuTOS path", default.end()
|
||||
)
|
||||
override = src.find(
|
||||
rf'isOptSet\("(\w+)"\)[^\n]*\n\s*{var} = Path\.Combine\({BIOS}, ((?:"[^"]+", )+)SystemConfig\["\1"\]\);',
|
||||
rf'isOptSet\("(\w+)"\)[^\n]*\n\s*{var} = Path\.Combine\({tos_dir}, SystemConfig\["\1"\]\);',
|
||||
"TOS option override",
|
||||
default.end(),
|
||||
emutos.end(),
|
||||
)
|
||||
option = override.group(1)
|
||||
disk = src.find(
|
||||
rf"else if \(media\.HasHardDiskImage && File\.Exists\({emutos.group(1)}\)\)",
|
||||
"EmuTOS for a hard disk image",
|
||||
override.end(),
|
||||
)
|
||||
absent = src.find(
|
||||
rf"if \(!File\.Exists\({var}\) && File\.Exists\({emutos.group(1)}\)\)\s*{var} = {emutos.group(1)};",
|
||||
"EmuTOS without tos.img",
|
||||
disk.end(),
|
||||
)
|
||||
newer = src.find(
|
||||
r"new string\[\] \{ ((?:\"[^\"]+\"(?:, )?)+) \}\s*"
|
||||
rf"\.Select\(t => Path\.Combine\({tos_dir}, t\)\)\s*\.FirstOrDefault\(t => File\.Exists\(t\)\);",
|
||||
"TOS for autostart and GEMDOS",
|
||||
absent.end(),
|
||||
)
|
||||
option, folders = override.group(1), _strings(override.group(2))
|
||||
write = src.find(
|
||||
rf'ini\.WriteValue\("(\w+)", "(\w+)", {var}\);', "TOS ini write", override.end()
|
||||
rf'ini\.WriteValue\("(\w+)", "(\w+)", {var}\);', "TOS ini write", newer.end()
|
||||
)
|
||||
message, _ = _throw_message(src, override.end(), write.start())
|
||||
message, _ = _throw_message(src, newer.end(), write.start())
|
||||
passes = f"hatari.cfg [{write.group(1)}] {write.group(2)}"
|
||||
tos_folder = "/".join(["bios", *folders])
|
||||
choices, choice_lines = feature_choices(features, "hatari", option)
|
||||
head = src.lines(folder.start(), emutos.end())
|
||||
tail = src.lines(write.start(), write.end())
|
||||
return [
|
||||
_record(
|
||||
"hatari",
|
||||
"standalone",
|
||||
"fixed_name",
|
||||
[name],
|
||||
source_ref((src.path, [src.lines(default.start(), write.end())])),
|
||||
source_ref((src.path, [head, src.lines(absent.start(), absent.end()), tail])),
|
||||
case_insensitive=True,
|
||||
search_dir="bios",
|
||||
passes_to=f"{passes}=<bios>/{name}",
|
||||
fails_when_missing=message,
|
||||
depends_on_option=f"{option} unset",
|
||||
fails_when_missing=f"{tos_folder}/{emutos.group(2)} instead, else {message}",
|
||||
depends_on_option=f"{option} unset, no hard disk image",
|
||||
),
|
||||
_record(
|
||||
"hatari",
|
||||
@@ -416,15 +449,39 @@ def hatari(sources: dict[str, Source]) -> list[Record]:
|
||||
"core_option",
|
||||
choices,
|
||||
source_ref(
|
||||
(src.path, [src.lines(override.start(), write.end())]),
|
||||
(src.path, [head, src.lines(override.start(), override.end()), tail]),
|
||||
(features.path, [choice_lines]),
|
||||
),
|
||||
case_insensitive=True,
|
||||
search_dir="/".join(["bios", *folders]),
|
||||
search_dir=tos_folder,
|
||||
passes_to=f"{passes}=<bios>/{'/'.join(folders)}/<value>",
|
||||
fails_when_missing=message,
|
||||
depends_on_option=option,
|
||||
),
|
||||
_record(
|
||||
"hatari",
|
||||
"standalone",
|
||||
"fixed_name",
|
||||
[emutos.group(2)],
|
||||
source_ref((src.path, [head, src.lines(disk.start(), absent.end()), tail])),
|
||||
case_insensitive=True,
|
||||
search_dir=tos_folder,
|
||||
passes_to=f"{passes}=<bios>/{'/'.join(folders)}/{emutos.group(2)}",
|
||||
fails_when_missing=f"{name} is used, as without a hard disk image",
|
||||
depends_on_option=f"{option} unset, a hard disk image mounted or no {name}",
|
||||
),
|
||||
_record(
|
||||
"hatari",
|
||||
"standalone",
|
||||
"names_searched",
|
||||
_strings(newer.group(1)),
|
||||
source_ref((src.path, [head, src.lines(newer.start(), newer.end()), tail])),
|
||||
case_insensitive=True,
|
||||
search_dir=tos_folder,
|
||||
passes_to=f"{passes}=<first found>",
|
||||
fails_when_missing="the TOS older than 1.04 is kept",
|
||||
depends_on_option=f"{option} unset, autostart or GEMDOS folder, TOS older than 1.04",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -434,70 +491,100 @@ def hatari_libretro(sources: dict[str, Source]) -> list[Record]:
|
||||
records = []
|
||||
|
||||
tosimage = src.find(
|
||||
r'if \(SystemConfig\.isOptSet\("(\w+)"\)[^\n]*\n\s*coreSettings\["(hatari_tosimage)"\] = SystemConfig\["\1"\];'
|
||||
r'\s*else\s*coreSettings\["\2"\] = "(\w+)";',
|
||||
r'string (\w+) = SystemConfig\["(\w+)"\];\s*'
|
||||
rf'if \(!string\.IsNullOrEmpty\(\1\) && \1 != "(\w+)" && File\.Exists\(Path\.Combine\({BIOS}, '
|
||||
r'((?:"[^"]+", )+)\1\)\)\)\s*coreSettings\["(hatari_tosimage)"\] = \1;'
|
||||
r'\s*else\s*coreSettings\["\5"\] = "\3";',
|
||||
"hatari_tosimage",
|
||||
)
|
||||
choices, choice_lines = feature_choices(features, "libretro", tosimage.group(1), core="hatari")
|
||||
guard = src.find(r'if \(core != "(hatari2014)"\)', "hatari2014 guard")
|
||||
folders = _strings(tosimage.group(4).rstrip(", "))
|
||||
choices, choice_lines = feature_choices(
|
||||
features, "libretro", tosimage.group(2), core=guard.group(1)
|
||||
)
|
||||
records.append(
|
||||
_record(
|
||||
"hatari",
|
||||
guard.group(1),
|
||||
"libretro",
|
||||
"core_option",
|
||||
choices,
|
||||
source_ref(
|
||||
(src.path, [src.lines(tosimage.start(), tosimage.end())]),
|
||||
(src.path, [src.lines(guard.start(), tosimage.end())]),
|
||||
(features.path, [choice_lines]),
|
||||
),
|
||||
search_dir="bios",
|
||||
passes_to=f"{tosimage.group(2)} = <value> | {tosimage.group(3)}",
|
||||
fails_when_missing="not checked by the launcher",
|
||||
depends_on_option=tosimage.group(1),
|
||||
search_dir="/".join(["bios", *folders]),
|
||||
passes_to=f"{tosimage.group(5)} = <value>, if the file is there | {tosimage.group(3)}",
|
||||
fails_when_missing=f"{tosimage.group(5)} = {tosimage.group(3)}",
|
||||
depends_on_option=tosimage.group(2),
|
||||
)
|
||||
)
|
||||
|
||||
guard = src.find(r'if \(core != "hatarib"\)', "hatarib guard")
|
||||
method = src.enclosing(guard.start())
|
||||
found = src.find(
|
||||
rf'else if \(File\.Exists\(Path\.Combine\({BIOS}, "([^"]+)"\)\)\)\s*'
|
||||
r'coreSettings\["(hatarib_tos)"\] = "([^"]+)";\s*else\s*coreSettings\["hatarib_tos"\] = "([^"]+)";',
|
||||
"hatarib tos.img fallback",
|
||||
method[0],
|
||||
tos_img = src.find(
|
||||
rf'string (\w+) = Path\.Combine\((\w+), "([^"]+)"\);', "hatarib tos.img path",
|
||||
method[0], method[1],
|
||||
)
|
||||
own = src.find(
|
||||
rf'string (\w+) = Path\.Combine\({tos_img.group(2)}, "([^"]+)"\);', "hatarib folder",
|
||||
tos_img.end(), method[1],
|
||||
)
|
||||
option = src.find(
|
||||
r'string (\w+) = SystemConfig\["(hatarib_tos)"\];', "hatarib option", own.end(), method[1]
|
||||
)
|
||||
tos_var, key = option.group(1), option.group(2)
|
||||
named = src.find(
|
||||
rf'if \({tos_var} == "(\w+)"\)\s*\{{\s*if \(File\.Exists\({tos_img.group(1)}\)\)\s*'
|
||||
r'(\w+) = "([^"]+)";',
|
||||
"tos.img choice", option.end(), method[1],
|
||||
)
|
||||
builtin = src.find(
|
||||
rf'else if \({tos_var}\.StartsWith\("(\w+)"\)\)', "EmuTOS choices", named.end(), method[1]
|
||||
)
|
||||
shared = src.find(
|
||||
rf'string (\w+) = Path\.Combine\({own.group(1)}, {tos_var}\);\s*'
|
||||
rf'string (\w+) = Path\.Combine\({tos_img.group(2)}, ((?:"[^"]+", )+){tos_var}\);',
|
||||
"shared TOS folder", builtin.end(), method[1],
|
||||
)
|
||||
copy = src.find(
|
||||
rf"if \(!File\.Exists\({shared.group(1)}\) && File\.Exists\({shared.group(2)}\)\)",
|
||||
"copy from the shared folder", shared.end(), method[1],
|
||||
)
|
||||
chosen = src.find(
|
||||
rf'if \(File\.Exists\({shared.group(1)}\)\)\s*{named.group(2)} = "([^"/]+)/" \+ {tos_var};',
|
||||
"chosen TOS write", copy.end(), method[1],
|
||||
)
|
||||
fallback = src.find(
|
||||
rf'if \({named.group(2)} == null\)\s*\{{\s*{named.group(2)} = "([^"]+)";\s*'
|
||||
rf'if \(File\.Exists\({tos_img.group(1)}\)\)\s*\{{\s*{named.group(2)} = "([^"]+)";',
|
||||
"default TOS", chosen.end(), method[1],
|
||||
)
|
||||
emutos = src.find(
|
||||
rf'{named.group(2)} = "{re.escape(fallback.group(1))}";', "EmuTOS for a disk", fallback.end(),
|
||||
method[1],
|
||||
)
|
||||
folders = _strings(shared.group(3).rstrip(", "))
|
||||
choices, choice_lines = feature_choices(features, "libretro", key, core="hatarib")
|
||||
files = [c for c in choices if c != named.group(1) and not c.startswith(builtin.group(1))]
|
||||
head = src.lines(tos_img.start(), own.end())
|
||||
records.append(
|
||||
_record(
|
||||
"hatarib",
|
||||
"libretro",
|
||||
"fixed_name",
|
||||
[found.group(1)],
|
||||
source_ref((src.path, [src.lines(found.start(), found.end())])),
|
||||
[tos_img.group(3)],
|
||||
source_ref((src.path, [head, src.lines(named.start(), named.end()),
|
||||
src.lines(fallback.start(), emutos.end())])),
|
||||
case_insensitive=True,
|
||||
search_dir="bios",
|
||||
passes_to=f"{found.group(2)} = {found.group(3)}",
|
||||
fails_when_missing=f"falls back to {found.group(2)} = {found.group(4)}",
|
||||
depends_on_option=f"{found.group(2)} unset",
|
||||
passes_to=f"{key} = {fallback.group(2)}",
|
||||
fails_when_missing=f"falls back to {key} = {fallback.group(1)}",
|
||||
depends_on_option=(
|
||||
f"{key} unset or {named.group(1)}; {fallback.group(1)} instead for a hard disk image "
|
||||
"under a TOS other than EmuTOS, or for autostart or GEMDOS under TOS older than 1.04"
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
picked = src.find(
|
||||
rf'string (\w+) = Path\.Combine\({BIOS}, "([^"]+)", SystemConfig\["(hatarib_tos)"\]\);',
|
||||
"hatarib option path",
|
||||
method[0],
|
||||
method[1],
|
||||
)
|
||||
write = src.find(
|
||||
r'coreSettings\["hatarib_tos"\] = (\w+);', "hatarib option write", picked.end()
|
||||
)
|
||||
skipped = re.findall(
|
||||
r'SystemConfig\["hatarib_tos"\] == "(\w+)"', src.text[method[0] : picked.start()]
|
||||
)
|
||||
prefixes = re.findall(
|
||||
r'SystemConfig\["hatarib_tos"\]\.StartsWith\("(\w+)"\)',
|
||||
src.text[method[0] : picked.start()],
|
||||
)
|
||||
choices, choice_lines = feature_choices(features, "libretro", picked.group(3), core="hatarib")
|
||||
files = [c for c in choices if c not in skipped and not c.startswith(tuple(prefixes))]
|
||||
records.append(
|
||||
_record(
|
||||
"hatarib",
|
||||
@@ -505,14 +592,28 @@ def hatari_libretro(sources: dict[str, Source]) -> list[Record]:
|
||||
"core_option",
|
||||
files,
|
||||
source_ref(
|
||||
(src.path, [src.lines(picked.start(), write.end())]),
|
||||
(src.path, [head, src.lines(shared.start(), chosen.end())]),
|
||||
(features.path, [choice_lines]),
|
||||
),
|
||||
case_insensitive=True,
|
||||
search_dir=f"bios/{picked.group(2)}",
|
||||
passes_to=f"hatarib_tos = {picked.group(2)}/<value>",
|
||||
fails_when_missing="option not written when the file is absent",
|
||||
depends_on_option=picked.group(3),
|
||||
search_dir=f"bios/{own.group(2)}",
|
||||
passes_to=f"{key} = {chosen.group(1)}/<value>",
|
||||
fails_when_missing=f"{key} = {fallback.group(1)}, or {fallback.group(2)} when bios holds it",
|
||||
depends_on_option=key,
|
||||
)
|
||||
)
|
||||
records.append(
|
||||
_record(
|
||||
"hatarib",
|
||||
"libretro",
|
||||
"copies",
|
||||
files,
|
||||
source_ref((src.path, [head, src.lines(shared.start(), copy.end())])),
|
||||
case_insensitive=True,
|
||||
search_dir="/".join(["bios", *folders]),
|
||||
passes_to=f"copied to bios/{own.group(2)}/<value>, only when the target does not exist",
|
||||
fails_when_missing=False,
|
||||
depends_on_option=key,
|
||||
)
|
||||
)
|
||||
return records
|
||||
@@ -2397,11 +2498,46 @@ def raine(sources: dict[str, Source]) -> list[Record]:
|
||||
|
||||
|
||||
def gsplus(sources: dict[str, Source]) -> list[Record]:
|
||||
"""The first of the names GSplus accepts that the bios folder holds, written
|
||||
as its ROM path. Without one the key is left alone and GSplus searches
|
||||
beside its executable."""
|
||||
src = sources[f"{GENERATORS}/GsPlus.Generator.cs"]
|
||||
records = _value_writes(src, "gsplus", "standalone")
|
||||
if not records:
|
||||
raise LauncherPatternMissing(src.path, "ROM path write")
|
||||
return _covered(src, records)
|
||||
listed = src.find(
|
||||
r"static readonly string\[\] (\w+) = new string\[\] \{ ((?:\"[^\"]+\"(?:, )?)+) \};",
|
||||
"ROM names",
|
||||
)
|
||||
root = src.find(r"string (\w+) = AppConfig\.GetFullPath\(\"bios\"\);", "bios folder")
|
||||
first = src.find(
|
||||
rf"string (\w+) = {listed.group(1)}\s*\.Select\(n => Path\.Combine\({root.group(1)}, n\)\)"
|
||||
r"\s*\.FirstOrDefault\(File\.Exists\);",
|
||||
"first name present",
|
||||
)
|
||||
write = src.find(
|
||||
rf'(\w+)\.WriteValue\(null, "(\w+)", {first.group(1)}\);', "ROM path write"
|
||||
)
|
||||
conditions, returns = _when(src, write.start())
|
||||
# The test on the name found is the selection itself, not a condition.
|
||||
conditions = [c for c in conditions if first.group(1) not in c]
|
||||
target = f"{_config_label(src, write.start(), write.group(1))} {write.group(2)}"
|
||||
record = _record(
|
||||
"gsplus",
|
||||
"standalone",
|
||||
"names_searched",
|
||||
_strings(listed.group(2)),
|
||||
_path_parts(
|
||||
src,
|
||||
*returns,
|
||||
src.lines(listed.start(), listed.end()),
|
||||
src.lines(root.start(), root.end()),
|
||||
src.lines(first.start(), write.end()),
|
||||
),
|
||||
case_insensitive=True,
|
||||
search_dir="bios",
|
||||
passes_to=f"{target} = <first found>",
|
||||
fails_when_missing=False,
|
||||
depends_on_option=", ".join(conditions) or None,
|
||||
)
|
||||
return _covered(src, [record])
|
||||
|
||||
|
||||
def _copies_if_absent(
|
||||
@@ -2994,15 +3130,25 @@ def arcadeduck(sources: dict[str, Source]) -> list[Record]:
|
||||
lookup_body[0],
|
||||
lookup_body[1],
|
||||
)
|
||||
method = src.find(r"private string GetBiosPath\(string rom, string biosRoot\)", "GetBiosPath")
|
||||
method = src.find(
|
||||
r"private string GetBiosPath\(string rom, string biosRoot, bool isChd\)", "GetBiosPath"
|
||||
)
|
||||
body = src.block_at(method.end())
|
||||
src.find(
|
||||
r"var candidates = new List<string> \{ Path\.GetDirectoryName\(Path\.GetFullPath\(rom\)\) \};",
|
||||
r"string romDir = Path\.GetDirectoryName\(Path\.GetFullPath\(rom\)\);\s*"
|
||||
r"var candidates = new List<string> \{ romDir \};",
|
||||
"game folder first",
|
||||
body[0],
|
||||
body[1],
|
||||
)
|
||||
src.find(r"candidates\.Add\(biosRoot\);", "bios folder second", body[0], body[1])
|
||||
src.find(
|
||||
r"if \(isChd && Directory\.GetParent\(romDir\) != null\)\s*"
|
||||
r"candidates\.Add\(Directory\.GetParent\(romDir\)\.FullName\);",
|
||||
"folder above a CHD-only set second",
|
||||
body[0],
|
||||
body[1],
|
||||
)
|
||||
src.find(r"candidates\.Add\(biosRoot\);", "bios folder last", body[0], body[1])
|
||||
message, _ = _throw_message(src, body[0], body[1])
|
||||
root = src.find(rf"string biosPath = {_BIOS_ROOT};", "bios root")
|
||||
write = src.find(r'ini\.WriteValue\("(\w+)", "(\w+)", biosPath\);', "SearchDirectory write")
|
||||
@@ -3031,7 +3177,7 @@ def arcadeduck(sources: dict[str, Source]) -> list[Record]:
|
||||
[f"<bios archive of the game's system in {database_file}>"],
|
||||
ref,
|
||||
case_insensitive=False,
|
||||
search_dir="<rom directory>, then bios",
|
||||
search_dir="<rom directory>, then the folder above it for a CHD-only set, then bios",
|
||||
passes_to=f"{target} = <folder found>",
|
||||
fails_when_missing=message,
|
||||
),
|
||||
@@ -3043,7 +3189,7 @@ def arcadeduck(sources: dict[str, Source]) -> list[Record]:
|
||||
ref,
|
||||
slot=fixed.group(1),
|
||||
case_insensitive=False,
|
||||
search_dir="<rom directory>, then bios",
|
||||
search_dir="<rom directory>, then the folder above it for a CHD-only set, then bios",
|
||||
passes_to=f"{target} = <folder found>",
|
||||
fails_when_missing=message,
|
||||
depends_on_option=f"{database_file} names no archive for {fixed.group(1)}",
|
||||
|
||||
@@ -217,6 +217,9 @@ class Scraper(BaseScraper):
|
||||
sys_name = sys_data.get("name", "") if isinstance(sys_data, dict) else ""
|
||||
if sys_name:
|
||||
native["native_name"] = sys_name
|
||||
# One held file of a group is enough (Program.cs): verify reads it.
|
||||
if bios.get("group"):
|
||||
native["group"] = str(bios["group"])
|
||||
|
||||
requirements.append(
|
||||
BiosRequirement(
|
||||
@@ -224,7 +227,7 @@ class Scraper(BaseScraper):
|
||||
system=SYSTEM_SLUG_MAP.get(sys_key, sys_key),
|
||||
md5=md5 or None,
|
||||
destination=file_path,
|
||||
required=True,
|
||||
required=not bios.get("optional", False),
|
||||
native_id=sys_key,
|
||||
native_path=declared_path,
|
||||
native=native,
|
||||
|
||||
@@ -327,9 +327,15 @@ def link_record(emulator: str, script: Script, link: Link, **fields: object) ->
|
||||
|
||||
def hatari(tree: RepoTree) -> list[Launcher]:
|
||||
package = f"{STANDALONE}/hatarisa"
|
||||
script = Script(
|
||||
f"{package}/scripts/start_hatari.sh", tree.read(f"{package}/scripts/start_hatari.sh")
|
||||
# The script is named after the package's binary: start_hatari.sh became
|
||||
# start_hatarisa.sh (2e7041d273), so it is found, not spelled.
|
||||
starts = sorted(
|
||||
name for name in tree.listdir(f"{package}/scripts")
|
||||
if name.startswith("start_") and name.endswith(".sh")
|
||||
)
|
||||
if len(starts) != 1:
|
||||
raise LauncherPatternMissing(f"{package}/scripts", "one start script")
|
||||
script = Script(f"{package}/scripts/{starts[0]}", tree.read(f"{package}/scripts/{starts[0]}"))
|
||||
copy_line, copy = script.find(r"cp \S+/([\w-]+\.cfg) ", "default config copy")
|
||||
run_line, _ = script.find(r"--configfile", "--configfile", copy_line)
|
||||
path = f"{package}/config/conf/{copy.group(1)}"
|
||||
@@ -557,17 +563,6 @@ def duckstation(tree: RepoTree) -> list[Launcher]:
|
||||
)
|
||||
|
||||
|
||||
def aethersx2(tree: RepoTree) -> list[Launcher]:
|
||||
return directory_records(
|
||||
tree,
|
||||
"aethersx2",
|
||||
f"{STANDALONE}/aethersx2-sa",
|
||||
"aethersx2/inis/PCSX2.ini",
|
||||
("Folders", "Bios"),
|
||||
(("Filenames", "BIOS"),),
|
||||
)
|
||||
|
||||
|
||||
def armsx2(tree: RepoTree) -> list[Launcher]:
|
||||
return directory_records(
|
||||
tree,
|
||||
@@ -683,7 +678,6 @@ EXTRACTORS: tuple[Callable[[RepoTree], list[Launcher]], ...] = (
|
||||
mednafen,
|
||||
yabasanshiro,
|
||||
duckstation,
|
||||
aethersx2,
|
||||
armsx2,
|
||||
patched_directories,
|
||||
links,
|
||||
|
||||
@@ -1021,6 +1021,7 @@ SYSTEM_NAMES: dict[str, str] = {
|
||||
"m68k": "Motorola 68000",
|
||||
"magnetic-scrolls": "Magnetic Scrolls",
|
||||
"marty": "Fujitsu FM Towns Marty",
|
||||
"mattel-hyperscan": "Mattel HyperScan",
|
||||
"mega-cd-32x": "Sega Mega-CD 32X",
|
||||
"mega-duck": "Welback Mega Duck",
|
||||
"mega-ld": "Sega Mega LD",
|
||||
|
||||
@@ -1429,6 +1429,25 @@ def verify_platform(
|
||||
):
|
||||
file_severity[dest] = sev
|
||||
|
||||
# RetroBat's group: one file of it held is enough, and the others are
|
||||
# reported OPTIONAL (batocera-systems/Program.cs). None held, each stays
|
||||
# required.
|
||||
members: dict[tuple[str, str], list[str]] = {}
|
||||
for sys_id, system in config.get("systems", {}).items():
|
||||
for file_entry in system.get("files", []):
|
||||
if file_entry.get("group"):
|
||||
dest = _dest_key(file_entry, sys_id)
|
||||
if dest in file_status:
|
||||
members.setdefault((sys_id, file_entry["group"]), []).append(dest)
|
||||
for dests in members.values():
|
||||
if any(file_status[d] == Status.OK for d in dests):
|
||||
for dest in dests:
|
||||
if file_status[dest] == Status.MISSING:
|
||||
file_required[dest] = False
|
||||
file_severity[dest] = compute_severity(Status.MISSING, False, mode)
|
||||
for result in results_at.get(dest, []):
|
||||
result["required"] = False
|
||||
|
||||
shipped, occupied = _builder_placement(
|
||||
packed_order, bool(config.get("case_insensitive_fs", False))
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user